diff --git a/.circleci/config.yml b/.circleci/config.yml index 666a9564a..8a756b3de 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -64,6 +64,12 @@ jobs: - run: name: Test - Mustache Spans command: npm run test:mustache-syntax + - run: + name: Test - Definition Lists + command: npm run test:definition-lists + - run: + name: Test - Variables + command: npm run test:variables - run: name: Test - Routes command: npm run test:route diff --git a/.github/actions/limit-pull-requests/action.yml b/.github/actions/limit-pull-requests/action.yml new file mode 100644 index 000000000..413fa0624 --- /dev/null +++ b/.github/actions/limit-pull-requests/action.yml @@ -0,0 +1,103 @@ +name: Limit pull requests +description: > + Limit the number of open pull requests to the repository created by a user +author: ZhongRuoyu (from Homebrew repository) +branding: + icon: alert-triangle + color: yellow + +inputs: + token: + description: GitHub token + required: false + default: ${{ github.token }} + except-users: + description: The users exempted from the limit, one per line + required: false + # https://docs.github.com/en/graphql/reference/enums#commentauthorassociation + except-author-associations: + description: The author associations exempted from the limit, one per line + required: false + comment-limit: + description: > + Post the comment when the user's number of open pull requests exceeds this + number and `comment` is not empty + required: true + default: "10" + comment: + description: The comment to post when the limit is reached + required: false + close-limit: + description: > + Close the pull request when the user's number of open pull requests + exceeds this number and `close` is set to `true` + required: true + default: "50" + close: + description: Whether to close the pull request when the limit is reached + required: true + default: "false" + +runs: + using: composite + steps: + - name: Check the number of pull requests + id: count-pull-requests + run: | + # If the user is exempted, assume they have no pull requests. + if grep -Fiqx '${{ github.actor }}' <<<"$EXCEPT_USERS"; then + echo "::notice::@${{ github.actor }} is exempted from the limit." + echo "count=0" >>"$GITHUB_OUTPUT" + exit 0 + fi + if grep -Fiqx '${{ github.event.pull_request.author_association }}' <<<"$EXCEPT_AUTHOR_ASSOCIATIONS"; then + echo "::notice::@{{ github.actor }} is a ${{ github.event.pull_request.author_association }} exempted from the limit." + echo "count=0" >>"$GITHUB_OUTPUT" + exit 0 + fi + + count="$( + gh api \ + --method GET \ + --header 'Accept: application/vnd.github+json' \ + --header 'X-GitHub-Api-Version: 2022-11-28' \ + --field state=open \ + --paginate \ + '/repos/{owner}/{repo}/pulls' | + jq \ + --raw-output \ + --arg USER '${{ github.actor }}' \ + 'map(select(.user.login == $USER)) | length' + )" + echo "::notice::@${{ github.actor }} has $count open pull request(s)." + echo "count=$count" >>"$GITHUB_OUTPUT" + env: + GH_REPO: ${{ github.repository }} + GH_TOKEN: ${{ inputs.token }} + EXCEPT_USERS: ${{ inputs.except-users }} + EXCEPT_AUTHOR_ASSOCIATIONS: ${{ inputs.except-author-associations }} + shell: bash + + - name: Comment on pull request + if: > + fromJSON(steps.count-pull-requests.outputs.count) > fromJSON(inputs.comment-limit) && + inputs.comment != '' + run: | + gh pr comment '${{ github.event.pull_request.number }}' \ + --body="${COMMENT_BODY}" + env: + GH_REPO: ${{ github.repository }} + GH_TOKEN: ${{ inputs.token }} + COMMENT_BODY: ${{ inputs.comment }} + shell: bash + + - name: Close pull request + if: > + fromJSON(steps.count-pull-requests.outputs.count) > fromJSON(inputs.close-limit) && + inputs.close == 'true' + run: | + gh pr close '${{ github.event.pull_request.number }}' + env: + GH_REPO: ${{ github.repository }} + GH_TOKEN: ${{ inputs.token }} + shell: bash diff --git a/.github/workflows/pr-check.yml b/.github/workflows/pr-check.yml new file mode 100644 index 000000000..e5adb2561 --- /dev/null +++ b/.github/workflows/pr-check.yml @@ -0,0 +1,29 @@ +name: PR Check +on: pull_request_target +env: + GH_REPO: ${{ github.repository }} + GH_NO_UPDATE_NOTIFIER: 1 + GH_PROMPT_DISABLED: 1 +permissions: + contents: read + issues: write + pull-requests: write + statuses: write +jobs: + limit-pull-requests: + if: always() && github.repository_owner == 'naturalcrit' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name : Run limit-pull-requests action + uses: ./.github/actions/limit-pull-requests + with: + except-users: | + dependabot + comment-limit: 3 + comment: | + Hi, thanks for your contribution to the Homebrewery! You already have >=3 open pull requests. Consider completing some of your existing PRs before opening new ones. Thanks! + close-limit: 5 + close: false diff --git a/Dockerfile b/Dockerfile index 82b13ac86..84652fbf9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:18-alpine +FROM node:20-alpine RUN apk --no-cache add git ENV NODE_ENV=docker diff --git a/changelog.md b/changelog.md index e86c2ea0f..0cdb89c29 100644 --- a/changelog.md +++ b/changelog.md @@ -84,7 +84,145 @@ pre { ## changelog For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery). -### Wednesday 21/2/2024 - v3.11.0 +### Monday 7/29/2024 - v3.14.0 +{{taskList + +##### abquintic, calculuschild + +* [x] Alternative Brew Themes, including importing other brews as a base theme. + +- In the :fas_circle_info: **Properties** menu, find the new {{openSans **THEME**}} dropdown. It lists Brew Themes, including a new **Blank** theme as a simpler basis for custom styling. +- Brews tagged with `meta:theme` will appear in the Brew Themes list. Selecting one loads its :fas_paintbrush: **Style** tab contents as the CSS basis for the current brew, allowing one brew to style multiple documents. +- Brews with `meta:theme` can also select their own Theme, i.e. layering Themes on top of each other. +- The next goal is to make **Published** Themes shareable between users. + + +Fixes issues [#1899](https://github.com/naturalcrit/homebrewery/issues/1899), [#3085](https://github.com/naturalcrit/homebrewery/issues/3085) + +##### G-Ambatte + +* [x] Fix Drop-cap font becoming corrupted when Bold + +Fixes issues [#3551](https://github.com/naturalcrit/homebrewery/issues/3551) + +* [x] Fixes to UI styling + +Fixes issues [#3568](https://github.com/naturalcrit/homebrewery/issues/3568) + +}} + + +### Saturday 6/7/2024 - v3.13.1 +{{taskList + +##### calculuschild, G-Ambatte + +* [x] Hotfixes for issues with v3.13.0 + +Fixes issues [#3559](https://github.com/naturalcrit/homebrewery/issues/3559), [#3552](https://github.com/naturalcrit/homebrewery/issues/3552), [#3554](https://github.com/naturalcrit/homebrewery/issues/3554) +}} + +### Friday 28/6/2024 - v3.13.0 +{{taskList + +##### calculuschild + +* [x] Add `:emoji:` Markdown syntax, with autosuggest; start typing after the first `:` for matching emojis from +:fab_font_awesome: FontAwesome, :df_d20: DiceFont, :ei_action: ElderberryInn, and a subset of :gi_broadsword: GameIcons + +* [x] Fix `{curly injection}` to append to, rather than erase and replace target CSS +* [x] {{openSans **GET PDF**}} {{fa,fa-file-pdf}} now opens the print dialog directly, rather than redirecting to a separate page + +##### Gazook + +* [x] Several small style tweaks to the UI +* [x] Cleaning and refactoring several large pieces of code + +##### 5e-Cleric + +* [x] For error pages, add links to user account and `/share` page if available + +Fixes issue [#3298](https://github.com/naturalcrit/homebrewery/issues/3298) + +* [x] Change FrontCover title to use stroke outline instead of faking it with dozens of shadows +* [x] Cleaning and refactoring several large pieces of CSS + +##### abquintic + +* [x] Added additional {{openSans **TABLE OF CONTENTS**}} snippet options. Explicitly include or exclude items from the ToC generation via CSS properties +`--TOC:exclude` or `--TOC:include`, or change the included header depth from 3 to 6 (default 3) with `tocDepthH6` + +##### MurdoMaclachlan *(new contributor!)* + +* [x] Added "proficiency bonus" to Monster Stat Block snippet. + +Fixes issue [#3397](https://github.com/naturalcrit/homebrewery/issues/3397) +}} + +### Monday 18/3/2024 - v3.12.0 +{{taskList + +##### 5e-Cleric + +* [x] Fix language-specific hyphenation on print page + +Fixes issue [#3294](https://github.com/naturalcrit/homebrewery/issues/3294) + +* [x] Upgrade Font-Awesome to v6.51 + +* [x] Allow downloaded files to be uploaded via {{openSans **NEW {{fa,fa-plus-square}} → FROM UPLOAD {{fa,fa-upload}}**}} + +##### G-Ambatte + +* [x] Fix an edge case crash with empty documents + +Fixes issue [#3315](https://github.com/naturalcrit/homebrewery/issues/3315) + +* [x] Brews on the user page can be searched by tag; clicking a tag adds it to the filter + +Fixes issue [#3164](https://github.com/naturalcrit/homebrewery/issues/3164) + +* [x] Add *DiceFont* icons {{df,d20-20}} `{{df,icon-name}}` + +##### abquintic + +* [x] Fix ^super^ and ^^sub^^ highlighting in the text editor + +* [x] Add new syntax for multiline Definition Lists: + + +``` +Term +::Definition 1 +::Definition 2 +with more text +``` + +produces: + +Term +::Definition 1 +::Definition 2 +with more text + +Fixes issue [#2340](https://github.com/naturalcrit/homebrewery/issues/2340) + +##### RKuerten : +* [x] Fix monster stat block backgrounds on print page + +Fixes issue [#3275](https://github.com/naturalcrit/homebrewery/issues/3275) + +* [x] Added new text editor theme: "Darkvision". + +##### calculuschild, G-Ambatte, 5e-Cleric + +* [x] Codebase and UI cleanup +}} + +\page + + +### Friday 21/2/2024 - v3.11.0 {{taskList ##### Gazook89 @@ -166,14 +304,16 @@ Fixes issue [1488](https://github.com/naturalcrit/homebrewery/issues/1488) Fixes issues [2510](https://github.com/naturalcrit/homebrewery/issues/2510), [2975](https://github.com/naturalcrit/homebrewery/issues/2975) -* [x] New Variables syntax. See below for details. +* [x] Brew Variables }} +\ + {{wide ### Brew Variable Syntax -You may already be familiar with `[link](url)` and `![image](url)` syntax. We have expanded this to include a third `$[variable](text)` syntax. All three of these syntaxes now share a common set of features: +You may already be familiar with `[link](url)` and `![image](url)` synax. We have expanded this to include a third `$[variable](text)` syntax. All three of these syntaxes now share a common set of features: {{varSyntaxTable | syntax | description | @@ -1512,7 +1652,7 @@ myStyle {color: black} ### Sunday, 29/05/2016 - v2.1.0 - Finally added a syntax for doing spell lists. A bit in-depth about why this took so long. Essentially I'm running out of syntax to use in stardard Markdown. There are too many unique elements in the PHB-style to be mapped. I solved this earlier by stacking certain elements together (eg. an `
` before a `blockquote` turns it into moster state block), but those are getting unweildly. I would like to simply wrap these in `div`s with classes, but unfortunately Markdown stops processing when within HTML blocks. To get around this I wrote my own override to the Markdown parser and lexer to process Markdown within a simple div class wrapper. This should open the door for more unique syntaxes in the future. Big step! - Override Ctrl+P (and cmd+P) to launch to the print page. Many people try to just print either the editing or share page to get a PDF. While this dones;t make much sense, I do get a ton of issues about it. So now if you try to do this, it'll just bring you imediately to the print page. Everybody wins! -- The onboarding flow has also been confusing a few users (Homepage -> new -> save -> edit page). If you edit the Homepage text now, a Call to Action to save your work will pop-up. +- The onboarding flow has also been confusing a few users (Homepage → new → save → edit page). If you edit the Homepage text now, a Call to Action to save your work will pop-up. - Added a 'Recently Edited' and 'Recently Viewed' nav item to the edit and share page respectively. Each will remember the last 8 items you edited or viewed and when you viewed it. Makes use of the new title attribute of brews to easy navigatation. - Paragraphs now indent properly after lists (thanks u/slitjen!) diff --git a/client/admin/brewCleanup/brewCleanup.jsx b/client/admin/brewCleanup/brewCleanup.jsx index b55a70bef..a166ae112 100644 --- a/client/admin/brewCleanup/brewCleanup.jsx +++ b/client/admin/brewCleanup/brewCleanup.jsx @@ -1,7 +1,6 @@ require('./brewCleanup.less'); const React = require('react'); const createClass = require('create-react-class'); -const cx = require('classnames'); const request = require('superagent'); diff --git a/client/admin/brewCompress/brewCompress.jsx b/client/admin/brewCompress/brewCompress.jsx index c12f430a2..2c8e5b023 100644 --- a/client/admin/brewCompress/brewCompress.jsx +++ b/client/admin/brewCompress/brewCompress.jsx @@ -1,7 +1,6 @@ require('./brewCompress.less'); const React = require('react'); const createClass = require('create-react-class'); -const cx = require('classnames'); const request = require('superagent'); diff --git a/client/components/combobox.jsx b/client/components/combobox.jsx index a6e699dcf..5fcc154bc 100644 --- a/client/components/combobox.jsx +++ b/client/components/combobox.jsx @@ -1,7 +1,6 @@ const React = require('react'); const createClass = require('create-react-class'); const _ = require('lodash'); -const cx = require('classnames'); require('./combobox.less'); const Combobox = createClass({ diff --git a/client/components/dialog.jsx b/client/components/dialog.jsx new file mode 100644 index 000000000..2057ecb87 --- /dev/null +++ b/client/components/dialog.jsx @@ -0,0 +1,29 @@ +// Dialog box, for popups and modal blocking messages +const React = require('react'); +const { useRef, useEffect } = React; + +function Dialog({ dismissKey, closeText = 'Close', blocking = false, ...rest }) { + const dialogRef = useRef(null); + + useEffect(()=>{ + if(!dismissKey || !localStorage.getItem(dismissKey)) { + blocking ? dialogRef.current?.showModal() : dialogRef.current?.show(); + } + }, []); + + const dismiss = ()=>{ + dismissKey && localStorage.setItem(dismissKey, true); + dialogRef.current?.close(); + }; + + return ( + + {rest.children} + + + ); +}; + +export default Dialog; diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index f1c9cdeda..4b82c6bc0 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -13,16 +13,18 @@ const RenderWarnings = require('homebrewery/renderWarnings/renderWarnings.jsx'); const NotificationPopup = require('./notificationPopup/notificationPopup.jsx'); const Frame = require('react-frame-component').default; const dedent = require('dedent-tabs').default; +const { printCurrentBrew } = require('../../../shared/helpers.js'); -const Themes = require('themes/themes.json'); +const DOMPurify = require('dompurify'); +const purifyConfig = { FORCE_BODY: true, SANITIZE_DOM: false }; const PAGE_HEIGHT = 1056; const INITIAL_CONTENT = dedent` - + - +
`; @@ -33,8 +35,9 @@ const BrewPage = (props)=>{ index : 0, ...props }; + const cleanText = props.contents; //DOMPurify.sanitize(props.contents, purifyConfig); return
-
+
; }; @@ -52,6 +55,7 @@ const BrewRenderer = (props)=>{ lang : '', errors : [], currentEditorPage : 0, + themeBundle : {}, ...props }; @@ -102,13 +106,6 @@ const BrewRenderer = (props)=>{ return false; }; - const sanitizeScriptTags = (content)=>{ - return content - ?.replace(/