diff --git a/.circleci/config.yml b/.circleci/config.yml index 3049a872a..461a0dfa6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -63,7 +63,7 @@ jobs: command: npm run test:basic - run: name: Test - Mustache Spans - command: npm run test:mustache-span + command: npm run test:mustache-syntax - run: name: Test - Routes command: npm run test:route diff --git a/.eslintrc.js b/.eslintrc.js index bc8b5c8cd..dd4bcd0d3 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -11,7 +11,7 @@ module.exports = { browser : true, node : true }, - plugins : ['react'], + plugins : ['react', 'jest'], rules : { /** Errors **/ 'camelcase' : ['error', { properties: 'never' }], @@ -24,6 +24,7 @@ module.exports = { 'react/jsx-no-bind' : ['error', { allowArrowFunctions: true }], 'react/jsx-uses-react' : 'error', 'react/prefer-es6-class' : ['error', 'never'], + 'jest/valid-expect' : ['error', { maxArgs: 3 }], /** Warnings **/ 'max-lines' : ['warn', { diff --git a/Dockerfile b/Dockerfile index 33adea2b8..67b42b9dc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16.11-alpine +FROM node:16.13-alpine RUN apk --no-cache add git ENV NODE_ENV=docker @@ -10,11 +10,11 @@ WORKDIR /usr/src/app # This improves caching so we don't have to download the dependencies every time the code changes COPY package.json ./ # --ignore-scripts tells yarn not to run postbuild. We run it explicitly later -RUN yarn install --ignore-scripts +RUN npm install --ignore-scripts # Bundle app source and build application COPY . . -RUN yarn build +RUN npm run build EXPOSE 8000 -CMD [ "yarn", "start" ] +CMD [ "npm", "start" ] diff --git a/changelog.md b/changelog.md index 60719b916..c40aa625b 100644 --- a/changelog.md +++ b/changelog.md @@ -80,19 +80,69 @@ pre { ## changelog For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery). -### XXXXday DD/MM/2023 - v3.8.0 +### Wednesday 12/04/2023 - v3.8.0 {{taskList + +##### calculuschild + +* [x] Rename `{{coverPage}}` to `{{frontCover}}`. Those using this {{beta BETA}} feature will need to update that text to make the cover page appear again. + +* [x] Several background fixes to test scripts + +##### Jeddai + +* [X] Add content negotiation to exclude image requests from our API calls + +Fixes issue [#2595](https://github.com/naturalcrit/homebrewery/issues/2595) + ##### G-Ambatte * [x] Update server build scripts to fix Admin page Fixes issues [#2657](https://github.com/naturalcrit/homebrewery/issues/2657) -* [x] Fix internal links inside `
` blocks not automatically receiving the `target=_self` attribute +* [x] Fix internal links inside `
` blocks not receiving the `target=_self` attribute Fixes issues [#2680](https://github.com/naturalcrit/homebrewery/issues/2680) + +* [x] See brew details on `/share` pages by clicking the brew title (author, last update, tags, etc.) + +Fixes issues [#1679](https://github.com/naturalcrit/homebrewery/issues/1679) + +* [x] Add local Windows install script via Chocolatey + +##### 5e-Clerc + +* [x] New {{openSans **TABLES → {{fas,fa-language}} RUNE TABLE**}} snippets for V3. Adds an alphabetic script translation table. + +* [x] New {{openSans **IMAGES → {{fac,mask-center}} WATERCOLOR CENTER** }} snippets for V3, which adds a stylish watercolor texture to the center of your images! + +* [x] New {{openSans **PHB → {{fac,book-inside-cover}} INSIDE COVER PAGE** }} snippet for V3! (Thanks to /u/Kaiburr_Kath-Hound on Reddit for providing some of these resources!) + +* [x] Add some missing characters {{font-family:scalySansRemake Ñ ñ ç Ç Ý ý # ^ ¿ ' " ¡ ·}} to the "scalySansRemake" font in V3. + +Fixes issues [#2280](https://github.com/naturalcrit/homebrewery/issues/2280) + +##### Gazook89 + +* [x] Add "Language" selector in {{fa,fa-info-circle}} **Properties** menu. Sets the HTML Lang attribute for your brew to better handle hyphenation or spellcheck. + +Fixes issues [#1343](https://github.com/naturalcrit/homebrewery/issues/1343) + +* [x] Fix a crash when multiple `{injection}` tags appear in sequence + +Fixes issues [#2712](https://github.com/naturalcrit/homebrewery/issues/2712) + +##### MichielDeMey + +* [x] Remove all-caps display on Account button since usernames are case-sensitive. + +Fixes issues [#2731](https://github.com/naturalcrit/homebrewery/issues/2731) + }} +\page + ### Monday 13/03/2023 - v3.7.2 {{taskList @@ -106,7 +156,7 @@ Fixes issues [#2680](https://github.com/naturalcrit/homebrewery/issues/2680) ##### Lucastucious (new contributor!) -* [x] Changed `filter: drop-shadow` to `box-shadow` on text boxes, making text selectable in PDFs again. +* [x] Changed `filter: drop-shadow` to `box-shadow` on text boxes, making PDF text selectable Fixes issues [#1569](https://github.com/naturalcrit/homebrewery/issues/1569) @@ -124,7 +174,6 @@ Fixes issues [#1569](https://github.com/naturalcrit/homebrewery/issues/1569) * [x] Fix PDF pixelation on CoverPage text outlines }} - ### Tuesday 28/02/2023 - v3.7.0 {{taskList @@ -154,7 +203,7 @@ Fixes issues [#2687](https://github.com/naturalcrit/homebrewery/issues/2687) {{taskList ##### G-Ambatte -* [x] Fix users not being removed from Authors list correctly +* [x] Fix users not being removed from Authors list Fixes issues [#2674](https://github.com/naturalcrit/homebrewery/issues/2674) }} @@ -184,6 +233,8 @@ Fixes issues [#2583](https://github.com/naturalcrit/homebrewery/issues/2583) * [x] Fix cloned brews inheriting the parent view count }} +\page + ### Friday 23/12/2022 - v3.5.0 {{taskList @@ -197,8 +248,6 @@ Fixes issues [#2583](https://github.com/naturalcrit/homebrewery/issues/2583) Fixes issues [#1987](https://github.com/naturalcrit/homebrewery/issues/1987) }} -\page - ### Saturday 10/12/2022 - v3.4.2 {{taskList diff --git a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx index f0a0f5f1f..202f3bf83 100644 --- a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx +++ b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx @@ -4,7 +4,7 @@ const createClass = require('create-react-class'); const _ = require('lodash'); const cx = require('classnames'); //Unused variable -const DISMISS_KEY = 'dismiss_notification08-27-22'; +const DISMISS_KEY = 'dismiss_notification12-04-23'; const NotificationPopup = createClass({ displayName : 'NotificationPopup', @@ -25,21 +25,14 @@ const NotificationPopup = createClass({ return ( <>
  • - V3.2.0 Released!
    - We are happy to announce that after nearly a year of use by our many users, - we are making the V3 render mode the default setting for all new brews. - This mode has become quite popular, and has proven to be stable and powerful. - Of course, we will always keep the option to use the Legacy renderer for any - brew, which can still be accessed from the Properties menu. -
  • - -
  • - Change to Google Drive Storage!
    - We have made a change to the process of tranferring brews between Google - Drive and the Homebrewery storage. Starting now, any time a brew is - transferred, it will keep the same links instead of generating new ones! - We hope this change will help reduce issues where people "lost" their work - by trying to visit old links. + Broken CoverPage snippet
    + Those of you who have been trying out our Cover Page snippet may + notice that the cover page no longer displays correctly. Due to some + small tweaks of this BETA feature, the CSS class has been renamed + from "coverPage" to "frontCover". Simply change the text to "frontCover" + and it should again function as before. Remember that any snippet + marked "beta" may have a similar change in the future as we + encounter any bugs or reworks.
  • diff --git a/client/homebrew/navbar/error-navitem.jsx b/client/homebrew/navbar/error-navitem.jsx index efee04019..eb2872c22 100644 --- a/client/homebrew/navbar/error-navitem.jsx +++ b/client/homebrew/navbar/error-navitem.jsx @@ -82,4 +82,4 @@ const ErrorNavItem = createClass({ } }); -module.exports = ErrorNavItem; \ No newline at end of file +module.exports = ErrorNavItem; diff --git a/client/homebrew/navbar/error-navitem.less b/client/homebrew/navbar/error-navitem.less index 8a7cabb19..7e7dab772 100644 --- a/client/homebrew/navbar/error-navitem.less +++ b/client/homebrew/navbar/error-navitem.less @@ -1,77 +1,75 @@ -.navItem { - &.error { - position : relative; - background-color : @red; - } +.navItem.error { + position : relative; + background-color : @red; +} - .errorContainer{ - animation-name: glideDown; - animation-duration: 0.4s; - position : absolute; - top : 100%; - left : 50%; - z-index : 1000; - width : 140px; - padding : 3px; - color : white; +.errorContainer{ + animation-name: glideDown; + animation-duration: 0.4s; + position : absolute; + top : 100%; + left : 50%; + z-index : 1000; + width : 140px; + padding : 3px; + color : white; + background-color : #333; + border : 3px solid #444; + border-radius : 5px; + transform : translate(-50% + 3px, 10px); + text-align : center; + font-size : 10px; + font-weight : 800; + text-transform : uppercase; + a{ + color : @teal; + } + &:before { + content: ""; + width: 0px; + height: 0px; + position: absolute; + border-left: 10px solid transparent; + border-right: 10px solid transparent; + border-top: 10px solid transparent; + border-bottom: 10px solid #444; + left: 53px; + top: -23px; + } + &:after { + content: ""; + width: 0px; + height: 0px; + position: absolute; + border-left: 10px solid transparent; + border-right: 10px solid transparent; + border-top: 10px solid transparent; + border-bottom: 10px solid #333; + left: 53px; + top: -19px; + } + .deny { + width : 48%; + margin : 1px; + padding : 5px; background-color : #333; - border : 3px solid #444; - border-radius : 5px; - transform : translate(-50% + 3px, 10px); - text-align : center; - font-size : 10px; - font-weight : 800; - text-transform : uppercase; - a{ - color : @teal; - } - &:before { - content: ""; - width: 0px; - height: 0px; - position: absolute; - border-left: 10px solid transparent; - border-right: 10px solid transparent; - border-top: 10px solid transparent; - border-bottom: 10px solid #444; - left: 53px; - top: -23px; - } - &:after { - content: ""; - width: 0px; - height: 0px; - position: absolute; - border-left: 10px solid transparent; - border-right: 10px solid transparent; - border-top: 10px solid transparent; - border-bottom: 10px solid #333; - left: 53px; - top: -19px; - } - .deny { - width : 48%; - margin : 1px; - padding : 5px; - background-color : #333; - display : inline-block; - border-left : 1px solid #666; - .animate(background-color); - &:hover{ - background-color : red; - } - } - .confirm { - width : 48%; - margin : 1px; - padding : 5px; - background-color : #333; - display : inline-block; - color : white; - .animate(background-color); - &:hover{ - background-color : teal; - } + display : inline-block; + border-left : 1px solid #666; + .animate(background-color); + &:hover{ + background-color : red; } } -} \ No newline at end of file + .confirm { + width : 48%; + margin : 1px; + padding : 5px; + background-color : #333; + display : inline-block; + color : white; + .animate(background-color); + &:hover{ + background-color : teal; + } + } +} diff --git a/client/homebrew/navbar/metadata.navitem.jsx b/client/homebrew/navbar/metadata.navitem.jsx new file mode 100644 index 000000000..f4a09e143 --- /dev/null +++ b/client/homebrew/navbar/metadata.navitem.jsx @@ -0,0 +1,90 @@ +const React = require('react'); +const createClass = require('create-react-class'); +const _ = require('lodash'); +const Moment = require('moment'); + +const Nav = require('naturalcrit/nav/nav.jsx'); + + +const MetadataNav = createClass({ + displayName : 'MetadataNav', + getDefaultProps : function() { + return { + }; + }, + + getInitialState : function() { + return { + showMetaWindow : false + }; + }, + + componentDidMount : function() { + }, + + toggleMetaWindow : function(){ + this.setState((prevProps)=>({ + showMetaWindow : !prevProps.showMetaWindow + })); + }, + + getAuthors : function(){ + if(!this.props.brew.authors || this.props.brew.authors.length == 0) return 'No authors'; + return <> + {this.props.brew.authors.map((author, idx, arr)=>{ + const spacer = arr.length - 1 == idx ? <> : , ; + return {author}{spacer}; + })} + ; + }, + + getTags : function(){ + if(!this.props.brew.tags || this.props.brew.tags.length == 0) return 'No tags'; + return <> + {this.props.brew.tags.map((tag, idx)=>{ + return {tag}; + })} + ; + }, + + getSystems : function(){ + if(!this.props.brew.systems || this.props.brew.systems.length == 0) return 'No systems'; + return this.props.brew.systems.join(', '); + }, + + renderMetaWindow : function(){ + return
    +
    +

    Description

    +

    {this.props.brew.description || 'No description.'}

    +
    +
    +

    Authors

    +

    {this.getAuthors()}

    +
    +
    +

    Tags

    +

    {this.getTags()}

    +
    +
    +

    Systems

    +

    {this.getSystems()}

    +
    +
    +

    Updated

    +

    {Moment(this.props.brew.updatedAt).fromNow()}

    +
    +
    ; + }, + + render : function(){ + return this.toggleMetaWindow()}> + {this.props.children} + {this.renderMetaWindow()} + ; + } + +}); + +module.exports = MetadataNav; diff --git a/client/homebrew/navbar/navbar.less b/client/homebrew/navbar/navbar.less index b1db6ae30..f23034dd8 100644 --- a/client/homebrew/navbar/navbar.less +++ b/client/homebrew/navbar/navbar.less @@ -1,193 +1,278 @@ -@import 'naturalcrit/styles/colors.less'; -@navbarHeight : 28px; -@keyframes pinkColoring { - //from {color: white;} - //to {color: red;} - 0% {color: pink;} - 50% {color: pink;} - 75% {color: red;} - 100% {color: pink;} -} -.homebrew nav{ - .homebrewLogo{ - .animate(color); - font-family : CodeBold; - font-size : 12px; - color : white; - div{ - margin-top : 2px; - margin-bottom : -2px; - } - &:hover{ - color : @blue; - } - } - .editTitle.navItem{ - padding : 2px 12px; - input{ - width : 250px; - margin : 0; - padding : 2px; - background-color : #444; - font-family : 'Open Sans', sans-serif; - font-size : 12px; - font-weight : 800; - color : white; - text-align : center; - border : 1px solid @blue; - outline : none; - } - .charCount{ - display : inline-block; - vertical-align : bottom; - margin-left : 8px; - color : #666; - text-align : right; - &.max{ - color : @red; - } - } - } - .brewTitle.navItem{ - font-size : 12px; - font-weight : 800; - color : white; - text-align : center; - text-transform : initial; - } - .save-menu { - .dropdown { - z-index: 1000; - } - .navItem i.fa-power-off { - color : red; - &.active { - color : rgb(0, 182, 52); - filter : drop-shadow(0 0 2px rgba(0, 182, 52, 0.765)) - } - } - } - .patreon.navItem{ - border-left : 1px solid #666; - border-right : 1px solid #666; - &:hover i { - color: red; - } - i{ - .animate(color); - animation-name: pinkColoring; - animation-duration: 2s; - color: pink; - } - } - .recent.navItem { - position : relative; - .dropdown{ - position : absolute; - top : 28px; - left : 0px; - z-index : 10000; - width : 100%; - overflow : hidden auto; - max-height : ~"calc(100vh - 28px)"; - scrollbar-color : #666 #333; - scrollbar-width : thin; - h4{ - display : block; - box-sizing : border-box; - padding : 5px 0px; - background-color : #333; - font-size : 0.8em; - color : #bbb; - text-align : center; - border-top : 1px solid #888; - &:nth-of-type(1){ background-color: darken(@teal, 20%); } - &:nth-of-type(2){ background-color: darken(@purple, 30%); } - } - .item{ +@import "naturalcrit/styles/colors.less"; +@navbarHeight : 28px; +@keyframes pinkColoring { + 0% {color : pink;} + 50% {color : pink;} + 75% {color : red;} + 100% {color : pink;} +} +.homebrew nav { + .homebrewLogo { + .animate(color); + font-family : CodeBold; + font-size : 12px; + color : white; + div { + margin-top : 2px; + margin-bottom : -2px; + } + &:hover { + color : @blue; + } + } + .editTitle.navItem { + padding : 2px 12px; + input { + font-family : "Open Sans", sans-serif; + font-size : 12px; + font-weight : 800; + width : 250px; + margin : 0; + padding : 2px; + text-align : center; + color : white; + border : 1px solid @blue; + outline : none; + background-color : transparent; + } + .charCount { + display : inline-block; + margin-left : 8px; + text-align : right; + vertical-align : bottom; + color : #666; + &.max { + color : @red; + } + } + } + .brewTitle.navItem { + font-size : 12px; + font-weight : 800; + height : 100%; + text-align : center; + text-transform : initial; + color : white; + background-color : transparent; + flex-grow : 1; + } + .save-menu { + .dropdown { + z-index : 1000; + } + .navItem i.fa-power-off { + color : red; + &.active { + color : rgb(0, 182, 52); + filter : drop-shadow(0 0 2px rgba(0, 182, 52, 0.765)); + } + } + } + .patreon.navItem { + border-right : 1px solid #666; + border-left : 1px solid #666; + &:hover i { + color : red; + } + i { + .animate(color); + animation-name : pinkColoring; + animation-duration : 2s; + color : pink; + } + } + .recent.navItem { + position : relative; + .dropdown { + position : absolute; + z-index : 10000; + top : 28px; + left : 0; + overflow : hidden auto; + width : 100%; + max-height : ~"calc(100vh - 28px)"; + scrollbar-color : #666 #333; + scrollbar-width : thin; + h4 { + font-size : 0.8em; + display : block; + box-sizing : border-box; + padding : 5px 0; + text-align : center; + color : #BBB; + border-top : 1px solid #888; + background-color : #333; + &:nth-of-type(1) { + background-color : darken(@teal, 20%); + } + &:nth-of-type(2) { + background-color : darken(@purple, 30%); + } + } + .item { #backgroundColorsHover; - .animate(background-color); - position : relative; - display : block; - box-sizing : border-box; - padding : 8px 5px 13px; - background-color : #333; - color : white; - text-decoration : none; - border-top : 1px solid #888; - overflow : clip; - .clear{ - display : none; - position : absolute; - top : 50%; - transform : translateY(-50%); - right : 0px; - width : 20px; - height : 100%; - background-color : #333; - opacity : 70%; - border-radius : 3px; - &:hover { - opacity : 100%; - } - i { - text-align : center; - font-size : 10px; - margin : 0; - height :100%; - width :100%; - } - } - &:hover{ - background-color : @blue; - - .clear{ - display : grid; - place-content : center; - } - } - .title{ - display : inline-block; - overflow : hidden; - width : 100%; - text-overflow : ellipsis; - white-space : nowrap; - } - .time{ - position : absolute; - right : 2px; - bottom : 2px; - font-size : 0.7em; - color : #888; - } - } - } - } - .warning.navItem{ - position : relative; - background-color : @orange; - color : white; - &:hover>.dropdown{ - visibility : visible; - } - .dropdown{ - position : absolute; - display : block; - top : 28px; - left : 0px; - visibility : hidden; - z-index : 10000; - box-sizing : border-box; - width : 100%; - padding : 13px 5px; - background-color : #333; - text-align : center; - } - } - .account.navItem{ - min-width: 100px; - } - .account.username.navItem{ - text-transform: none; - } -} + .animate(background-color); + position : relative; + display : block; + overflow : clip; + box-sizing : border-box; + padding : 8px 5px 13px; + text-decoration : none; + color : white; + border-top : 1px solid #888; + background-color : #333; + .clear { + position : absolute; + top : 50%; + right : 0; + display : none; + width : 20px; + height : 100%; + transform : translateY(-50%); + opacity : 70%; + border-radius : 3px; + background-color : #333; + &:hover { + opacity : 100%; + } + i { + font-size : 10px; + width : 100%; + height : 100%; + margin : 0; + text-align : center; + } + } + &:hover { + background-color : @blue; + .clear { + display : grid; + place-content : center; + } + } + .title { + display : inline-block; + overflow : hidden; + width : 100%; + white-space : nowrap; + text-overflow : ellipsis; + } + .time { + font-size : 0.7em; + position : absolute; + right : 2px; + bottom : 2px; + color : #888; + } + } + } + } + .metadata.navItem { + position : relative; + display : flex; + align-items : center; + height : 100%; + padding : 0; + flex-grow : 1; + i { + margin-right : 10px; + } + .window { + position : absolute; + z-index : -1; + bottom : 0; + left : 50%; + display : flex; + justify-content : flex-start; + width : 440px; + max-height : ~"calc(100vh - 28px)"; + margin : 0 auto; + padding : 0 10px 5px; + transition : transform 0.4s, opacity 0.4s; + border : 3px solid #444; + border-top : unset; + border-radius : 0 0 5px 5px; + background-color : #333; + box-shadow : inset 0 7px 9px -7px #111; + flex-flow : row wrap; + align-content : baseline; + &.active { + transform : translateX(-50%) translateY(100%); + opacity : 1; + } + &.inactive { + transform : translateX(-50%) translateY(0%); + opacity : 0; + } + .row { + display : flex; + width : 100%; + flex-flow : row wrap; + h4 { + display : block; + box-sizing : border-box; + min-width : 76px; + padding : 5px 0; + text-align : center; + color : #BBB; + flex-basis : 20%; + flex-grow : 1; + } + p { + font-family : "Open Sans", sans-serif; + font-size : 10px; + font-weight : normal; + padding : 5px 0; + text-transform : initial; + flex-basis : 80%; + flex-grow : 1; + .tag { + display : inline-block; + margin : 2px 2px; + padding : 2px; + border : 2px solid grey; + border-radius : 5px; + background-color : #444; + } + a.userPageLink { + text-decoration : none; + color : white; + &:hover { + text-decoration : underline; + } + } + } + &:nth-of-type(even) { + background-color : #555; + } + } + } + } + .warning.navItem { + position : relative; + color : white; + background-color : @orange; + &:hover > .dropdown { + visibility : visible; + } + .dropdown { + position : absolute; + z-index : 10000; + top : 28px; + left : 0; + display : block; + visibility : hidden; + box-sizing : border-box; + width : 100%; + padding : 13px 5px; + text-align : center; + background-color : #333; + } + } + .account.navItem { + min-width : 100px; + } + .account.username.navItem { + text-transform : none; + } +} diff --git a/client/homebrew/pages/basePages/listPage/listPage.less b/client/homebrew/pages/basePages/listPage/listPage.less index 4e5557a3e..bcffbf3e7 100644 --- a/client/homebrew/pages/basePages/listPage/listPage.less +++ b/client/homebrew/pages/basePages/listPage/listPage.less @@ -16,6 +16,7 @@ } .listPage{ .content{ + z-index : 1; .page{ .noColumns() !important; //Needed to override PHB Theme since this is on a lower @layer &::after{ @@ -63,7 +64,7 @@ border-bottom : 1px solid #666; color : white; text-align : center; - z-index : 500; + z-index : 1; display : flex; justify-content : center; align-items : baseline; diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index 94d5aef3b..4f2e8f8a2 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -254,6 +254,15 @@ const EditPage = createClass({
  • } + + {this.state.alertTrashedGoogleBrew && +
    + This brew is currently in your Trash folder on Google Drive!
    If you want to keep it, make sure to move it before it is deleted permanently!
    +
    + OK +
    +
    + } ; }, @@ -335,16 +344,6 @@ const EditPage = createClass({ const shareLink = this.processShareId(); return - - {this.state.alertTrashedGoogleBrew && -
    - This brew is currently in your Trash folder on Google Drive!
    If you want to keep it, make sure to move it before it is deleted permanently!
    -
    - OK -
    -
    - } - {this.state.brew.title} diff --git a/client/homebrew/pages/sharePage/sharePage.jsx b/client/homebrew/pages/sharePage/sharePage.jsx index 232c2a1e3..981ad0126 100644 --- a/client/homebrew/pages/sharePage/sharePage.jsx +++ b/client/homebrew/pages/sharePage/sharePage.jsx @@ -5,6 +5,7 @@ const { Meta } = require('vitreum/headtags'); const Nav = require('naturalcrit/nav/nav.jsx'); const Navbar = require('../../navbar/navbar.jsx'); +const MetadataNav = require('../../navbar/metadata.navitem.jsx'); const PrintLink = require('../../navbar/print.navitem.jsx'); const RecentNavItem = require('../../navbar/recent.navitem.jsx').both; const Account = require('../../navbar/account.navitem.jsx'); @@ -50,8 +51,10 @@ const SharePage = createClass({ return
    - - {this.props.brew.title} + + + {this.props.brew.title} + diff --git a/client/homebrew/pages/sharePage/sharePage.less b/client/homebrew/pages/sharePage/sharePage.less index 40b90496a..83e784c49 100644 --- a/client/homebrew/pages/sharePage/sharePage.less +++ b/client/homebrew/pages/sharePage/sharePage.less @@ -1,4 +1,8 @@ .sharePage{ + .navContent .navSection.titleSection { + flex-grow: 1; + justify-content: center; + } .content{ overflow-y : hidden; } diff --git a/client/icons/book-inside-cover.svg b/client/icons/book-inside-cover.svg new file mode 100644 index 000000000..9005e3247 --- /dev/null +++ b/client/icons/book-inside-cover.svg @@ -0,0 +1,53 @@ + + + + + + + + + diff --git a/client/icons/customIcons.less b/client/icons/customIcons.less index 3e28089a5..d89afdab1 100644 --- a/client/icons/customIcons.less +++ b/client/icons/customIcons.less @@ -40,6 +40,9 @@ .book-front-cover { content: url('../icons/book-front-cover.svg'); } +.book-inside-cover { + content: url('../icons/book-inside-cover.svg'); +} .davek { content: url('../icons/Davek.svg'); } diff --git a/package-lock.json b/package-lock.json index f142969f6..80e8e4ebc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,18 @@ { "name": "homebrewery", - "version": "3.7.2", + "version": "3.8.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "homebrewery", - "version": "3.7.2", + "version": "3.8.0", "hasInstallScript": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.21.3", - "@babel/plugin-transform-runtime": "^7.21.0", - "@babel/preset-env": "^7.19.4", + "@babel/core": "^7.21.4", + "@babel/plugin-transform-runtime": "^7.21.4", + "@babel/preset-env": "^7.21.4", "@babel/preset-react": "^7.18.6", "@googleapis/drive": "^5.0.2", "body-parser": "^1.20.2", @@ -33,26 +33,28 @@ "marked-extended-tables": "^1.0.5", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.29.4", - "mongoose": "^7.0.3", + "mongoose": "^7.1.0", "nanoid": "3.3.4", "nconf": "^0.12.0", - "npm": "^9.6.2", + "npm": "^9.6.5", "react": "^17.0.2", "react-dom": "^17.0.2", - "react-frame-component": "5.2.6", - "react-router-dom": "6.9.0", + "react-frame-component": "^4.1.3", + "react-router-dom": "6.10.0", "sanitize-filename": "1.6.3", "superagent": "^6.1.0", "vitreum": "git+https://git@github.com/calculuschild/vitreum.git" }, "devDependencies": { - "eslint": "^8.36.0", + "eslint": "^8.39.0", + "eslint-plugin-jest": "^27.2.1", "eslint-plugin-react": "^7.32.2", "jest": "^29.5.0", + "jest-expect-message": "^1.1.3", "supertest": "^6.3.3" }, "engines": { - "node": "16.11.x" + "node": "16.13.x" } }, "node_modules/@ampproject/remapping": { @@ -68,9 +70,9 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", + "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", "dependencies": { "@babel/highlight": "^7.18.6" }, @@ -79,28 +81,28 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz", - "integrity": "sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz", + "integrity": "sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.3.tgz", - "integrity": "sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz", + "integrity": "sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.3", - "@babel/helper-compilation-targets": "^7.20.7", + "@babel/code-frame": "^7.21.4", + "@babel/generator": "^7.21.4", + "@babel/helper-compilation-targets": "^7.21.4", "@babel/helper-module-transforms": "^7.21.2", "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.3", + "@babel/parser": "^7.21.4", "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.3", - "@babel/types": "^7.21.3", + "@babel/traverse": "^7.21.4", + "@babel/types": "^7.21.4", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -116,11 +118,11 @@ } }, "node_modules/@babel/generator": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz", - "integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz", + "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==", "dependencies": { - "@babel/types": "^7.21.3", + "@babel/types": "^7.21.4", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -166,12 +168,12 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", - "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz", + "integrity": "sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==", "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-validator-option": "^7.18.6", + "@babel/compat-data": "^7.21.4", + "@babel/helper-validator-option": "^7.21.0", "browserslist": "^4.21.3", "lru-cache": "^5.1.1", "semver": "^6.3.0" @@ -289,11 +291,11 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", + "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.21.4" }, "engines": { "node": ">=6.9.0" @@ -467,9 +469,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz", - "integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", + "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -1408,11 +1410,11 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.21.0.tgz", - "integrity": "sha512-ReY6pxwSzEU0b3r2/T/VhqMKg/AkceBT19X0UptA3/tYi5Pe2eXgEUH+NNMC5nok6c6XQz5tyVTUpuezRfSMSg==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.21.4.tgz", + "integrity": "sha512-1J4dhrw1h1PqnNNpzwxQ2UBymJUF8KuPjAAnlLwZcGhHAIqUigFW7cdK6GHoB64ubY4qXQNYknoUeks4Wz7CUA==", "dependencies": { - "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-module-imports": "^7.21.4", "@babel/helper-plugin-utils": "^7.20.2", "babel-plugin-polyfill-corejs2": "^0.3.3", "babel-plugin-polyfill-corejs3": "^0.6.0", @@ -1527,30 +1529,30 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz", - "integrity": "sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.21.4.tgz", + "integrity": "sha512-2W57zHs2yDLm6GD5ZpvNn71lZ0B/iypSdIeq25OurDKji6AdzV07qp4s3n1/x5BqtiGaTrPN3nerlSCaC5qNTw==", "dependencies": { - "@babel/compat-data": "^7.20.1", - "@babel/helper-compilation-targets": "^7.20.0", + "@babel/compat-data": "^7.21.4", + "@babel/helper-compilation-targets": "^7.21.4", "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-validator-option": "^7.18.6", + "@babel/helper-validator-option": "^7.21.0", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-async-generator-functions": "^7.20.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.20.7", + "@babel/plugin-proposal-async-generator-functions": "^7.20.7", "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.21.0", "@babel/plugin-proposal-dynamic-import": "^7.18.6", "@babel/plugin-proposal-export-namespace-from": "^7.18.9", "@babel/plugin-proposal-json-strings": "^7.18.6", - "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-logical-assignment-operators": "^7.20.7", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", "@babel/plugin-proposal-numeric-separator": "^7.18.6", - "@babel/plugin-proposal-object-rest-spread": "^7.20.2", + "@babel/plugin-proposal-object-rest-spread": "^7.20.7", "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.21.0", "@babel/plugin-proposal-private-methods": "^7.18.6", - "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.21.0", "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", @@ -1567,40 +1569,40 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.18.6", - "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.20.7", + "@babel/plugin-transform-async-to-generator": "^7.20.7", "@babel/plugin-transform-block-scoped-functions": "^7.18.6", - "@babel/plugin-transform-block-scoping": "^7.20.2", - "@babel/plugin-transform-classes": "^7.20.2", - "@babel/plugin-transform-computed-properties": "^7.18.9", - "@babel/plugin-transform-destructuring": "^7.20.2", + "@babel/plugin-transform-block-scoping": "^7.21.0", + "@babel/plugin-transform-classes": "^7.21.0", + "@babel/plugin-transform-computed-properties": "^7.20.7", + "@babel/plugin-transform-destructuring": "^7.21.3", "@babel/plugin-transform-dotall-regex": "^7.18.6", "@babel/plugin-transform-duplicate-keys": "^7.18.9", "@babel/plugin-transform-exponentiation-operator": "^7.18.6", - "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-for-of": "^7.21.0", "@babel/plugin-transform-function-name": "^7.18.9", "@babel/plugin-transform-literals": "^7.18.9", "@babel/plugin-transform-member-expression-literals": "^7.18.6", - "@babel/plugin-transform-modules-amd": "^7.19.6", - "@babel/plugin-transform-modules-commonjs": "^7.19.6", - "@babel/plugin-transform-modules-systemjs": "^7.19.6", + "@babel/plugin-transform-modules-amd": "^7.20.11", + "@babel/plugin-transform-modules-commonjs": "^7.21.2", + "@babel/plugin-transform-modules-systemjs": "^7.20.11", "@babel/plugin-transform-modules-umd": "^7.18.6", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.20.5", "@babel/plugin-transform-new-target": "^7.18.6", "@babel/plugin-transform-object-super": "^7.18.6", - "@babel/plugin-transform-parameters": "^7.20.1", + "@babel/plugin-transform-parameters": "^7.21.3", "@babel/plugin-transform-property-literals": "^7.18.6", - "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.20.5", "@babel/plugin-transform-reserved-words": "^7.18.6", "@babel/plugin-transform-shorthand-properties": "^7.18.6", - "@babel/plugin-transform-spread": "^7.19.0", + "@babel/plugin-transform-spread": "^7.20.7", "@babel/plugin-transform-sticky-regex": "^7.18.6", "@babel/plugin-transform-template-literals": "^7.18.9", "@babel/plugin-transform-typeof-symbol": "^7.18.9", "@babel/plugin-transform-unicode-escapes": "^7.18.10", "@babel/plugin-transform-unicode-regex": "^7.18.6", "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.20.2", + "@babel/types": "^7.21.4", "babel-plugin-polyfill-corejs2": "^0.3.3", "babel-plugin-polyfill-corejs3": "^0.6.0", "babel-plugin-polyfill-regenerator": "^0.4.1", @@ -1678,18 +1680,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz", - "integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz", + "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==", "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.3", + "@babel/code-frame": "^7.21.4", + "@babel/generator": "^7.21.4", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.21.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.3", - "@babel/types": "^7.21.3", + "@babel/parser": "^7.21.4", + "@babel/types": "^7.21.4", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1698,9 +1700,9 @@ } }, "node_modules/@babel/types": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz", - "integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz", + "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==", "dependencies": { "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", @@ -1741,14 +1743,14 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.1.tgz", - "integrity": "sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", + "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.0", + "espree": "^9.5.1", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -1791,9 +1793,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.36.0.tgz", - "integrity": "sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", + "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2663,9 +2665,9 @@ } }, "node_modules/@remix-run/router": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.4.0.tgz", - "integrity": "sha512-BJ9SxXux8zAg991UmT8slpwpsd31K1dHHbD3Ba4VzD+liLQ4WAMSxQp2d2ZPRPfN0jN2NPRowcSSoM7lCaF08Q==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.5.0.tgz", + "integrity": "sha512-bkUDCp8o1MvFO+qxkODcbhSqRa6P2GXgrGZVpt0dCXNW2HCSCqYI0ZoAqEOSAjRWmmlKcYgFvN4B4S+zo/f8kg==", "engines": { "node": ">=14" } @@ -2768,6 +2770,12 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, "node_modules/@types/node": { "version": "18.15.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.5.tgz", @@ -2779,6 +2787,12 @@ "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", "dev": true }, + "node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, "node_modules/@types/stack-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", @@ -2814,6 +2828,194 @@ "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", "dev": true }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.58.0.tgz", + "integrity": "sha512-b+w8ypN5CFvrXWQb9Ow9T4/6LC2MikNf1viLkYTiTbkQl46CnR69w7lajz1icW0TBsYmlpg+mRzFJ4LEJ8X9NA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.58.0", + "@typescript-eslint/visitor-keys": "5.58.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.58.0.tgz", + "integrity": "sha512-JYV4eITHPzVQMnHZcYJXl2ZloC7thuUHrcUmxtzvItyKPvQ50kb9QXBkgNAt90OYMqwaodQh2kHutWZl1fc+1g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.58.0.tgz", + "integrity": "sha512-cRACvGTodA+UxnYM2uwA2KCwRL7VAzo45syNysqlMyNyjw0Z35Icc9ihPJZjIYuA5bXJYiJ2YGUB59BqlOZT1Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.58.0", + "@typescript-eslint/visitor-keys": "5.58.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz", + "integrity": "sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.58.0.tgz", + "integrity": "sha512-gAmLOTFXMXOC+zP1fsqm3VceKSBQJNzV385Ok3+yzlavNHZoedajjS4UyS21gabJYcobuigQPs/z71A9MdJFqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.58.0", + "@typescript-eslint/types": "5.58.0", + "@typescript-eslint/typescript-estree": "5.58.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz", + "integrity": "sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.58.0.tgz", + "integrity": "sha512-/fBraTlPj0jwdyTwLyrRTxv/3lnU2H96pNTVM6z3esTWLtA5MZ9ghSMJ7Rb+TtUAdtEw9EyJzJ0EydIMKxQ9gA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.58.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -3020,6 +3222,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", @@ -3820,9 +4031,9 @@ } }, "node_modules/bson": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-5.1.0.tgz", - "integrity": "sha512-FEecNHkhYRBe7X9KDkdG12xNuz5VHGeH6mCE0B5sBmYtiR/Ux/9vUH/v4NUoBCDr6NuEhvahjoLiiRogptVW0A==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-5.2.0.tgz", + "integrity": "sha512-HevkSpDbpUfsrHWmWiAsNavANKYIErV2ePXllp1bwq5CDreAaFVj6RVlZpJnxK4WWDCJ/5jMUpaY6G526q3Hjg==", "engines": { "node": ">=14.20.1" } @@ -4603,6 +4814,18 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -4852,15 +5075,15 @@ } }, "node_modules/eslint": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz", - "integrity": "sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz", + "integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.1", - "@eslint/js": "8.36.0", + "@eslint/eslintrc": "^2.0.2", + "@eslint/js": "8.39.0", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -4870,9 +5093,9 @@ "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.5.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.0", + "espree": "^9.5.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -4908,6 +5131,30 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-plugin-jest": { + "version": "27.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.2.1.tgz", + "integrity": "sha512-l067Uxx7ZT8cO9NJuf+eJHvt6bqJyz2Z29wykyEdz/OtmcELQl2MQGQLX8J94O1cSJWAwUSEvCjwjA7KEK3Hmg==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "^5.10.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^5.0.0", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + } + } + }, "node_modules/eslint-plugin-react": { "version": "7.32.2", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", @@ -4967,9 +5214,9 @@ } }, "node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", @@ -4977,15 +5224,21 @@ }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/ansi-styles": { @@ -5098,14 +5351,14 @@ } }, "node_modules/espree": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.0.tgz", - "integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==", + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", + "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", "dev": true, "dependencies": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -5477,6 +5730,34 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -5899,6 +6180,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/google-auth-library": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.7.0.tgz", @@ -7486,6 +7787,12 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-expect-message": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/jest-expect-message/-/jest-expect-message-1.1.3.tgz", + "integrity": "sha512-bTK77T4P+zto+XepAX3low8XVQxDgaEqh3jSTQOG8qvPpD69LsIdyJTa+RmnJh3HNSzJng62/44RPPc7OIlFxg==", + "dev": true + }, "node_modules/jest-get-type": { "version": "29.4.3", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", @@ -8968,6 +9275,15 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -9175,11 +9491,11 @@ } }, "node_modules/mongodb": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.1.0.tgz", - "integrity": "sha512-qgKb7y+EI90y4weY3z5+lIgm8wmexbonz0GalHkSElQXVKtRuwqXuhXKccyvIjXCJVy9qPV82zsinY0W1FBnJw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.3.0.tgz", + "integrity": "sha512-Wy/sbahguL8c3TXQWXmuBabiLD+iVmz+tOgQf+FwkCjhUIorqbAxRbbz00g4ZoN4sXIPwpAlTANMaGRjGGTikQ==", "dependencies": { - "bson": "^5.0.1", + "bson": "^5.2.0", "mongodb-connection-string-url": "^2.6.0", "socks": "^2.7.1" }, @@ -9191,7 +9507,7 @@ }, "peerDependencies": { "@aws-sdk/credential-providers": "^3.201.0", - "mongodb-client-encryption": "^2.3.0", + "mongodb-client-encryption": ">=2.3.0 <3", "snappy": "^7.2.2" }, "peerDependenciesMeta": { @@ -9216,13 +9532,13 @@ } }, "node_modules/mongoose": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.0.3.tgz", - "integrity": "sha512-3n8vc1/mssuxKa6vfghSocp3MeiCFYzhX36Ok+PsDNNYzHC9tw3rNkAMLemIwZ2jgXqkZ7CfKOxkzjp/d/SWfg==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.1.0.tgz", + "integrity": "sha512-shoo9z/7o96Ojx69wpJn65+EC+Mt3q1SWTducW+F2Y4ieCXo0lZwpCZedgC841MIvJ7V8o6gmzoN1NfcnOTOuw==", "dependencies": { - "bson": "^5.0.1", + "bson": "^5.2.0", "kareem": "2.5.1", - "mongodb": "5.1.0", + "mongodb": "5.3.0", "mpath": "0.9.0", "mquery": "5.0.0", "ms": "2.1.3", @@ -9573,9 +9889,9 @@ } }, "node_modules/npm": { - "version": "9.6.2", - "resolved": "https://registry.npmjs.org/npm/-/npm-9.6.2.tgz", - "integrity": "sha512-TnXoXhlFkH/9wI4+aXSq0aPLwKG7Ge17t1ME4/rQt+0DZWQCRk9PwhBuX/shqdUiHeKicSLSkzWx+QZgTRE+/A==", + "version": "9.6.5", + "resolved": "https://registry.npmjs.org/npm/-/npm-9.6.5.tgz", + "integrity": "sha512-0SYs9lz1ND7V3+Lz6EbsnUdZ4OxjQOHbaIKdWd8OgsbZ2hCC2ZeiXMEaBEPEVBaILW+huFA0pJ1YME+52iZI5g==", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -9646,14 +9962,14 @@ ], "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^6.2.5", - "@npmcli/config": "^6.1.4", - "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/arborist": "^6.2.8", + "@npmcli/config": "^6.1.6", + "@npmcli/map-workspaces": "^3.0.3", "@npmcli/package-json": "^3.0.0", "@npmcli/run-script": "^6.0.0", "abbrev": "^2.0.0", "archy": "~1.0.0", - "cacache": "^17.0.4", + "cacache": "^17.0.5", "chalk": "^4.1.2", "ci-info": "^3.8.0", "cli-columns": "^4.0.0", @@ -9661,49 +9977,49 @@ "columnify": "^1.6.0", "fastest-levenshtein": "^1.0.16", "fs-minipass": "^3.0.1", - "glob": "^8.1.0", - "graceful-fs": "^4.2.10", + "glob": "^9.3.2", + "graceful-fs": "^4.2.11", "hosted-git-info": "^6.1.1", - "ini": "^3.0.1", + "ini": "^4.1.0", "init-package-json": "^5.0.0", "is-cidr": "^4.0.2", "json-parse-even-better-errors": "^3.0.0", "libnpmaccess": "^7.0.2", - "libnpmdiff": "^5.0.13", - "libnpmexec": "^5.0.13", - "libnpmfund": "^4.0.13", + "libnpmdiff": "^5.0.16", + "libnpmexec": "^5.0.16", + "libnpmfund": "^4.0.16", "libnpmhook": "^9.0.3", "libnpmorg": "^5.0.3", - "libnpmpack": "^5.0.13", - "libnpmpublish": "^7.1.2", + "libnpmpack": "^5.0.16", + "libnpmpublish": "^7.1.3", "libnpmsearch": "^6.0.2", "libnpmteam": "^5.0.3", "libnpmversion": "^4.0.2", - "make-fetch-happen": "^11.0.3", - "minimatch": "^6.2.0", - "minipass": "^4.2.4", + "make-fetch-happen": "^11.1.0", + "minimatch": "^7.4.6", + "minipass": "^4.2.8", "minipass-pipeline": "^1.2.4", "ms": "^2.1.2", "node-gyp": "^9.3.1", - "nopt": "^7.0.0", + "nopt": "^7.1.0", "npm-audit-report": "^4.0.0", - "npm-install-checks": "^6.0.0", + "npm-install-checks": "^6.1.1", "npm-package-arg": "^10.1.0", "npm-pick-manifest": "^8.0.1", "npm-profile": "^7.0.1", - "npm-registry-fetch": "^14.0.3", + "npm-registry-fetch": "^14.0.4", "npm-user-validate": "^2.0.0", "npmlog": "^7.0.1", "p-map": "^4.0.0", "pacote": "^15.1.1", - "parse-conflict-json": "^3.0.0", + "parse-conflict-json": "^3.0.1", "proc-log": "^3.0.0", "qrcode-terminal": "^0.12.0", - "read": "^2.0.0", - "read-package-json": "^6.0.0", + "read": "^2.1.0", + "read-package-json": "^6.0.1", "read-package-json-fast": "^3.0.2", - "semver": "^7.3.8", - "ssri": "^10.0.1", + "semver": "^7.5.0", + "ssri": "^10.0.3", "tar": "^6.1.13", "text-table": "~0.2.0", "tiny-relative-date": "^1.3.0", @@ -9752,7 +10068,7 @@ "license": "ISC" }, "node_modules/npm/node_modules/@npmcli/arborist": { - "version": "6.2.5", + "version": "6.2.8", "inBundle": true, "license": "ISC", "dependencies": { @@ -9772,7 +10088,7 @@ "hosted-git-info": "^6.1.1", "json-parse-even-better-errors": "^3.0.0", "json-stringify-nice": "^1.1.4", - "minimatch": "^6.1.6", + "minimatch": "^7.4.2", "nopt": "^7.0.0", "npm-install-checks": "^6.0.0", "npm-package-arg": "^10.1.0", @@ -9783,12 +10099,12 @@ "parse-conflict-json": "^3.0.0", "proc-log": "^3.0.0", "promise-all-reject-late": "^1.0.0", - "promise-call-limit": "^1.0.1", + "promise-call-limit": "^1.0.2", "read-package-json-fast": "^3.0.2", "semver": "^7.3.7", "ssri": "^10.0.1", "treeverse": "^3.0.0", - "walk-up-path": "^1.0.0" + "walk-up-path": "^3.0.1" }, "bin": { "arborist": "bin/index.js" @@ -9798,17 +10114,17 @@ } }, "node_modules/npm/node_modules/@npmcli/config": { - "version": "6.1.4", + "version": "6.1.6", "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/map-workspaces": "^3.0.2", - "ini": "^3.0.0", + "ini": "^4.1.0", "nopt": "^7.0.0", "proc-log": "^3.0.0", "read-package-json-fast": "^3.0.2", "semver": "^7.3.5", - "walk-up-path": "^1.0.0" + "walk-up-path": "^3.0.1" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -9837,13 +10153,12 @@ } }, "node_modules/npm/node_modules/@npmcli/git": { - "version": "4.0.3", + "version": "4.0.4", "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/promise-spawn": "^6.0.0", "lru-cache": "^7.4.4", - "mkdirp": "^1.0.4", "npm-pick-manifest": "^8.0.0", "proc-log": "^3.0.0", "promise-inflight": "^1.0.1", @@ -9871,13 +10186,13 @@ } }, "node_modules/npm/node_modules/@npmcli/map-workspaces": { - "version": "3.0.2", + "version": "3.0.3", "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/name-from-folder": "^2.0.0", - "glob": "^8.0.1", - "minimatch": "^6.1.6", + "glob": "^9.3.1", + "minimatch": "^7.4.2", "read-package-json-fast": "^3.0.0" }, "engines": { @@ -9885,7 +10200,7 @@ } }, "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { - "version": "5.0.0", + "version": "5.0.1", "inBundle": true, "license": "ISC", "dependencies": { @@ -9990,12 +10305,21 @@ "node": ">= 10" } }, - "node_modules/npm/node_modules/@tufjs/models": { + "node_modules/npm/node_modules/@tufjs/canonical-json": { "version": "1.0.0", "inBundle": true, "license": "MIT", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@tufjs/models": { + "version": "1.0.3", + "inBundle": true, + "license": "MIT", "dependencies": { - "minimatch": "^6.1.0" + "@tufjs/canonical-json": "1.0.0", + "minimatch": "^7.4.6" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -10186,13 +10510,13 @@ } }, "node_modules/npm/node_modules/cacache": { - "version": "17.0.4", + "version": "17.0.5", "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", - "glob": "^8.0.1", + "glob": "^9.3.1", "lru-cache": "^7.7.1", "minipass": "^4.0.0", "minipass-collect": "^1.0.2", @@ -10512,36 +10836,24 @@ } }, "node_modules/npm/node_modules/glob": { - "version": "8.1.0", + "version": "9.3.2", "inBundle": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "minimatch": "^7.4.1", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" }, "engines": { - "node": ">=12" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/npm/node_modules/glob/node_modules/minimatch": { - "version": "5.1.6", - "inBundle": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/npm/node_modules/graceful-fs": { - "version": "4.2.10", + "version": "4.2.11", "inBundle": true, "license": "ISC" }, @@ -10650,11 +10962,11 @@ "license": "BSD-3-Clause" }, "node_modules/npm/node_modules/ignore-walk": { - "version": "6.0.1", + "version": "6.0.2", "inBundle": true, "license": "ISC", "dependencies": { - "minimatch": "^6.1.6" + "minimatch": "^7.4.2" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -10696,11 +11008,11 @@ "license": "ISC" }, "node_modules/npm/node_modules/ini": { - "version": "3.0.1", + "version": "4.1.0", "inBundle": true, "license": "ISC", "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/init-package-json": { @@ -10798,7 +11110,7 @@ "license": "MIT" }, "node_modules/npm/node_modules/just-diff": { - "version": "5.2.0", + "version": "6.0.2", "inBundle": true, "license": "MIT" }, @@ -10820,16 +11132,16 @@ } }, "node_modules/npm/node_modules/libnpmdiff": { - "version": "5.0.13", + "version": "5.0.16", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.2.5", + "@npmcli/arborist": "^6.2.8", "@npmcli/disparity-colors": "^3.0.0", "@npmcli/installed-package-contents": "^2.0.2", "binary-extensions": "^2.2.0", "diff": "^5.1.0", - "minimatch": "^6.1.6", + "minimatch": "^7.4.2", "npm-package-arg": "^10.1.0", "pacote": "^15.0.8", "tar": "^6.1.13" @@ -10839,11 +11151,11 @@ } }, "node_modules/npm/node_modules/libnpmexec": { - "version": "5.0.13", + "version": "5.0.16", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.2.5", + "@npmcli/arborist": "^6.2.8", "@npmcli/run-script": "^6.0.0", "chalk": "^4.1.0", "ci-info": "^3.7.1", @@ -10854,18 +11166,18 @@ "read": "^2.0.0", "read-package-json-fast": "^3.0.2", "semver": "^7.3.7", - "walk-up-path": "^1.0.0" + "walk-up-path": "^3.0.1" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmfund": { - "version": "4.0.13", + "version": "4.0.16", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.2.5" + "@npmcli/arborist": "^6.2.8" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -10896,11 +11208,11 @@ } }, "node_modules/npm/node_modules/libnpmpack": { - "version": "5.0.13", + "version": "5.0.16", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.2.5", + "@npmcli/arborist": "^6.2.8", "@npmcli/run-script": "^6.0.0", "npm-package-arg": "^10.1.0", "pacote": "^15.0.8" @@ -10910,7 +11222,7 @@ } }, "node_modules/npm/node_modules/libnpmpublish": { - "version": "7.1.2", + "version": "7.1.3", "inBundle": true, "license": "ISC", "dependencies": { @@ -10974,7 +11286,7 @@ } }, "node_modules/npm/node_modules/make-fetch-happen": { - "version": "11.0.3", + "version": "11.1.0", "inBundle": true, "license": "ISC", "dependencies": { @@ -10999,7 +11311,7 @@ } }, "node_modules/npm/node_modules/minimatch": { - "version": "6.2.0", + "version": "7.4.6", "inBundle": true, "license": "ISC", "dependencies": { @@ -11013,7 +11325,7 @@ } }, "node_modules/npm/node_modules/minipass": { - "version": "4.2.4", + "version": "4.2.8", "inBundle": true, "license": "ISC", "engines": { @@ -11043,7 +11355,7 @@ } }, "node_modules/npm/node_modules/minipass-fetch": { - "version": "3.0.1", + "version": "3.0.2", "inBundle": true, "license": "MIT", "dependencies": { @@ -11466,7 +11778,7 @@ } }, "node_modules/npm/node_modules/node-gyp/node_modules/readable-stream": { - "version": "3.6.1", + "version": "3.6.2", "inBundle": true, "license": "MIT", "dependencies": { @@ -11526,7 +11838,7 @@ } }, "node_modules/npm/node_modules/nopt": { - "version": "7.0.0", + "version": "7.1.0", "inBundle": true, "license": "ISC", "dependencies": { @@ -11576,7 +11888,7 @@ } }, "node_modules/npm/node_modules/npm-install-checks": { - "version": "6.0.0", + "version": "6.1.1", "inBundle": true, "license": "BSD-2-Clause", "dependencies": { @@ -11646,7 +11958,7 @@ } }, "node_modules/npm/node_modules/npm-registry-fetch": { - "version": "14.0.3", + "version": "14.0.4", "inBundle": true, "license": "ISC", "dependencies": { @@ -11738,12 +12050,12 @@ } }, "node_modules/npm/node_modules/parse-conflict-json": { - "version": "3.0.0", + "version": "3.0.1", "inBundle": true, "license": "ISC", "dependencies": { "json-parse-even-better-errors": "^3.0.0", - "just-diff": "^5.0.1", + "just-diff": "^6.0.0", "just-diff-apply": "^5.2.0" }, "engines": { @@ -11758,6 +12070,21 @@ "node": ">=0.10.0" } }, + "node_modules/npm/node_modules/path-scurry": { + "version": "1.6.3", + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^7.14.1", + "minipass": "^4.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/npm/node_modules/postcss-selector-parser": { "version": "6.0.11", "inBundle": true, @@ -11795,7 +12122,7 @@ } }, "node_modules/npm/node_modules/promise-call-limit": { - "version": "1.0.1", + "version": "1.0.2", "inBundle": true, "license": "ISC", "funding": { @@ -11838,7 +12165,7 @@ } }, "node_modules/npm/node_modules/read": { - "version": "2.0.0", + "version": "2.1.0", "inBundle": true, "license": "ISC", "dependencies": { @@ -11857,11 +12184,11 @@ } }, "node_modules/npm/node_modules/read-package-json": { - "version": "6.0.0", + "version": "6.0.1", "inBundle": true, "license": "ISC", "dependencies": { - "glob": "^8.0.1", + "glob": "^9.3.0", "json-parse-even-better-errors": "^3.0.0", "normalize-package-data": "^5.0.0", "npm-normalize-package-bin": "^3.0.0" @@ -11969,7 +12296,7 @@ "optional": true }, "node_modules/npm/node_modules/semver": { - "version": "7.3.8", + "version": "7.5.0", "inBundle": true, "license": "ISC", "dependencies": { @@ -12004,13 +12331,13 @@ "license": "ISC" }, "node_modules/npm/node_modules/sigstore": { - "version": "1.1.1", + "version": "1.3.0", "inBundle": true, "license": "Apache-2.0", "dependencies": { "@sigstore/protobuf-specs": "^0.1.0", "make-fetch-happen": "^11.0.1", - "tuf-js": "^1.0.0" + "tuf-js": "^1.1.3" }, "bin": { "sigstore": "bin/sigstore.js" @@ -12078,12 +12405,12 @@ } }, "node_modules/npm/node_modules/spdx-license-ids": { - "version": "3.0.12", + "version": "3.0.13", "inBundle": true, "license": "CC0-1.0" }, "node_modules/npm/node_modules/ssri": { - "version": "10.0.1", + "version": "10.0.3", "inBundle": true, "license": "ISC", "dependencies": { @@ -12193,11 +12520,11 @@ } }, "node_modules/npm/node_modules/tuf-js": { - "version": "1.1.1", + "version": "1.1.4", "inBundle": true, "license": "MIT", "dependencies": { - "@tufjs/models": "1.0.0", + "@tufjs/models": "1.0.3", "make-fetch-happen": "^11.0.1" }, "engines": { @@ -12252,7 +12579,7 @@ } }, "node_modules/npm/node_modules/walk-up-path": { - "version": "1.0.0", + "version": "3.0.1", "inBundle": true, "license": "ISC" }, @@ -12691,6 +13018,15 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/pbkdf2": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", @@ -13069,9 +13405,9 @@ } }, "node_modules/react-frame-component": { - "version": "5.2.6", - "resolved": "https://registry.npmjs.org/react-frame-component/-/react-frame-component-5.2.6.tgz", - "integrity": "sha512-CwkEM5VSt6nFwZ1Op8hi3JB5rPseZlmnp5CGiismVTauE6S4Jsc4TNMlT0O7Cts4WgIC3ZBAQ2p1Mm9XgLbj+w==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/react-frame-component/-/react-frame-component-4.1.3.tgz", + "integrity": "sha512-4PurhctiqnmC1F5prPZ+LdsalH7pZ3SFA5xoc0HBe8mSHctdLLt4Cr2WXfXOoajHBYq/yiipp9zOgx+vy8GiEA==", "peerDependencies": { "prop-types": "^15.5.9", "react": ">= 16.3", @@ -13085,11 +13421,11 @@ "dev": true }, "node_modules/react-router": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.9.0.tgz", - "integrity": "sha512-51lKevGNUHrt6kLuX3e/ihrXoXCa9ixY/nVWRLlob4r/l0f45x3SzBvYJe3ctleLUQQ5fVa4RGgJOTH7D9Umhw==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.10.0.tgz", + "integrity": "sha512-Nrg0BWpQqrC3ZFFkyewrflCud9dio9ME3ojHCF/WLsprJVzkq3q3UeEhMCAW1dobjeGbWgjNn/PVF6m46ANxXQ==", "dependencies": { - "@remix-run/router": "1.4.0" + "@remix-run/router": "1.5.0" }, "engines": { "node": ">=14" @@ -13099,12 +13435,12 @@ } }, "node_modules/react-router-dom": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.9.0.tgz", - "integrity": "sha512-/seUAPY01VAuwkGyVBPCn1OXfVbaWGGu4QN9uj0kCPcTyNYgL1ldZpxZUpRU7BLheKQI4Twtl/OW2nHRF1u26Q==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.10.0.tgz", + "integrity": "sha512-E5dfxRPuXKJqzwSe/qGcqdwa18QiWC6f3H3cWXM24qj4N0/beCIf/CWTipop2xm7mR0RCS99NnaqPNjHtrAzCg==", "dependencies": { - "@remix-run/router": "1.4.0", - "react-router": "6.9.0" + "@remix-run/router": "1.5.0", + "react-router": "6.10.0" }, "engines": { "node": ">=14" @@ -14712,6 +15048,21 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, "node_modules/tty-browserify": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", @@ -14781,6 +15132,20 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, + "node_modules/typescript": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=12.20" + } + }, "node_modules/umd": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", diff --git a/package.json b/package.json index 28b5fab23..7c2bea8b5 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "homebrewery", "description": "Create authentic looking D&D homebrews using only markdown", - "version": "3.7.2", + "version": "3.8.0", "engines": { - "node": "16.11.x" + "node": "16.13.x" }, "repository": { "type": "git", @@ -23,7 +23,10 @@ "test:coverage": "jest --coverage --silent --runInBand", "test:dev": "jest --verbose --watch", "test:basic": "jest tests/markdown/basic.test.js --verbose", - "test:mustache-span": "jest tests/markdown/mustache-span.test.js --verbose", + "test:mustache-syntax": "jest '.*(mustache-syntax).*' --verbose --noStackTrace", + "test:mustache-syntax:inline": "jest '.*(mustache-syntax).*' -t '^Inline:.*' --verbose --noStackTrace", + "test:mustache-syntax:block": "jest '.*(mustache-syntax).*' -t '^Block:.*' --verbose --noStackTrace", + "test:mustache-syntax:injection": "jest '.*(mustache-syntax).*' -t '^Injection:.*' --verbose --noStackTrace", "test:route": "jest tests/routes/static-pages.test.js --verbose", "phb": "node scripts/phb.js", "prod": "set NODE_ENV=production && npm run build", @@ -45,20 +48,23 @@ "coveragePathIgnorePatterns": [ "build/*" ], - "coverageThreshold" : { - "global" : { - "statements" : 25, - "branches" : 10, - "functions" : 22, - "lines" : 25 + "coverageThreshold": { + "global": { + "statements": 25, + "branches": 10, + "functions": 22, + "lines": 25 }, - "server/homebrew.api.js" : { - "statements" : 65, - "branches" : 50, - "functions" : 60, - "lines" : 70 + "server/homebrew.api.js": { + "statements": 65, + "branches": 50, + "functions": 60, + "lines": 70 } - } + }, + "setupFilesAfterEnv": [ + "jest-expect-message" + ] }, "babel": { "presets": [ @@ -70,9 +76,9 @@ ] }, "dependencies": { - "@babel/core": "^7.21.3", - "@babel/plugin-transform-runtime": "^7.21.0", - "@babel/preset-env": "^7.19.4", + "@babel/core": "^7.21.4", + "@babel/plugin-transform-runtime": "^7.21.4", + "@babel/preset-env": "^7.21.4", "@babel/preset-react": "^7.18.6", "@googleapis/drive": "^5.0.2", "body-parser": "^1.20.2", @@ -93,22 +99,24 @@ "marked-extended-tables": "^1.0.5", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.29.4", - "mongoose": "^7.0.3", + "mongoose": "^7.1.0", "nanoid": "3.3.4", "nconf": "^0.12.0", - "npm": "^9.6.2", + "npm": "^9.6.5", "react": "^17.0.2", "react-dom": "^17.0.2", - "react-frame-component": "5.2.6", - "react-router-dom": "6.9.0", + "react-frame-component": "^4.1.3", + "react-router-dom": "6.10.0", "sanitize-filename": "1.6.3", "superagent": "^6.1.0", "vitreum": "git+https://git@github.com/calculuschild/vitreum.git" }, "devDependencies": { - "eslint": "^8.36.0", + "eslint": "^8.39.0", "eslint-plugin-react": "^7.32.2", + "eslint-plugin-jest": "^27.2.1", "jest": "^29.5.0", + "jest-expect-message": "^1.1.3", "supertest": "^6.3.3" } } diff --git a/server/app.js b/server/app.js index 5b153d115..22c9d9dac 100644 --- a/server/app.js +++ b/server/app.js @@ -43,8 +43,7 @@ const sanitizeBrew = (brew, accessType)=>{ }; app.use('/', serveCompressedStaticAssets(`build`)); - -//app.use(express.static(`${__dirname}/build`)); +app.use(require('./middleware/content-negotiation.js')); app.use(require('body-parser').json({ limit: '25mb' })); app.use(require('cookie-parser')()); app.use(require('./forcessl.mw.js')); diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 6f5fcb1ef..39fa021e5 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -305,7 +305,7 @@ If you believe you should have access to this brew, ask the file owner to invite if(brew.authors.length === 0) { // Delete brew if there are no authors left - await brew.remove() + await HomebrewModel.deleteOne({ _id: brew._id }) .catch((err)=>{ console.error(err); throw { status: 500, message: 'Error while removing' }; diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 5ab6ac4fc..c6443be7b 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -10,7 +10,6 @@ describe('Tests for api', ()=>{ let modelBrew; let saveFunc; - let removeFunc; let markModifiedFunc; let saved; @@ -20,18 +19,15 @@ describe('Tests for api', ()=>{ saved = { ...this, _id: '1' }; return saved; }); - removeFunc = jest.fn(async function() {}); markModifiedFunc = jest.fn(()=>true); modelBrew = (brew)=>({ ...brew, save : saveFunc, - remove : removeFunc, markModified : markModifiedFunc, toObject : function() { delete this.save; delete this.toObject; - delete this.remove; delete this.markModified; return this; } @@ -569,13 +565,14 @@ brew`); req.brew = brew; }); model.findOne = jest.fn(async ()=>modelBrew(brew)); + model.deleteOne = jest.fn(async ()=>{}); const req = {}; await api.deleteBrew(req, res); expect(api.getBrew).toHaveBeenCalled(); expect(model.findOne).toHaveBeenCalled(); - expect(removeFunc).toHaveBeenCalled(); + expect(model.deleteOne).toHaveBeenCalled(); }); it('should throw on delete error', async ()=>{ @@ -587,7 +584,7 @@ brew`); req.brew = brew; }); model.findOne = jest.fn(async ()=>modelBrew(brew)); - removeFunc = jest.fn(async ()=>{ throw 'err'; }); + model.deleteOne = jest.fn(async ()=>{ throw 'err'; }); const req = {}; let err; @@ -600,7 +597,7 @@ brew`); expect(err).not.toBeUndefined(); expect(api.getBrew).toHaveBeenCalled(); expect(model.findOne).toHaveBeenCalled(); - expect(removeFunc).toHaveBeenCalled(); + expect(model.deleteOne).toHaveBeenCalled(); }); it('should delete when one author', async ()=>{ @@ -612,13 +609,14 @@ brew`); req.brew = brew; }); model.findOne = jest.fn(async ()=>modelBrew(brew)); + model.deleteOne = jest.fn(async ()=>{}); const req = { account: { username: 'test' } }; await api.deleteBrew(req, res); expect(api.getBrew).toHaveBeenCalled(); expect(model.findOne).toHaveBeenCalled(); - expect(removeFunc).toHaveBeenCalled(); + expect(model.deleteOne).toHaveBeenCalled(); }); it('should remove one author when multiple present', async ()=>{ @@ -630,6 +628,7 @@ brew`); req.brew = brew; }); model.findOne = jest.fn(async ()=>modelBrew(brew)); + model.deleteOne = jest.fn(async ()=>{}); const req = { account: { username: 'test' } }; await api.deleteBrew(req, res); @@ -637,7 +636,7 @@ brew`); expect(api.getBrew).toHaveBeenCalled(); expect(markModifiedFunc).toHaveBeenCalled(); expect(model.findOne).toHaveBeenCalled(); - expect(removeFunc).not.toHaveBeenCalled(); + expect(model.deleteOne).not.toHaveBeenCalled(); expect(saveFunc).toHaveBeenCalled(); expect(saved.authors).toEqual(['test2']); }); @@ -651,6 +650,7 @@ brew`); req.brew = brew; }); model.findOne = jest.fn(async ()=>modelBrew(brew)); + model.deleteOne = jest.fn(async ()=>{}); saveFunc = jest.fn(async ()=>{ throw 'err'; }); const req = { account: { username: 'test' } }; @@ -664,7 +664,7 @@ brew`); expect(err).not.toBeUndefined(); expect(api.getBrew).toHaveBeenCalled(); expect(model.findOne).toHaveBeenCalled(); - expect(removeFunc).not.toHaveBeenCalled(); + expect(model.deleteOne).not.toHaveBeenCalled(); expect(saveFunc).toHaveBeenCalled(); }); @@ -677,6 +677,7 @@ brew`); req.brew = brew; }); model.findOne = jest.fn(async ()=>modelBrew(brew)); + model.deleteOne = jest.fn(async ()=>{}); api.deleteGoogleBrew = jest.fn(async ()=>true); const req = { account: { username: 'test' } }; @@ -684,7 +685,7 @@ brew`); expect(api.getBrew).toHaveBeenCalled(); expect(model.findOne).toHaveBeenCalled(); - expect(removeFunc).toHaveBeenCalled(); + expect(model.deleteOne).toHaveBeenCalled(); expect(api.deleteGoogleBrew).toHaveBeenCalled(); }); @@ -697,6 +698,7 @@ brew`); req.brew = brew; }); model.findOne = jest.fn(async ()=>modelBrew(brew)); + model.deleteOne = jest.fn(async ()=>{}); api.deleteGoogleBrew = jest.fn(async ()=>{ throw 'err'; }); @@ -706,7 +708,7 @@ brew`); expect(api.getBrew).toHaveBeenCalled(); expect(model.findOne).toHaveBeenCalled(); - expect(removeFunc).toHaveBeenCalled(); + expect(model.deleteOne).toHaveBeenCalled(); expect(api.deleteGoogleBrew).toHaveBeenCalled(); }); @@ -719,6 +721,7 @@ brew`); req.brew = brew; }); model.findOne = jest.fn(async ()=>modelBrew(brew)); + model.deleteOne = jest.fn(async ()=>{}); api.deleteGoogleBrew = jest.fn(async ()=>true); const req = { account: { username: 'test' } }; @@ -727,7 +730,7 @@ brew`); expect(api.getBrew).toHaveBeenCalled(); expect(markModifiedFunc).toHaveBeenCalled(); expect(model.findOne).toHaveBeenCalled(); - expect(removeFunc).not.toHaveBeenCalled(); + expect(model.deleteOne).not.toHaveBeenCalled(); expect(api.deleteGoogleBrew).toHaveBeenCalled(); expect(saveFunc).toHaveBeenCalled(); expect(saved.authors).toEqual(['test2']); @@ -745,6 +748,7 @@ brew`); req.brew = brew; }); model.findOne = jest.fn(async ()=>modelBrew(brew)); + model.deleteOne = jest.fn(async ()=>{}); api.deleteGoogleBrew = jest.fn(async ()=>true); const req = { account: { username: 'test2' } }; @@ -752,7 +756,7 @@ brew`); expect(api.getBrew).toHaveBeenCalled(); expect(model.findOne).toHaveBeenCalled(); - expect(removeFunc).not.toHaveBeenCalled(); + expect(model.deleteOne).not.toHaveBeenCalled(); expect(api.deleteGoogleBrew).not.toHaveBeenCalled(); expect(saveFunc).toHaveBeenCalled(); expect(saved.authors).toEqual(['test']); diff --git a/server/middleware/content-negotiation.js b/server/middleware/content-negotiation.js new file mode 100644 index 000000000..201e64a25 --- /dev/null +++ b/server/middleware/content-negotiation.js @@ -0,0 +1,12 @@ +module.exports = (req, res, next)=>{ + const isImageRequest = req.get('Accept')?.split(',') + ?.filter((h)=>!h.includes('q=')) + ?.every((h)=>/image\/.*/.test(h)); + if(isImageRequest) { + return res.status(406).send({ + message : 'Request for image at this URL is not supported' + }); + } + + next(); +}; \ No newline at end of file diff --git a/server/middleware/content-negotiation.spec.js b/server/middleware/content-negotiation.spec.js new file mode 100644 index 000000000..68f22eb1c --- /dev/null +++ b/server/middleware/content-negotiation.spec.js @@ -0,0 +1,41 @@ +const contentNegotiationMiddleware = require('./content-negotiation.js'); + +describe('content-negotiation-middleware', ()=>{ + let request; + let response; + let next; + + beforeEach(()=>{ + request = { + get : function(key) { + return this[key]; + } + }; + response = { + status : jest.fn(()=>response), + send : jest.fn(()=>{}) + }; + next = jest.fn(); + }); + + it('should return 406 on image request', ()=>{ + contentNegotiationMiddleware({ + Accept : 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8', + ...request + }, response); + + expect(response.status).toHaveBeenLastCalledWith(406); + expect(response.send).toHaveBeenCalledWith({ + message : 'Request for image at this URL is not supported' + }); + }); + + it('should call next on non-image request', ()=>{ + contentNegotiationMiddleware({ + Accept : 'text,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8', + ...request + }, response, next); + + expect(next).toHaveBeenCalled(); + }); +}); \ No newline at end of file diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 16623b8a5..1960776d3 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -134,7 +134,7 @@ const mustacheInjectInline = { const match = inlineRegex.exec(src); if(match) { const lastToken = tokens[tokens.length - 1]; - if(!lastToken) + if(!lastToken || lastToken.type == 'mustacheInjectInline') return false; const tags = ` ${processStyleTags(match[1])}`; @@ -169,7 +169,7 @@ const mustacheInjectBlock = { const match = inlineRegex.exec(src); if(match) { const lastToken = tokens[tokens.length - 1]; - if(!lastToken) + if(!lastToken || lastToken.type == 'mustacheInjectBlock') return false; lastToken.originalType = 'mustacheInjectBlock'; diff --git a/shared/naturalcrit/nav/nav.jsx b/shared/naturalcrit/nav/nav.jsx index ef7d387e9..5d5aacd78 100644 --- a/shared/naturalcrit/nav/nav.jsx +++ b/shared/naturalcrit/nav/nav.jsx @@ -29,7 +29,7 @@ const Nav = { section : createClass({ displayName : 'Nav.section', render : function(){ - return
    + return
    {this.props.children}
    ; } diff --git a/shared/naturalcrit/nav/nav.less b/shared/naturalcrit/nav/nav.less index 43eaa0819..e01715a95 100644 --- a/shared/naturalcrit/nav/nav.less +++ b/shared/naturalcrit/nav/nav.less @@ -13,6 +13,7 @@ nav{ position : relative; display : flex; justify-content : space-between; + z-index : 2; } .navSection{ display : flex; diff --git a/tests/markdown/mustache-span.test.js b/tests/markdown/mustache-span.test.js deleted file mode 100644 index 6d249ebcb..000000000 --- a/tests/markdown/mustache-span.test.js +++ /dev/null @@ -1,128 +0,0 @@ -/* eslint-disable max-lines */ - -const Markdown = require('naturalcrit/markdown.js'); - -test('Renders a mustache span with text only', function() { - const source = '{{ text}}'; - const rendered = Markdown.render(source); - expect(rendered).toBe('text'); -}); - -test('Renders a mustache span with text only, but with spaces', function() { - const source = '{{ this is a text}}'; - const rendered = Markdown.render(source); - expect(rendered).toBe('this is a text'); -}); - -test('Renders an empty mustache span', function() { - const source = '{{}}'; - const rendered = Markdown.render(source); - expect(rendered).toBe(''); -}); - -test('Renders a mustache span with just a space', function() { - const source = '{{ }}'; - const rendered = Markdown.render(source); - expect(rendered).toBe(''); -}); - -test('Renders a mustache span with a few spaces only', function() { - const source = '{{ }}'; - const rendered = Markdown.render(source); - expect(rendered).toBe(''); -}); - -test('Renders a mustache span with text and class', function() { - const source = '{{my-class text}}'; - const rendered = Markdown.render(source); - // FIXME: why do we have those two extra spaces after closing "? - expect(rendered).toBe('text'); -}); - -test('Renders a mustache span with text and two classes', function() { - const source = '{{my-class,my-class2 text}}'; - const rendered = Markdown.render(source); - // FIXME: why do we have those two extra spaces after closing "? - expect(rendered).toBe('text'); -}); - -test('Renders a mustache span with text with spaces and class', function() { - const source = '{{my-class this is a text}}'; - const rendered = Markdown.render(source); - // FIXME: why do we have those two extra spaces after closing "? - expect(rendered).toBe('this is a text'); -}); - -test('Renders a mustache span with text and id', function() { - const source = '{{#my-span text}}'; - const rendered = Markdown.render(source); - // FIXME: why do we have that one extra space after closing "? - expect(rendered).toBe('text'); -}); - -test('Renders a mustache span with text and two ids', function() { - const source = '{{#my-span,#my-favorite-span text}}'; - const rendered = Markdown.render(source); - // FIXME: do we need to report an error here somehow? - expect(rendered).toBe('text'); -}); - -test('Renders a mustache span with text and css property', function() { - const source = '{{color:red text}}'; - const rendered = Markdown.render(source); - expect(rendered).toBe('text'); -}); - -test('Renders a mustache span with text and two css properties', function() { - const source = '{{color:red,padding:5px text}}'; - const rendered = Markdown.render(source); - expect(rendered).toBe('text'); -}); - -test('Renders a mustache span with text and css property which contains quotes', function() { - const source = '{{font:"trebuchet ms" text}}'; - const rendered = Markdown.render(source); - // FIXME: is it correct to remove quotes surrounding css property value? - expect(rendered).toBe('text'); -}); - -test('Renders a mustache span with text and two css properties which contains quotes', function() { - const source = '{{font:"trebuchet ms",padding:"5px 10px" text}}'; - const rendered = Markdown.render(source); - expect(rendered).toBe('text'); -}); - - -test('Renders a mustache span with text with quotes and css property which contains quotes', function() { - const source = '{{font:"trebuchet ms" text "with quotes"}}'; - const rendered = Markdown.render(source); - expect(rendered).toBe('text “with quotes”'); -}); - -test('Renders a mustache span with text, id, class and a couple of css properties', function() { - const source = '{{pen,#author,color:orange,font-family:"trebuchet ms" text}}'; - const rendered = Markdown.render(source); - expect(rendered).toBe('text'); -}); - -// TODO: add tests for ID with accordance to CSS spec: -// -// From https://drafts.csswg.org/selectors/#id-selectors: -// -// > An ID selector consists of a “number sign” (U+0023, #) immediately followed by the ID value, which must be a CSS identifier. -// -// From: https://www.w3.org/TR/CSS21/syndata.html#value-def-identifier: -// -// > In CSS, identifiers (including element names, classes, and IDs in selectors) can contain only the characters [a-zA-Z0-9] -// > and ISO 10646 characters U+00A0 and higher, plus the hyphen (-) and the underscore (_); -// > they cannot start with a digit, two hyphens, or a hyphen followed by a digit. -// > Identifiers can also contain escaped characters and any ISO 10646 character as a numeric code (see next item). -// > For instance, the identifier "B&W?" may be written as "B\&W\?" or "B\26 W\3F". -// > Note that Unicode is code-by-code equivalent to ISO 10646 (see [UNICODE] and [ISO10646]). - -// TODO: add tests for class with accordance to CSS spec: -// -// From: https://drafts.csswg.org/selectors/#class-html: -// -// > The class selector is given as a full stop (. U+002E) immediately followed by an identifier. - diff --git a/tests/markdown/mustache-syntax.test.js b/tests/markdown/mustache-syntax.test.js new file mode 100644 index 000000000..d9e1ce6f9 --- /dev/null +++ b/tests/markdown/mustache-syntax.test.js @@ -0,0 +1,375 @@ +/* eslint-disable max-lines */ + +const dedent = require('dedent-tabs').default; +const Markdown = require('naturalcrit/markdown.js'); + +// Marked.js adds line returns after closing tags on some default tokens. +// This removes those line returns for comparison sake. +String.prototype.trimReturns = function(){ + return this.replace(/\r?\n|\r/g, ''); +}; + +// Adding `.failing()` method to `describe` or `it` will make failing tests "pass" as long as they continue to fail. +// Remove the `.failing()` method once you have fixed the issue. + +describe('Inline: When using the Inline syntax {{ }}', ()=>{ + it.failing('Renders a mustache span with text only', function() { + const source = '{{ text}}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders a mustache span with text only, but with spaces', function() { + const source = '{{ this is a text}}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('this is a text'); + }); + + it.failing('Renders an empty mustache span', function() { + const source = '{{}}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(''); + }); + + it.failing('Renders a mustache span with just a space', function() { + const source = '{{ }}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(''); + }); + + it.failing('Renders a mustache span with a few spaces only', function() { + const source = '{{ }}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(''); + }); + + it.failing('Renders a mustache span with text and class', function() { + const source = '{{my-class text}}'; + const rendered = Markdown.render(source); + // FIXME: adds two extra \s before closing `>` in opening tag. + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders a mustache span with text and two classes', function() { + const source = '{{my-class,my-class2 text}}'; + const rendered = Markdown.render(source); + // FIXME: adds two extra \s before closing `>` in opening tag. + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders a mustache span with text with spaces and class', function() { + const source = '{{my-class this is a text}}'; + const rendered = Markdown.render(source); + // FIXME: adds two extra \s before closing `>` in opening tag + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('this is a text'); + }); + + it.failing('Renders a mustache span with text and id', function() { + const source = '{{#my-span text}}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s before closing `>` in opening tag, and another after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders a mustache span with text and two ids', function() { + const source = '{{#my-span,#my-favorite-span text}}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s before closing `>` in opening tag, and another after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders a mustache span with text and css property', function() { + const source = '{{color:red text}}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders a mustache span with text and two css properties', function() { + const source = '{{color:red,padding:5px text}}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders a mustache span with text and css property which contains quotes', function() { + const source = '{{font-family:"trebuchet ms" text}}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders a mustache span with text and two css properties which contains quotes', function() { + const source = '{{font-family:"trebuchet ms",padding:"5px 10px" text}}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + + it.failing('Renders a mustache span with text with quotes and css property which contains quotes', function() { + const source = '{{font-family:"trebuchet ms" text "with quotes"}}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text “with quotes”'); + }); + + it('Renders a mustache span with text, id, class and a couple of css properties', function() { + const source = '{{pen,#author,color:orange,font-family:"trebuchet ms" text}}'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); +}); + +// BLOCK SYNTAX + +describe(`Block: When using the Block syntax {{tags\\ntext\\n}}`, ()=>{ + it.failing('Renders a div with text only', function() { + const source = dedent`{{ + text + }}`; + const rendered = Markdown.render(source).trimReturns(); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

    text

    `); + }); + + it.failing('Renders an empty div', function() { + const source = dedent`{{ + + }}`; + const rendered = Markdown.render(source).trimReturns(); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`
    `); + }); + + it('Renders a single paragraph with opening and closing brackets', function() { + const source = dedent`{{ + }}`; + const rendered = Markdown.render(source).trimReturns(); + // this actually renders in HB as '{{ }}'... + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

    {{}}

    `); + }); + + it.failing('Renders a div with a single class', function() { + const source = dedent`{{cat + + }}`; + const rendered = Markdown.render(source).trimReturns(); + // FIXME: adds two extra \s before closing `>` in opening tag + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`
    `); + }); + + it.failing('Renders a div with a single class and text', function() { + const source = dedent`{{cat + Sample text. + }}`; + const rendered = Markdown.render(source).trimReturns(); + // FIXME: adds two extra \s before closing `>` in opening tag + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

    Sample text.

    `); + }); + + it.failing('Renders a div with two classes and text', function() { + const source = dedent`{{cat,dog + Sample text. + }}`; + const rendered = Markdown.render(source).trimReturns(); + // FIXME: adds two extra \s before closing `>` in opening tag + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

    Sample text.

    `); + }); + + it.failing('Renders a div with a style and text', function() { + const source = dedent`{{color:red + Sample text. + }}`; + const rendered = Markdown.render(source).trimReturns(); + // FIXME: adds two extra \s before closing `>` in opening tag + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

    Sample text.

    `); + }); + + it.failing('Renders a div with a class, style and text', function() { + const source = dedent`{{cat,color:red + Sample text. + }}`; + const rendered = Markdown.render(source).trimReturns(); + // FIXME: adds extra \s after the class attribute + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

    Sample text.

    `); + }); + + it('Renders a div with an ID, class, style and text (different order)', function() { + const source = dedent`{{color:red,cat,#dog + Sample text. + }}`; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

    Sample text.

    `); + }); + + it.failing('Renders a div with a single ID', function() { + const source = dedent`{{#cat,#dog + Sample text. + }}`; + const rendered = Markdown.render(source).trimReturns(); + // FIXME: adds extra \s before closing `>` in opening tag, and another after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

    Sample text.

    `); + }); +}); + +// MUSTACHE INJECTION SYNTAX + +describe('Injection: When an injection tag follows an element', ()=>{ + // FIXME: Most of these fail because injections currently replace attributes, rather than append to. Or just minor extra whitespace issues. + describe('and that element is an inline-block', ()=>{ + it.failing('Renders a span "text" with no injection', function() { + const source = '{{ text}}{}'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders a span "text" with injected Class name', function() { + const source = '{{ text}}{ClassName}'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders a span "text" with injected style', function() { + const source = '{{ text}}{color:red}'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders a span "text" with two injected styles', function() { + const source = '{{ text}}{color:red,background:blue}'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders an emphasis element with injected Class name', function() { + const source = '*emphasis*{big}'; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

    emphasis

    '); + }); + + it.failing('Renders a code element with injected style', function() { + const source = '`code`{background:gray}'; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

    code

    '); + }); + + it.failing('Renders an image element with injected style', function() { + const source = '![alt text](http://i.imgur.com/hMna6G0.png){position:absolute}'; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

    homebrew mug

    '); + }); + + it.failing('Renders an element modified by only the first of two consecutive injections', function() { + const source = '{{ text}}{color:red}{background:blue}'; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

    text{background:blue}

    '); + }); + }); + + describe('and that element is a block', ()=>{ + it.failing('renders a div "text" with no injection', function() { + const source = '{{\ntext\n}}\n{}'; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

    text

    '); + }); + + it.failing('renders a div "text" with injected Class name', function() { + const source = '{{\ntext\n}}\n{ClassName}'; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

    text

    '); + }); + + it.failing('renders a div "text" with injected style', function() { + const source = '{{\ntext\n}}\n{color:red}'; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

    text

    '); + }); + + it.failing('renders a div "text" with two injected styles', function() { + const source = dedent`{{ + text + }} + {color:red,background:blue}`; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

    text

    '); + }); + + it.failing('renders an h2 header "text" with injected class name', function() { + const source = dedent`## text + {ClassName}`; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

    text

    '); + }); + + it.failing('renders a table with injected class name', function() { + const source = dedent`| Experience Points | Level | + |:------------------|:-----:| + | 0 | 1 | + | 300 | 2 | + + {ClassName}`; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`
    Experience PointsLevel
    01
    3002
    `); + }); + + // it('renders a list with with a style injected into the
      tag', function() { + // const source = dedent`- Cursed Ritual of Bad Hair + // - Eliminate Vindictiveness in Gym Teacher + // - Ultimate Rite of the Confetti Angel + // - Dark Chant of the Dentists + // - Divine Spell of Crossdressing + // {color:red}`; + // const rendered = Markdown.render(source).trimReturns(); + // expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`...`); // FIXME: expect this to be injected into
        ? Currently injects into last
      • + // }); + + it.failing('renders an h2 header "text" with injected class name, and "secondInjection" as regular text on the next line.', function() { + const source = dedent`## text + {ClassName} + {secondInjection}`; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

        text

        {secondInjection}

        '); + }); + + it.failing('renders a div nested into another div, the inner with class=innerDiv and the other class=outerDiv', function() { + const source = dedent`{{ + outer text + {{ + inner text + }} + {innerDiv} + }} + {outerDiv}`; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

        outer text

        inner text

        '); + }); + }); +}); + + +// TODO: add tests for ID with accordance to CSS spec: +// +// From https://drafts.csswg.org/selectors/#id-selectors: +// +// > An ID selector consists of a “number sign” (U+0023, #) immediately followed by the ID value, which must be a CSS identifier. +// +// From: https://www.w3.org/TR/CSS21/syndata.html#value-def-identifier: +// +// > In CSS, identifiers (including element names, classes, and IDs in selectors) can contain only the characters [a-zA-Z0-9] +// > and ISO 10646 characters U+00A0 and higher, plus the hyphen (-) and the underscore (_); +// > they cannot start with a digit, two hyphens, or a hyphen followed by a digit. +// > Identifiers can also contain escaped characters and any ISO 10646 character as a numeric code (see next item). +// > For instance, the identifier "B&W?" may be written as "B\&W\?" or "B\26 W\3F". +// > Note that Unicode is code-by-code equivalent to ISO 10646 (see [UNICODE] and [ISO10646]). + +// TODO: add tests for class with accordance to CSS spec: +// +// From: https://drafts.csswg.org/selectors/#class-html: +// +// > The class selector is given as a full stop (. U+002E) immediately followed by an identifier. diff --git a/themes/V3/5ePHB/snippets.js b/themes/V3/5ePHB/snippets.js index 0a9005ddf..56ce0628c 100644 --- a/themes/V3/5ePHB/snippets.js +++ b/themes/V3/5ePHB/snippets.js @@ -3,7 +3,7 @@ const MagicGen = require('./snippets/magic.gen.js'); const ClassTableGen = require('./snippets/classtable.gen.js'); const MonsterBlockGen = require('./snippets/monsterblock.gen.js'); -const scriptGen = require('./snippets/script.gen.js'); +const scriptGen = require('./snippets/script.gen.js'); const ClassFeatureGen = require('./snippets/classfeature.gen.js'); const CoverPageGen = require('./snippets/coverpage.gen.js'); const PartCoverPageGen = require('./snippets/partcoverpage.gen.js'); @@ -171,9 +171,15 @@ module.exports = [ gen : MonsterBlockGen.monster('monster,frame,wide', 4), }, { - name : 'Cover Page', + name : 'Front Cover Page', icon : 'fac book-front-cover', - gen : CoverPageGen, + gen : CoverPageGen.front, + experimental : true + }, + { + name : 'Inside Cover Page', + icon : 'fac book-inside-cover', + gen : CoverPageGen.inside, experimental : true }, { diff --git a/themes/V3/5ePHB/snippets/coverpage.gen.js b/themes/V3/5ePHB/snippets/coverpage.gen.js index 5351f5db5..7f9d0cd2a 100644 --- a/themes/V3/5ePHB/snippets/coverpage.gen.js +++ b/themes/V3/5ePHB/snippets/coverpage.gen.js @@ -13,7 +13,7 @@ const titles = [ 'The Living Dead Above the Fearful Cage', 'Bahamut\'s Demonspawn', 'Across Gruumsh\'s Elemental Chaos', 'The Blade of Orcus', 'Beyond Revenge', 'Brain of Insanity', - 'Breed Battle!, A New Beginning', 'Evil Lake, A New Beginning', + 'A New Beginning', 'Evil Lake of the Merfolk', 'Invasion of the Gigantic Cat, Part II', 'Kraken War 2020', 'The Body Whisperers', 'The Doctor from Heaven', 'The Diabolical Tales of the Ape-Women', 'The Doctor Immortal', @@ -23,7 +23,7 @@ const titles = [ 'Sky of Zelda: The Thunder of Force', 'Core Battle', 'Ruby of Atlantis: The Quake of Peace', 'Deadly Amazement III', 'Dry Chaos IX', 'Gate Thunder', - 'Vyse\'s Skies', 'White Greatness III', + 'Vyse\'s Skies', 'Blue Greatness III', 'Yellow Divinity', 'Zidane\'s Ghost' ]; @@ -68,23 +68,43 @@ const footnote = [ 'In an amazing kingdom, in an age of sorcery and lost souls, eight space pirates quest for freedom.' ]; -module.exports = ()=>{ - return dedent` - {{coverPage }} +module.exports = { - {{logo ![](/assets/naturalCritLogo.svg)}} + front : function() { + return dedent` + {{frontCover}} - # ${_.sample(titles)} - ## ${_.sample(subtitles)} - __________ + {{logo ![](/assets/naturalCritLogo.svg)}} - {{banner HOMEBREW}} + # ${_.sample(titles)} + ## ${_.sample(subtitles)} + ___ - {{footnote - ${_.sample(footnote)} - }} + {{banner HOMEBREW}} - ![background image](https://i.imgur.com/Mqx8Vf7.png) + {{footnote + ${_.sample(footnote)} + }} - \page`; + ![background image](https://i.imgur.com/IwHRrbF.jpg){position:absolute,bottom:0,left:0,height:100%} + + \page`; + }, + + inside : function() { + return dedent` + {{insideCover}} + + # ${_.sample(titles)} + ## ${_.sample(subtitles)} + ___ + + {{imageMaskCenter${_.random(1, 16)},--offsetX:0%,--offsetY:0%,--rotation:0 + ![](https://i.imgur.com/IsfUnFR.jpg){height:100%} + }} + + {{logo ![](/assets/naturalCritLogo.svg)}} + + \page`; + } }; diff --git a/themes/V3/5ePHB/style.less b/themes/V3/5ePHB/style.less index ebb677b72..e3c09780f 100644 --- a/themes/V3/5ePHB/style.less +++ b/themes/V3/5ePHB/style.less @@ -1,739 +1,827 @@ -@layer V3_5ePHB { - @import (less) './themes/fonts/5e/fonts.less'; - @import (less) './themes/assets/assets.less'; +@import (less) './themes/fonts/5e/fonts.less'; +@import (less) './themes/assets/assets.less'; - :root { - //Colors - --HB_Color_Background: #EEE5CE; // Light parchment - --HB_Color_Accent: #E0E5C1; // Pastel green - --HB_Color_HeaderUnderline: #C0AD6A; // Gold - --HB_Color_HorizontalRule: #9C2B1B; // Maroon - --HB_Color_HeaderText: #58180D; // Dark Maroon - --HB_Color_MonsterStatBackground: #F2E5B5; // Light orange parchment - --HB_Color_CaptionText: #766649; // Brown - --HB_Color_WatercolorStain: #BBAD82; // Light brown - --HB_Color_Footnotes: #C9AD6A; // Gold +:root { + //Colors + --HB_Color_Background : #EEE5CE; // Light parchment + --HB_Color_Accent : #E0E5C1; // Pastel green + --HB_Color_HeaderUnderline : #C0AD6A; // Gold + --HB_Color_HorizontalRule : #9C2B1B; // Maroon + --HB_Color_HeaderText : #58180D; // Dark Maroon + --HB_Color_MonsterStatBackground : #F2E5B5; // Light orange parchment + --HB_Color_CaptionText : #766649; // Brown + --HB_Color_WatercolorStain : #BBAD82; // Light brown + --HB_Color_Footnotes : #C9AD6A; // Gold +} + +@page { margin: 0; } +body { + counter-reset : phb-page-numbers; +} +*{ + -webkit-print-color-adjust : exact; +} +.useSansSerif(){ + font-family : ScalySansRemake; + font-size : 0.318cm; + line-height : 1.2em; + p,dl,ul,ol { + line-height : 1.2em; } - - @page { - margin: 0; + ul, ol { + padding-left : 1em; } - - body { - counter-reset: phb-page-numbers; + em{ + font-style : italic; } - - * { - -webkit-print-color-adjust: exact; + strong{ + font-weight : 800; + letter-spacing : -0.02em; } - - .useSansSerif() { - font-family: ScalySansRemake; - font-size: 0.318cm; - line-height: 1.2em; - - p, - dl, - ul, - ol { - line-height: 1.2em; - } - - ul, - ol { - padding-left: 1em; - } - - em { - font-style: italic; - } - - strong { - font-weight: 800; - letter-spacing: -0.02em; - } - - h5+* { - margin-top: 0.1cm; - } + h5 + * { + margin-top : 0.1cm; } - - .useColumns(@multiplier : 1, @fillMode: balance) { - column-count: 2; - column-fill: @fillMode; - column-gap: 0.9cm; - column-width: 8cm * @multiplier; - -webkit-column-count: 2; - -moz-column-count: 2; - -webkit-column-width: 8cm * @multiplier; - -moz-column-width: 8cm * @multiplier; - -webkit-column-gap: 0.9cm; - -moz-column-gap: 0.9cm; - } - - .columnWrapper { - max-height: 100%; - column-span: all; - columns: inherit; - column-gap: inherit; - } - - .page { - .useColumns(); - counter-increment: phb-page-numbers; - position: relative; - z-index: 15; - box-sizing: border-box; - overflow: hidden; - height: 279.4mm; - width: 215.9mm; - background-color: var(--HB_Color_Background); - background-image: @backgroundImage; - padding: 1.4cm 1.9cm 1.7cm; - font-family: BookInsanityRemake; - font-size: 0.34cm; - text-rendering: optimizeLegibility; - page-break-before: always; - page-break-after: always; - } - +} +.useColumns(@multiplier : 1, @fillMode: balance){ + column-count : 2; + column-fill : @fillMode; + column-gap : 0.9cm; + column-width : 8cm * @multiplier; + -webkit-column-count : 2; + -moz-column-count : 2; + -webkit-column-width : 8cm * @multiplier; + -moz-column-width : 8cm * @multiplier; + -webkit-column-gap : 0.9cm; + -moz-column-gap : 0.9cm; +} +.columnWrapper{ + max-height : 100%; + column-span : all; + columns : inherit; + column-gap : inherit; +} +.page{ + .useColumns(); + counter-increment : phb-page-numbers; + position : relative; + z-index : 15; + box-sizing : border-box; + overflow : hidden; + height : 279.4mm; + width : 215.9mm; + background-color : var(--HB_Color_Background); + background-image : @backgroundImage; + padding : 1.4cm 1.9cm 1.7cm; + font-family : BookInsanityRemake; + font-size : 0.34cm; + text-rendering : optimizeLegibility; + page-break-before : always; + page-break-after : always; +} //***************************** // * BASE // *****************************/ - .page { - p { - overflow-wrap: break-word; //TODO: MAKE ALL MARGINS TOP-ONLY. USE * + * STYLE SELECTORS - display: block; - line-height: 1.25em; - - &+* { - margin-top: 0.325cm; - } - - &+p { - margin-top: 0; +.page{ + p{ + overflow-wrap : break-word; //TODO: MAKE ALL MARGINS TOP-ONLY. USE * + * STYLE SELECTORS + display : block; + line-height : 1.25em; + &+* { + margin-top : 0.325cm; + } + &+p{ + margin-top : 0; + } + } + ul{ + margin-bottom : 0.8em; + padding-left : 1.4em; + line-height : 1.25em; + list-style-position : outside; + list-style-type : disc; + } + ol{ + margin-bottom : 0.8em; + padding-left : 1.4em; + line-height : 1.25em; + list-style-position : outside; + list-style-type : decimal; + } + //Indents after p or lists + p+p, ul+p, ol+p{ + text-indent : 1em; + } + img{ + z-index : -1; + } + strong{ + font-weight : bold; + letter-spacing : -0.02em; + } + em{ + font-style : italic; + } + sup{ + vertical-align : super; + font-size : smaller; + line-height : 0; + } + sub{ + vertical-align : sub; + font-size : smaller; + line-height : 0; + } + //***************************** + // * HEADERS + // *****************************/ + h1,h2,h3,h4{ + font-family : MrEavesRemake; + font-weight : 800; + color : var(--HB_Color_HeaderText); + } + h1{ + margin-bottom : 0.18cm; //Margin-bottom only because this is WIDE + column-span : all; + font-size : 0.89cm; + line-height : 1em; + -webkit-column-span : all; + -moz-column-span : all; + &+p::first-letter{ + float : left; + font-family : SolberaImitationRemake; + line-height : 1em; + font-size : 3.5cm; + padding-left : 40px; //Allow background color to extend into margins + margin-left : -40px; + margin-top : -0.3cm; + padding-bottom : 2px; + margin-bottom : -20px; + background-image : linear-gradient(-45deg, #322814, #998250, #322814); + background-clip : text; + -webkit-background-clip : text; + color : rgba(0, 0, 0, 0); + } + &+p::first-line{ + font-variant : small-caps; + } + } + h2{ + //margin-top : 0px; //Font is misaligned. Shift up slightly + //margin-bottom : 0.05cm; + font-size : 0.75cm; + line-height : 0.988em; //Font is misaligned. Shift up slightly + } + h3{ + //margin-top : -0.1cm; //Font is misaligned. Shift up slightly + //margin-bottom : 0.1cm; + font-size : 0.575cm; + border-bottom : 2px solid var(--HB_Color_HeaderUnderline);; + line-height : 0.995em; //Font is misaligned. Shift up slightly + & + * { + margin-top: 0.17cm; + } + } + * + h3 { + margin-top : 0.155cm; //(0.325 - 0.17) + } + h4{ + //margin-top : -0.02cm; //Font is misaligned. Shift up slightly + //margin-bottom : 0.02cm; + font-size : 0.458cm; + line-height : 0.971em; //Font is misaligned. Shift up slightly + & + * { + margin-top: 0.09cm; + } + } + * + h4 { + margin-top : 0.235cm; //(0.325 - 0.09) + } + h5{ + //margin-top : -0.02cm; //Font is misaligned. Shift up slightly + //margin-bottom : 0.02cm; + font-family : ScalySansSmallCapsRemake; + font-size : 0.423cm; + font-weight : 900; + line-height : 0.951em; //Font is misaligned. Shift up slightly + & + * { + margin-top : 0.2cm; + } + } + //***************************** + // * TABLE + // *****************************/ + table{ + .useSansSerif(); + width : 100%; + line-height : 16px; + & + * { + margin-top : 0.325cm; + } + thead{ + display: table-row-group; + font-weight : 800; + th{ + vertical-align : bottom; + //padding : 0.14em 0.4em; + padding : 0px 1.5px; // Both of these are temporary, just to force + //line-height : 16px; // PDF to render at same height until Chrome 108 } } - - ul { - margin-bottom: 0.8em; - padding-left: 1.4em; - line-height: 1.25em; - list-style-position: outside; - list-style-type: disc; - } - - ol { - margin-bottom: 0.8em; - padding-left: 1.4em; - line-height: 1.25em; - list-style-position: outside; - list-style-type: decimal; - } - - //Indents after p or lists - p+p, - ul+p, - ol+p { - text-indent: 1em; - } - - img { - z-index: -1; - } - - strong { - font-weight: bold; - letter-spacing: -0.02em; - } - - em { - font-style: italic; - } - - sup { - vertical-align: super; - font-size: smaller; - line-height: 0; - } - - sub { - vertical-align: sub; - font-size: smaller; - line-height: 0; - } - - //***************************** - // * HEADERS - // *****************************/ - h1, - h2, - h3, - h4 { - font-family: MrEavesRemake; - font-weight: 800; - color: var(--HB_Color_HeaderText); - } - - h1 { - margin-bottom: 0.18cm; //Margin-bottom only because this is WIDE - column-span: all; - font-size: 0.89cm; - line-height: 1em; - -webkit-column-span: all; - -moz-column-span: all; - - &+p::first-letter { - float: left; - font-family: SolberaImitationRemake; - line-height: 1em; - font-size: 3.5cm; - padding-left: 40px; //Allow background color to extend into margins - margin-left: -40px; - margin-top: -0.3cm; - padding-bottom: 2px; - margin-bottom: -20px; - background-image: linear-gradient(-45deg, #322814, #998250, #322814); - background-clip: text; - -webkit-background-clip: text; - color: rgba(0, 0, 0, 0); - } - - &+p::first-line { - font-variant: small-caps; + tbody{ + tr{ + td{ + //padding : 0.14em 0.4em; + padding : 0px 1.5px; // Both of these are temporary, just to force + //line-height : 16px; // PDF to render at same height until Chrome 108 + } + &:nth-child(odd){ + background-color : var(--HB_Color_Accent); + } } } - - h2 { - //margin-top : 0px; //Font is misaligned. Shift up slightly - //margin-bottom : 0.05cm; - font-size: 0.75cm; - line-height: 0.988em; //Font is misaligned. Shift up slightly + } + //***************************** + // * NOTE + // *****************************/ + .note{ + .useSansSerif(); + background-color : var(--HB_Color_Accent); + border-style : solid; + border-width : 1px; + border-image : @noteBorderImage 12 stretch; + border-image-outset : 9px 0px; + border-image-width : 11px; + padding : 0.13cm 0.16cm; + box-shadow : 1px 4px 14px #888; + .page :where(&) { + margin-top : 9px; //Prevent top border getting cut off on colbreak } - - h3 { - //margin-top : -0.1cm; //Font is misaligned. Shift up slightly - //margin-bottom : 0.1cm; - font-size: 0.575cm; - border-bottom: 2px solid var(--HB_Color_HeaderUnderline); - ; - line-height: 0.995em; //Font is misaligned. Shift up slightly - - &+* { - margin-top: 0.17cm; - } + & + * { + margin-top : 0.45cm; } - - *+h3 { - margin-top: 0.155cm; //(0.325 - 0.17) - } - - h4 { - //margin-top : -0.02cm; //Font is misaligned. Shift up slightly - //margin-bottom : 0.02cm; - font-size: 0.458cm; - line-height: 0.971em; //Font is misaligned. Shift up slightly - - &+* { - margin-top: 0.09cm; - } - } - - *+h4 { - margin-top: 0.235cm; //(0.325 - 0.09) - } - h5 { - //margin-top : -0.02cm; //Font is misaligned. Shift up slightly - //margin-bottom : 0.02cm; - font-family: ScalySansSmallCapsRemake; - font-size: 0.423cm; - font-weight: 900; - line-height: 0.951em; //Font is misaligned. Shift up slightly - - &+* { - margin-top: 0.2cm; - } + font-size : 0.375cm; } - - //***************************** - // * TABLE - // *****************************/ - table { - .useSansSerif(); - width: 100%; - line-height: 16px; - - &+* { - margin-top: 0.325cm; - } - - thead { - display: table-row-group; - font-weight: 800; - - th { - vertical-align: bottom; - //padding : 0.14em 0.4em; - padding: 0px 1.5px; // Both of these are temporary, just to force - //line-height : 16px; // PDF to render at same height until Chrome 108 - } - } - - tbody { - tr { - td { - //padding : 0.14em 0.4em; - padding: 0px 1.5px; // Both of these are temporary, just to force - //line-height : 16px; // PDF to render at same height until Chrome 108 - } - - &:nth-child(odd) { - background-color: var(--HB_Color_Accent); - } - } - } + p{ + display : block; + padding-bottom : 0px; } + :last-child { + margin-bottom : 0; + } + } + //************************************ + // * DESCRIPTIVE TEXT BOX + // ************************************/ + .descriptive{ + .useSansSerif(); + background-color : #faf7ea; + border-style : solid; + border-width : 7px; + border-image : @descriptiveBoxImage 12 stretch; + border-image-outset : 4px; + padding : 0.1em; + box-shadow : 0 0 6px #faf7ea; + .page :where(&) { + margin-top : 4px; //Prevent top border getting cut off on colbreak + } + & + * { + margin-top : 0.45cm; + } + h5 { + font-size : 0.375cm; + } + p{ + display : block; + padding-bottom : 0px; + line-height : 1.5em; + } + :last-child { + margin-bottom : 0; + } + } + //***************************** + // * Images Snippets + // *****************************/ - //***************************** - // * NOTE - // *****************************/ - .note { - .useSansSerif(); - background-color: var(--HB_Color_Accent); - border-style: solid; - border-width: 1px; - border-image: @noteBorderImage 12 stretch; - border-image-outset: 9px 0px; - border-image-width: 11px; - padding: 0.13cm 0.16cm; - box-shadow: 1px 4px 14px #888; - - .page :where(&) { - margin-top: 9px; //Prevent top border getting cut off on colbreak + /* Arist Credit */ + .artist { + position : absolute; + width : auto; + text-align : center; + font-family : WalterTurncoat; + font-size : 0.27cm; + color : var(--HB_Color_CaptionText); + p, p + p { + margin : unset; + text-indent : unset; + line-height : 1em; + } + h5 { + font-size : 1.3em; + font-family : WalterTurncoat; + } + a{ + color : inherit; + text-decoration : unset; + &:hover { + text-decoration : underline; } - - &+* { - margin-top: 0.45cm; - } - - h5 { - font-size: 0.375cm; - } - - p { - display: block; - padding-bottom: 0px; - } - - :last-child { - margin-bottom: 0; - } - } - - //************************************ - // * DESCRIPTIVE TEXT BOX - // ************************************/ - .descriptive { - .useSansSerif(); - background-color: #faf7ea; - border-style: solid; - border-width: 7px; - border-image: @descriptiveBoxImage 12 stretch; - border-image-outset: 4px; - padding: 0.1em; - box-shadow: 0 0 6px #faf7ea; - - .page :where(&) { - margin-top: 4px; //Prevent top border getting cut off on colbreak - } - - &+* { - margin-top: 0.45cm; - } - - h5 { - font-size: 0.375cm; - } - - p { - display: block; - padding-bottom: 0px; - line-height: 1.5em; - } - - :last-child { - margin-bottom: 0; - } - } - - //***************************** - // * Images Snippets - // *****************************/ - - /* Arist Credit */ - .artist { - position: absolute; - width: auto; - text-align: center; - font-family: WalterTurncoat; - font-size: 0.27cm; - color: var(--HB_Color_CaptionText); - - p, - p+p { - margin: unset; - text-indent: unset; - line-height: 1em; - } - - h5 { - font-size: 1.3em; - font-family: WalterTurncoat; - } - - a { - color: inherit; - text-decoration: unset; - - &:hover { - text-decoration: underline; - } - } - } - - /* Watermark */ - .watermark { - display: grid !important; - place-items: center; - justify-content: center; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - font-size: 120px; - text-transform: uppercase; - color: black; - mix-blend-mode: overlay; - opacity: 30%; - transform: rotate(-45deg); - z-index: 500; - - p { - margin-bottom: none; - } - } - - /* Watercolor */ - [class*="watercolor"] { - position: absolute; - width: 2000px; - /* dimensions need to be real big so the user can set */ - height: 2000px; - /* height or width and the image will maintain aspect ratio */ - -webkit-mask-image: var(--wc); - -webkit-mask-size: contain; - -webkit-mask-repeat: no-repeat; - mask-image: var(--wc); - mask-size: contain; - mask-repeat: no-repeat; - background-size: cover; - background-color: var(--HB_Color_WatercolorStain); - /*default color*/ - --wc: @watercolor1; - /*default image*/ - z-index: -2; - } - - .watercolor1 { - --wc: @watercolor1; - } - - .watercolor2 { - --wc: @watercolor2; - } - - .watercolor3 { - --wc: @watercolor3; - } - - .watercolor4 { - --wc: @watercolor4; - } - - .watercolor5 { - --wc: @watercolor5; - } - - .watercolor6 { - --wc: @watercolor6; - } - - .watercolor7 { - --wc: @watercolor7; - } - - .watercolor8 { - --wc: @watercolor8; - } - - .watercolor9 { - --wc: @watercolor9; - } - - .watercolor10 { - --wc: @watercolor10; - } - - .watercolor11 { - --wc: @watercolor11; - } - - .watercolor12 { - --wc: @watercolor12; - } - - //***************************** - // * MONSTER STAT BLOCK - // *****************************/ - .monster { - .useSansSerif(); - - &.frame { - border-style: solid; - border-width: 7px 6px; - background-color: var(--HB_Color_MonsterStatBackground); - background-image: @monsterBlockBackground; - border-image: @monsterBorderImage 14 round; - border-image-outset: 0px 2px; - background-blend-mode: overlay; - background-attachment: fixed; - box-shadow: 1px 4px 14px #888; - padding: 4px 2px; - margin-left: -0.16cm; - margin-right: -0.16cm; - width: calc(100% + 0.32cm); - } - - position : relative; - padding : 0px; - margin-bottom : 0.325cm; - - //Headers - h2 { - font-size: 0.62cm; - line-height: 1em; - margin: 0; - - &+p { - font-size: 0.304cm; //Monster size and type subtext - margin-bottom: 0; - } - } - - h3 { - font-family: ScalySansRemake; - font-weight: 800; - font-variant: small-caps; - border-bottom: 2px solid var(--HB_Color_HeaderText); - // margin-top : 0.05cm; //Font is misaligned. Shift up slightly - padding-bottom: 0.05cm; - } - - //Triangle dividers - hr { - visibility: visible; - height: 6px; - margin: 0.12cm 0cm; - background-image: @redTriangleImage; - background-size: 100% 100%; - border: none; - } - - //Attribute Lists - All text between HRs is red - hr~ :is(dl, p) { - color: var(--HB_Color_HeaderText); - } - - hr:last-of-type { - &~ :is(dl, p) { - color: inherit; // After the HRs, reset text to black - } - - &+* { - margin-top: 0.325cm; // Space after last HR - } - } - - // Monster Ability table - hr+table:first-of-type { - margin: 0; - column-span: none; - 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; - } - } - - :last-child { - margin-bottom: 0; - } - } - - //Full Width - .monster.wide { - .useColumns(0.96, @fillMode: balance); - } - - //***************************** - // * FOOTER - // *****************************/ - &:after { - content: ""; - position: absolute; - bottom: 0px; - left: 0px; - z-index: 100; - height: 50px; - width: 100%; - background-image: @footerAccentImage; - background-size: cover; - } - - &:nth-child(even) { - &:after { - transform: scaleX(-1); - } - - .pageNumber { - left: 2px; - } - - .footnote { - left: 80px; - text-align: left; - } - } - - .pageNumber { - position: absolute; - right: 2px; - bottom: 22px; - width: 50px; - font-size: 0.9em; - color: var(--HB_Color_Footnotes); - text-align: center; - text-indent: 0; - - &.auto::after { - content: counter(phb-page-numbers); - } - } - - .footnote { - position: absolute; - right: 80px; - bottom: 32px; - z-index: 150; - width: 200px; - font-size: 0.8em; - color: var(--HB_Color_Footnotes); - text-align: right; - } - - //************************************ - // * CODE BLOCKS - // ************************************/ - code { - font-family: "Courier New", Courier, monospace; - font-size: 0.325; - padding: 0px 4px; - color: #58180d; - background-color: #faf7ea; - border-radius: 4px; - white-space: pre-wrap; - overflow-wrap: break-word; - } - - pre code { - width: 100%; - display: inline-block; - border-style: solid; - border-width: 1px; - border-image: @codeBorderImage 26 stretch; - border-image-width: 10px; - border-image-outset: 2px; - border-radius: 12px; - margin-bottom: 2px; - padding: 0.15cm; - - .page :where(&) { - margin-top: 2px; //Prevent top border getting cut off on colbreak - } - - &+* { - margin-top: 0.325cm; - } - } - - //***************************** - // * EXTRAS - // *****************************/ - hr { - visibility: hidden; - margin: 0px; - } - - .columnSplit { - visibility: hidden; - -webkit-column-break-after: always; - break-after: always; - -moz-column-break-after: always; - } - - //Avoid breaking up - blockquote, - table { - z-index: 15; - -webkit-column-break-inside: avoid; - page-break-inside: avoid; - break-inside: avoid; - } - - //Text indent right after table - table+p { - text-indent: 1em; - } - - // Nested lists - ul ul, - ol ol, - ul ol, - ol ul { - margin-bottom: 0px; - margin-left: 1.5em; - } - - li { - -webkit-column-break-inside: avoid; - page-break-inside: avoid; - break-inside: avoid; } } + /* Watermark */ + .watermark { + display : grid !important; + place-items : center; + justify-content : center; + position : absolute; + top : 0; + left : 0; + width : 100%; + height : 100%; + font-size : 120px; + text-transform : uppercase; + color : black; + mix-blend-mode : overlay; + opacity : 30%; + transform : rotate(-45deg); + z-index : 500; + p { + margin-bottom : none; + } + } + + /* Watercolor */ + [class*="watercolor"] { + position : absolute; + width : 2000px; /* dimensions need to be real big so the user can set */ + height : 2000px; /* height or width and the image will maintain aspect ratio */ + -webkit-mask-image : var(--wc); + -webkit-mask-size : contain; + -webkit-mask-repeat : no-repeat; + mask-image : var(--wc); + mask-size : contain; + mask-repeat : no-repeat; + background-size : cover; + background-color : var(--HB_Color_WatercolorStain); /*default color*/ + --wc : @watercolor1; /*default image*/ + z-index : -2; + } + + .watercolor1 { --wc : @watercolor1; } + .watercolor2 { --wc : @watercolor2; } + .watercolor3 { --wc : @watercolor3; } + .watercolor4 { --wc : @watercolor4; } + .watercolor5 { --wc : @watercolor5; } + .watercolor6 { --wc : @watercolor6; } + .watercolor7 { --wc : @watercolor7; } + .watercolor8 { --wc : @watercolor8; } + .watercolor9 { --wc : @watercolor9; } + .watercolor10 { --wc : @watercolor10; } + .watercolor11 { --wc : @watercolor11; } + .watercolor12 { --wc : @watercolor12; } + //***************************** + // * MONSTER STAT BLOCK + // *****************************/ + .monster { + .useSansSerif(); + &.frame { + border-style : solid; + border-width : 7px 6px; + background-color : var(--HB_Color_MonsterStatBackground); + background-image : @monsterBlockBackground; + border-image : @monsterBorderImage 14 round; + border-image-outset : 0px 2px; + background-blend-mode : overlay; + background-attachment : fixed; + box-shadow : 1px 4px 14px #888; + padding : 4px 2px; + margin-left : -0.16cm; + margin-right : -0.16cm; + width : calc(100% + 0.32cm); + } + + position : relative; + padding : 0px; + margin-bottom : 0.325cm; + + //Headers + h2{ + font-size : 0.62cm; + line-height : 1em; + margin : 0; + &+p { + font-size : 0.304cm; //Monster size and type subtext + margin-bottom : 0; + } + } + h3{ + font-family : ScalySansRemake; + font-weight : 800; + font-variant : small-caps; + border-bottom : 2px solid var(--HB_Color_HeaderText); + // margin-top : 0.05cm; //Font is misaligned. Shift up slightly + padding-bottom : 0.05cm; + } + + //Triangle dividers + hr{ + visibility : visible; + height : 6px; + margin : 0.12cm 0cm; + background-image : @redTriangleImage; + background-size : 100% 100%; + border : none; + } + + //Attribute Lists - All text between HRs is red + hr ~ :is(dl,p) { + color : var(--HB_Color_HeaderText); + } + hr:last-of-type { + & ~ :is(dl,p) { + color : inherit; // After the HRs, reset text to black + } + & + * { + margin-top : 0.325cm; // Space after last HR + } + } + + // Monster Ability table + hr + table:first-of-type{ + margin : 0; + column-span : none; + 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; + } + } + + :last-child { + margin-bottom : 0; + } + } + + //Full Width + .monster.wide{ + .useColumns(0.96, @fillMode: balance); + } + + //***************************** + // * FOOTER + // *****************************/ + &:after{ + content : ""; + position : absolute; + bottom : 0px; + left : 0px; + z-index : 100; + height : 50px; + width : 100%; + background-image : @footerAccentImage; + background-size : cover; + } + &:nth-child(even){ + &:after{ + transform : scaleX(-1); + } + .pageNumber{ + left : 2px; + } + .footnote{ + left : 80px; + text-align : left; + } + } + .pageNumber{ + position : absolute; + right : 2px; + bottom : 22px; + width : 50px; + font-size : 0.9em; + color : var(--HB_Color_Footnotes); + text-align : center; + text-indent : 0; + &.auto::after { + content : counter(phb-page-numbers); + } + } + .footnote{ + position : absolute; + right : 80px; + bottom : 32px; + z-index : 150; + width : 200px; + font-size : 0.8em; + color : var(--HB_Color_Footnotes); + text-align : right; + } + //************************************ + // * CODE BLOCKS + // ************************************/ + code{ + font-family : "Courier New", Courier, monospace; + font-size : 0.325; + padding : 0px 4px; + color : #58180d; + background-color : #faf7ea; + border-radius : 4px; + white-space : pre-wrap; + overflow-wrap : break-word; + } + + pre code{ + width : 100%; + display : inline-block; + border-style : solid; + border-width : 1px; + border-image : @codeBorderImage 26 stretch; + border-image-width : 10px; + border-image-outset : 2px; + border-radius : 12px; + margin-bottom : 2px; + padding : 0.15cm; + .page :where(&) { + margin-top : 2px; //Prevent top border getting cut off on colbreak + } + & + * { + margin-top : 0.325cm; + } + } + //***************************** + // * EXTRAS + // *****************************/ + hr{ + visibility : hidden; + margin : 0px; + } + .columnSplit { + visibility : hidden; + -webkit-column-break-after : always; + break-after : always; + -moz-column-break-after : always; + } + //Avoid breaking up + blockquote,table{ + z-index : 15; + -webkit-column-break-inside : avoid; + page-break-inside : avoid; + break-inside : avoid; + } + //Text indent right after table + table+p{ + text-indent : 1em; + } + // Nested lists + ul ul,ol ol,ul ol,ol ul{ + margin-bottom : 0px; + margin-left : 1.5em; + } + li{ + -webkit-column-break-inside : avoid; + page-break-inside : avoid; + break-inside : avoid; + } +} +//***************************** +// * SPELL LIST +// *****************************/ +.page .spellList{ + .useSansSerif(); + column-count : 2; + ul+h5{ + margin-top : 15px; + } + p, ul{ + font-size : 0.352cm; + line-height : 1.265em; + } + ul{ + margin-bottom : 0.5em; + padding-left : 1em; + text-indent : -1em; + list-style-type : none; + -webkit-column-break-inside : auto; + page-break-inside : auto; + break-inside : auto; + } + &.wide{ + column-count : 4; + } +} + +//***************************** +// * CLASS TABLE +// *****************************/ +.page .classTable{ +th[colspan]:not([rowspan]) { + white-space : nowrap; +} +&.frame { + margin-top : 0.7cm; + margin-bottom : 0.9cm; + margin-left : -0.1cm; + margin-right : -0.1cm; + width : calc(100% + 0.2cm); + border-collapse : separate; + background-color : white; + border : initial; + border-style : solid; + border-image-outset : 0.4cm 0.3cm; + border-image-repeat : stretch; + border-image-slice : 200; + border-image-source : @frameBorderImage; + border-image-width : 47px; + &.wide:first-child { + margin-top: 0.12cm; + } + & + * { + margin-top: 0; + } +} +&.decoration { + position:relative; +} +&.decoration::before { + content :''; + position : absolute; + background-image : @classTableDecoration, + @classTableDecoration; + background-size : contain, contain; + background-repeat : no-repeat, no-repeat; + background-position : top, bottom; + width : 7.75cm; + height : calc(100% + 3.3cm); + top : 50%; + left : 50%; + transform : translateY(-50%) translateX(-50%); + filter : drop-shadow(0px 0px 1px #C8C5C080); + z-index : -1; +} +&.decoration.wide::before { + width : calc(100% + 3.3cm); + height : 7.75cm; + background-position : left, right; +} +h5 + table{ + margin-top : 0.2cm; +} +} +//***************************** +// * FRONT COVER PAGE +// *****************************/ +.page:has(.frontCover) { + columns : 1; + text-align : center; + &:after { + all: unset; + } + h1 { + text-shadow: unset; + filter : drop-shadow(0 0 1.5px black) drop-shadow(0 0 0 black) + drop-shadow(0 0 0 black) drop-shadow(0 0 0 black) + drop-shadow(0 0 0 black) drop-shadow(0 0 0 black) + drop-shadow(0 0 0 black) drop-shadow(0 0 0 black); + text-transform : uppercase; + font-weight : normal; + margin-top : 1.2cm; + margin-bottom : 0; + color : white; + font-family : NodestoCapsCondensed; + font-size : 2.245cm; + line-height : 0.85em; + } + h2 { + filter : drop-shadow(0 0 1px black) drop-shadow(0 0 0 black) + drop-shadow(0 0 0 black) drop-shadow(0 0 0 black) + drop-shadow(0 0 0 black) drop-shadow(0 0 0 black) + drop-shadow(0 0 0 black) drop-shadow(0 0 0 black); + font-family : NodestoCapsCondensed; + font-weight : normal; + font-size : 0.85cm; + letter-spacing : 0.1cm; + color : white; + } + hr { + display : block; + position : relative; + background-image : @horizontalRule; + background-size : 100% 100%; + visibility : visible; + height : 0.5cm; + width : 12cm; + border : none; + margin : auto; + filter : drop-shadow(0 0 3px black); + } + .banner { + filter : drop-shadow(2px 2px 2px black); + position : absolute; + left : 0; + bottom : 4.2cm; + background-image : url('/assets/coverPageBanner.svg'); + height : 1.7cm; + width : 10.5cm; + color : white; + font-family : NodestoCapsCondensed; + font-weight : normal; + font-size : 1cm; + letter-spacing : 0.014cm; + text-align : left; + padding-left : 1cm; + display : flex; + justify-content : center; + flex-direction : column; + padding-top : 0.1cm; + } + .footnote { + filter : drop-shadow(0 0 0.7px black) drop-shadow(0 0 0 black) + drop-shadow(0 0 0 black) drop-shadow(0 0 0 black) + drop-shadow(0 0 0 black) drop-shadow(0 0 0 black) + drop-shadow(0 0 0 black) drop-shadow(0 0 0 black); + position : absolute; + text-align : center; + color : white; + font-size : 0.496cm; + bottom : 1.3cm; + left : 0; + right : 0; + margin-left : auto; + margin-right : auto; + width : 70%; + font-family : Overpass; + } + .logo { + position : absolute; + top : 0.5cm; + left : 0; + right : 0; + filter : drop-shadow(0 0 0.075cm black); + img { + height : 2cm; + width : 100%; + } + } +} +//***************************** +// * INSIDE COVER PAGE +// *****************************/ +.page:has(.insideCover) { + columns : 1; + text-align : center; + &:after { + all : unset; + } + h1 { + font-family : NodestoCapsCondensed; + font-weight : normal; + font-size : 2.1cm; + margin-top : 1.2cm; + margin-bottom : 0; + text-transform : uppercase; + line-height : 0.85em; + } + h2 { + font-family : NodestoCapsCondensed; + font-weight : normal; + font-size : 0.85cm; + letter-spacing : 0.5cm; + } + hr { + display : block; + position : relative; + background-image : @horizontalRule; + background-size : 100% 100%; + visibility : visible; + height : 0.5cm; + width : 12cm; + border : none; + margin : auto; + } + .logo { + position : absolute; + bottom : 1cm; + left : 0; + right : 0; + height : 2cm; + img { + height : 2cm; + width : 100%; + } + } +} + +//***************************** // * PART COVER // *****************************/ .page:has(.partCover) { @@ -791,394 +879,160 @@ } } - - //***************************** - // * SPELL LIST - // *****************************/ - .page .spellList { - .useSansSerif(); - column-count: 2; - - ul+h5 { - margin-top: 15px; - } - - p, - ul { - font-size: 0.352cm; - line-height: 1.265em; - } - - ul { - margin-bottom: 0.5em; - padding-left: 1em; - text-indent: -1em; - list-style-type: none; - -webkit-column-break-inside: auto; - page-break-inside: auto; - break-inside: auto; - } - - &.wide { - column-count: 4; +//***************************** +// * TABLE OF CONTENTS +// *****************************/ +.page { +&:has(.toc):after { + display: none; +} +.toc { +-webkit-column-break-inside : avoid; +page-break-inside : avoid; +break-inside : avoid; + h1 { + text-align : center; + margin-bottom : 0.3cm; + } + a{ + display : inline; + color : inherit; + text-decoration : none; + &:hover{ + text-decoration : underline; } } + h4 { + margin-top : 0.2cm; + line-height : 0.4cm; + & + ul li { + line-height: 1.2em; + } + } + ul{ + padding-left : 0; + list-style-type : none; + margin-top : 0; + a { + width : 100%; + display : flex; + flex-flow : row nowrap; + justify-content : space-between; + } + li + li h3 { + margin-top : 0.26cm; + line-height : 1em + } + h3 span:first-child::after { + border : none; + } + span { + display : contents; + &:first-child::after { + content : ""; + bottom : 0.08cm; + flex : 1; + margin-left : 0.08cm; /* Spacing before dot leaders */ + margin-right : 0.16cm; + border-bottom : 0.05cm dotted #000; + margin-bottom : 0.08cm; + } + &:last-child { + display : inline-block; + align-self : flex-end; + font-family : "BookInsanityRemake"; + font-size : 0.34cm; + font-weight : normal; + color : #000; + } + } + ul { /*List indent*/ + margin-left : 1em; + } + } + &.wide{ + .useColumns(0.96, @fillMode: balance); + } +} +} - //***************************** - // * CLASS TABLE - // *****************************/ - .page .classTable { - th[colspan]:not([rowspan]) { - white-space: nowrap; +//***************************** +// * DEFINITION LISTS +// *****************************/ +.page { + dl { + line-height : 1.25em; + padding-left : 1em; + white-space : pre-line; + & + * { + margin-top : 0.28cm; + } + } + dl + * { + margin-top : 0.17cm; + } + p + dl { + margin-top: 0.17cm; + } + dt { + display : inline; + margin-right : 5px; + margin-left : -1em; + } + dd { + display : inline; + margin-left : 0px; + text-indent : 0px; + } +} + +//***************************** +// * WIDE +// *****************************/ +.page .wide{ + margin-bottom : 0.325cm; +} + +.page h1 + *{ + margin-top : 0; +} + +//***************************** +// * RUNE TABLE +// *****************************/ +.page { + .runeTable { + margin-block: 0.7cm; + table { + font-family : inherit; + tbody tr { + background: unset; + } + th, td { + width: 1.3cm; + height: 1.3cm; + vertical-align: middle; + text-transform: uppercase; + outline: 1px solid #000; + font-weight: normal; + } + th{ + font-family: BookInsanityRemake; + font-size: 0.45cm; + } + td { + font-size: 0.7cm; + } } &.frame { - margin-top: 0.7cm; - margin-bottom: 0.9cm; - margin-left: -0.1cm; - margin-right: -0.1cm; - width: calc(100% + 0.2cm); - border-collapse: separate; - background-color: white; border: initial; border-style: solid; - border-image-outset: 0.4cm 0.3cm; + border-image-outset: .45cm .35cm .4cm .4cm; border-image-repeat: stretch; - border-image-slice: 200; - border-image-source: @frameBorderImage; - border-image-width: 47px; - - &.wide:first-child { - margin-top: 0.12cm; - } - - &+* { - margin-top: 0; - } - } - - &.decoration { - position: relative; - } - - &.decoration::before { - content: ''; - position: absolute; - background-image: @classTableDecoration, - @classTableDecoration; - background-size: contain, contain; - background-repeat: no-repeat, no-repeat; - background-position: top, bottom; - width: 7.75cm; - height: calc(100% + 3.3cm); - top: 50%; - left: 50%; - transform: translateY(-50%) translateX(-50%); - filter: drop-shadow(0px 0px 1px #C8C5C080); - z-index: -1; - } - - &.decoration.wide::before { - width: calc(100% + 3.3cm); - height: 7.75cm; - background-position: left, right; - } - - h5+table { - margin-top: 0.2cm; + border-image-slice: 170; + border-image-source: @scriptBorder; + border-image-width: 1.4cm; } } - - //***************************** - // * COVER PAGE - // *****************************/ - .page:has(.coverPage) { - columns: 1; - text-align: center; - - &:after { - all: unset; - } - - .logo { - position: absolute; - top: 0.5cm; - left: 0; - right: 0; - filter: drop-shadow(0 0 0.075cm black); - - img { - height: 2cm; - width: 100%; - } - } - - .columnWrapper>p img { - position: absolute; - bottom: 0; - left: 0; - height: 100%; - min-width: 100%; - z-index: -1; - } - - h1 { - text-shadow: unset; - filter: drop-shadow(0 0 1.5px black) drop-shadow(0 0 0 black) drop-shadow(0 0 0 black) drop-shadow(0 0 0 black) drop-shadow(0 0 0 black) drop-shadow(0 0 0 black) drop-shadow(0 0 0 black) drop-shadow(0 0 0 black); - text-transform: uppercase; - font-weight: normal; - display: block; - margin-top: 1.2cm; - margin-bottom: 0; - color: white; - font-family: NodestoCapsCondensed; - font-size: 2.245cm; - line-height: 0.85em; - } - - h2 { - filter: drop-shadow(0 0 1px black) drop-shadow(0 0 0 black) drop-shadow(0 0 0 black) drop-shadow(0 0 0 black) drop-shadow(0 0 0 black) drop-shadow(0 0 0 black) drop-shadow(0 0 0 black) drop-shadow(0 0 0 black); - font-family: NodestoCapsCondensed; - font-weight: normal; - font-size: 0.85cm; - letter-spacing: 0.1cm; - color: white; - } - - hr { - display: block; - position: relative; - background-image: @horizontalRule; - background-size: 100% 100%; - visibility: visible; - height: 0.5cm; - width: 12cm; - border: none; - margin: auto; - filter: drop-shadow(0 0 3px black); - } - - .banner { - filter: drop-shadow(2px 2px 2px black); - position: absolute; - left: 0; - bottom: 4.2cm; - background-image: url('/assets/coverPageBanner.svg'); - height: 1.7cm; - width: 10.5cm; - color: white; - font-family: NodestoCapsCondensed; - font-weight: normal; - font-size: 1cm; - letter-spacing: 0.014cm; - text-align: left; - padding-left: 1cm; - display: flex; - justify-content: center; - flex-direction: column; - padding-top: 0.1cm; - } - - .footnote { - filter: drop-shadow(0 0 0.7px black) drop-shadow(0 0 0 black) drop-shadow(0 0 0 black) drop-shadow(0 0 0 black) drop-shadow(0 0 0 black) drop-shadow(0 0 0 black) drop-shadow(0 0 0 black) drop-shadow(0 0 0 black); - position: absolute; - text-align: center; - color: white; - font-size: 0.496cm; - bottom: 1.3cm; - left: 0; - right: 0; - margin-left: auto; - margin-right: auto; - width: 70%; - font-family: Overpass; - } - } - - - //***************************** - // * TABLE OF CONTENTS - // *****************************/ - .page { - &:has(.toc):after { - display: none; - } - - .toc { - -webkit-column-break-inside: avoid; - page-break-inside: avoid; - break-inside: avoid; - - h1 { - text-align: center; - margin-bottom: 0.3cm; - } - - a { - display: inline; - color: inherit; - text-decoration: none; - - &:hover { - text-decoration: underline; - } - } - - h4 { - margin-top: 0.2cm; - line-height: 0.4cm; - - &+ul li { - line-height: 1.2em; - } - } - - ul { - padding-left: 0; - list-style-type: none; - margin-top: 0; - - a { - width: 100%; - display: flex; - flex-flow: row nowrap; - justify-content: space-between; - } - - li+li h3 { - margin-top: 0.26cm; - line-height: 1em - } - - h3 span:first-child::after { - border: none; - } - - span { - display: contents; - - &:first-child::after { - content: ""; - bottom: 0.08cm; - flex: 1; - margin-left: 0.08cm; - /* Spacing before dot leaders */ - margin-right: 0.16cm; - border-bottom: 0.05cm dotted #000; - margin-bottom: 0.08cm; - } - - &:last-child { - display: inline-block; - align-self: flex-end; - font-family: "BookInsanityRemake"; - font-size: 0.34cm; - font-weight: normal; - color: #000; - } - } - - ul { - /*List indent*/ - margin-left: 1em; - } - } - - &.wide { - .useColumns(0.96, @fillMode: balance); - } - } - } - - //***************************** - // * DEFINITION LISTS - // *****************************/ - .page { - dl { - line-height: 1.25em; - padding-left: 1em; - white-space: pre-line; - - &+* { - margin-top: 0.28cm; - } - } - - dl+* { - margin-top: 0.17cm; - } - - p+dl { - margin-top: 0.17cm; - } - - dt { - display: inline; - margin-right: 5px; - margin-left: -1em; - } - - dd { - display: inline; - margin-left: 0px; - text-indent: 0px; - } - } - - //***************************** - // * WIDE - // *****************************/ - .page .wide { - margin-bottom: 0.325cm; - } - - .page h1+* { - margin-top: 0; - } - - //***************************** - // * RUNE TABLE - // *****************************/ - .page { - .runeTable { - margin-block: 0.7cm; - - table { - font-family: inherit; - - tbody tr { - background: unset; - } - - th, - td { - width: 1.3cm; - height: 1.3cm; - vertical-align: middle; - text-transform: uppercase; - outline: 1px solid #000; - font-weight: normal; - } - - th { - font-family: BookInsanityRemake; - font-size: 0.45cm; - } - - td { - font-size: 0.7cm; - } - } - - &.frame { - border: initial; - border-style: solid; - border-image-outset: .45cm .35cm .4cm .4cm; - border-image-repeat: stretch; - border-image-slice: 170; - border-image-source: @scriptBorder; - border-image-width: 1.4cm; - } - } - } -} \ No newline at end of file +} diff --git a/themes/V3/Blank/snippets/imageMask.gen.js b/themes/V3/Blank/snippets/imageMask.gen.js index 5ddef7a2a..323f89a1f 100644 --- a/themes/V3/Blank/snippets/imageMask.gen.js +++ b/themes/V3/Blank/snippets/imageMask.gen.js @@ -2,9 +2,9 @@ const _ = require('lodash'); const dedent = require('dedent-tabs').default; module.exports = { - center :()=>{ + center : ()=>{ return dedent` - {{imageMaskCenter${_.random(1, 16)},--offsetX:0%,--offsetY:0%,--rotation:0; + {{imageMaskCenter${_.random(1, 16)},--offsetX:0%,--offsetY:0%,--rotation:0 ![](https://i.imgur.com/GZfjDWV.png){height:100%} }}