diff --git a/.circleci/config.yml b/.circleci/config.yml index 274ec25ac..fb239ceb3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,7 +10,7 @@ orbs: jobs: build: docker: - - image: cimg/node:20.8.0 + - image: cimg/node:20.18.0 - image: mongo:4.4 working_directory: ~/homebrewery @@ -27,7 +27,7 @@ jobs: # fallback to using the latest cache if no exact match is found - v1-dependencies- - - run: sudo npm install -g npm@10.2.0 + - run: sudo npm install -g npm@10.8.2 - node/install-packages: app-dir: ~/homebrewery cache-path: node_modules @@ -45,7 +45,7 @@ jobs: test: docker: - - image: cimg/node:20.8.0 + - image: cimg/node:20.17.0 working_directory: ~/homebrewery parallelism: 1 @@ -64,21 +64,30 @@ 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 - Hard Breaks command: npm run test:hard-breaks + - run: + name: Test - Non-Breaking Spaces + command: npm run test:non-breaking-spaces - run: name: Test - Variables command: npm run test:variables + - run: + name: Test - Emojis + command: npm run test:emojis - run: name: Test - Routes command: npm run test:route + - run: + name: Test - HTML sanitization + command: npm run test:safehtml - run: name: Test - Coverage command: npm run test:coverage + - run: + name: Test - Content Negotiation + command: npm run test:content-negotiation workflows: build_and_test: diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 208b0275b..2204679a6 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,6 +5,15 @@ updates: schedule: interval: daily open-pull-requests-limit: 99 + groups: + dev-dependencies: + dependency-type: "development" + patterns: ["*"] + update-types: ["patch", "minor"] + prod-dependencies: + dependency-type: "production" + patterns: ["*"] + update-types: ["patch", "minor"] ignore: - dependency-name: eslint versions: diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index b02835726..020653272 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,26 +1,29 @@ - +> [!TIP] +> Before submitting a Pull Request, please consider the following to speed up reviews: +> - 👷‍♀️ Create small PRs. Large PRs can usually be broken down into incremental PRs. +> - 🚩 Do you already have several open PRs? Consider finishing or asking for help with existing PRs first. +> - 🔧 Does your PR reference a discussed and approved issue, especially for personal or edge-case requests? +> - 💡 Is the solution agreed upon? Save rework time by discussing strategy before coding. ## Description +_Describe what your PR accomplishes. Consider walking through the main changes to aid reviewers in following your code, especially if it covers multiple files._ ## Related Issues or Discussions +> [!CAUTION] +> If no issue exists yet, create it, and get agreement on the approach (or paste in a previous agreement from chat, etc.) before moving forward. (Experimental PRs are OK without prior discussion, but do not expect to get merged.) + - Closes # ## QA Instructions, Screenshots, Recordings -_Please replace this line with instructions on how to test or view your changes, as well as any before/after -images for UI changes._ +_Replace this line with instructions on how to test or view your changes, as well as any before/after +screenshots or recordings for UI changes._ ### Reviewer Checklist -_Please replace the list below with specific features you want reviewers to look at._ +_Replace the list below with specific features you want reviewers to look at._ *Reviewers, refer to this list when testing features, or suggest new items * - [ ] Verify new features are functional @@ -32,5 +35,3 @@ _Please replace the list below with specific features you want reviewers to look - [ ] Feature A handles negative numbers - [ ] Identify opportunities for simplification and refactoring - [ ] Check for code legibility and appropriate comments - -
Copy this list diff --git a/.stylelintrc.json b/.stylelintrc.json index 2c7a9afdf..b5f2e7712 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -1,48 +1,48 @@ { - "extends": [ - "stylelint-config-recess-order", - "stylelint-config-recommended"], - "plugins": [ - "@stylistic/stylelint-plugin", - "./stylelint_plugins/declaration-colon-align.js", - "./stylelint_plugins/declaration-colon-min-space-before", - "./stylelint_plugins/declaration-block-multi-line-min-declarations" - ], - "customSyntax": "postcss-less", - "rules": { - "no-descending-specificity" : null, - "at-rule-no-unknown" : null, - "function-no-unknown" : null, - "font-family-no-missing-generic-family-keyword" : null, - "font-weight-notation" : "named-where-possible", - "font-family-name-quotes" : "always-unless-keyword", - "@stylistic/indentation" : "tab", - "no-duplicate-selectors" : true, - "@stylistic/color-hex-case" : "upper", - "color-hex-length" : "long", - "@stylistic/selector-combinator-space-after" : "always", - "@stylistic/selector-combinator-space-before" : "always", - "@stylistic/selector-attribute-operator-space-before" : "never", - "@stylistic/selector-attribute-operator-space-after" : "never", - "@stylistic/selector-attribute-brackets-space-inside" : "never", - "selector-attribute-quotes" : "always", - "selector-pseudo-element-colon-notation" : "double", - "@stylistic/selector-pseudo-class-parentheses-space-inside" : "never", - "@stylistic/block-opening-brace-space-before" : "always", - "naturalcrit/declaration-colon-min-space-before" : 1, - "@stylistic/declaration-block-trailing-semicolon" : "always", - "@stylistic/declaration-colon-space-after" : "always", - "@stylistic/number-leading-zero" : "always", - "function-url-quotes" : ["always", { "except": ["empty"] }], - "function-url-scheme-disallowed-list" : ["data","http"], - "comment-whitespace-inside" : "always", - "@stylistic/string-quotes" : "single", - "@stylistic/media-feature-range-operator-space-before" : "always", - "@stylistic/media-feature-range-operator-space-after" : "always", - "@stylistic/media-feature-parentheses-space-inside" : "never", - "@stylistic/media-feature-colon-space-before" : "always", - "@stylistic/media-feature-colon-space-after" : "always", - "naturalcrit/declaration-colon-align" : true, - "naturalcrit/declaration-block-multi-line-min-declarations": 1 - } + "extends": [ + "stylelint-config-recess-order", + "stylelint-config-recommended"], + "plugins": [ + "@stylistic/stylelint-plugin", + "./stylelint_plugins/declaration-colon-align.js", + "./stylelint_plugins/declaration-colon-min-space-before", + "./stylelint_plugins/declaration-block-multi-line-min-declarations" + ], + "customSyntax": "postcss-less", + "rules": { + "no-descending-specificity" : null, + "at-rule-no-unknown" : null, + "function-no-unknown" : null, + "font-family-no-missing-generic-family-keyword" : null, + "font-weight-notation" : "named-where-possible", + "font-family-name-quotes" : "always-unless-keyword", + "@stylistic/indentation" : "tab", + "no-duplicate-selectors" : true, + "@stylistic/color-hex-case" : "upper", + "color-hex-length" : "long", + "@stylistic/selector-combinator-space-after" : "always", + "@stylistic/selector-combinator-space-before" : "always", + "@stylistic/selector-attribute-operator-space-before" : "never", + "@stylistic/selector-attribute-operator-space-after" : "never", + "@stylistic/selector-attribute-brackets-space-inside" : "never", + "selector-attribute-quotes" : "always", + "selector-pseudo-element-colon-notation" : "double", + "@stylistic/selector-pseudo-class-parentheses-space-inside" : "never", + "@stylistic/block-opening-brace-space-before" : "always", + "naturalcrit/declaration-colon-min-space-before" : 1, + "@stylistic/declaration-block-trailing-semicolon" : "always", + "@stylistic/declaration-colon-space-after" : "always", + "@stylistic/number-leading-zero" : "always", + "function-url-quotes" : ["always", { "except": ["empty"] }], + "function-url-scheme-disallowed-list" : ["data","http"], + "comment-whitespace-inside" : "always", + "@stylistic/string-quotes" : "single", + "@stylistic/media-feature-range-operator-space-before" : "always", + "@stylistic/media-feature-range-operator-space-after" : "always", + "@stylistic/media-feature-parentheses-space-inside" : "never", + "@stylistic/media-feature-colon-space-before" : "always", + "@stylistic/media-feature-colon-space-after" : "always", + "naturalcrit/declaration-colon-align" : true, + "naturalcrit/declaration-block-multi-line-min-declarations" : 1 + } } diff --git a/Dockerfile b/Dockerfile index 84652fbf9..17d02b01f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:20-alpine +FROM node:22-alpine RUN apk --no-cache add git ENV NODE_ENV=docker @@ -9,7 +9,10 @@ WORKDIR /usr/src/app # Copy package.json into the image, then run yarn install # This improves caching so we don't have to download the dependencies every time the code changes COPY package.json ./ +COPY config/docker.json usr/src/app/config # --ignore-scripts tells yarn not to run postbuild. We run it explicitly later +RUN node --version +RUN npm --version RUN npm install --ignore-scripts # Bundle app source and build application diff --git a/README.DOCKER.md b/README.DOCKER.md index 356ac398a..dba2e2257 100644 --- a/README.DOCKER.md +++ b/README.DOCKER.md @@ -1,12 +1,130 @@ -# Running Homebrewery via Docker +# Offline Install Instructions: Docker -The repo includes a Dockerfile and a docker-compose.yml file. +These instructions are for setting up a persistent instance of the Homebrewery application locally using Docker. -To run the application via docker-compose.yml: -`docker-compose up -d` +If you intend to develop with Homebrewery, following the Homebrewery application section of this guide is not recommended. Using docker to deploy MongoDB locally for development is not a bad idea at all, however. -To stop the application: -`docker-compose down` +# Install Docker + +## Docker Desktop (MacOS/Windows) + +Windows and Mac installs use Docker Desktop. Current install instructions are below. + +* [Mac](https://docs.docker.com/desktop/mac/install/) +* [Windows](https://docs.docker.com/desktop/windows/install/) + +You can set up the docker engine to start on boot via the Docker desktop UI. + +## Docker Engine + +Linux installs use Docker Engine. Docker provides installers and instructions for several of the most common distrubutions. If you do not see yours listed, it is very likely supported indirectly by your distribution. + +* [Arch](https://docs.docker.com/desktop/setup/install/linux/archlinux/) +* [CentOS](https://docs.docker.com/engine/install/centos/) +* [Debian](https://docs.docker.com/engine/install/debian/) +* [Fedora](https://docs.docker.com/engine/install/fedora/) +* [RHEL](https://docs.docker.com/engine/install/rhel/) +* [Ubuntu](https://docs.docker.com/engine/install/ubuntu/) + +### Post installation steps +[Manage Docker as a non-root user (highly recommended)](https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user) +[Enable Docker to start on boot (highly recommended)](https://docs.docker.com/engine/install/linux-postinstall/#configure-docker-to-start-on-boot) + +# Build Homebrewery Image + +Next we build the homebrewery docker image. Start by cloning the repository. + +```shell +git clone https://github.com/naturalcrit/homebrewery.git +cd homebrewery +``` + +Make an changes you need to `config/docker.json` then build the image. If it does not exist,the below as a template. + +``` +{ +"host" : "localhost:8000", +"naturalcrit_url" : "local.naturalcrit.com:8010", +"secret" : "secret", +"web_port" : 8000, +"mongodb_uri": "mongodb://172.17.0.2/homebrewery", +} +``` + +```shell +docker-compose build homebrewery +``` + +# Add Mongo container + +Once docker is installed and running, it is time to set up the containers. First up, Mongo. + +```shell +docker run --name homebrewery-mongodb -d --restart unless-stopped -v mongodata:/data/db -p 27017:27017 mongo:latest +``` + +Older CPUs may run into an issue with AVX support. +``` +WARNING: MongoDB 5.0+ requires a CPU with AVX support, and your current system does not appear to have that! + see https://jira.mongodb.org/browse/SERVER-54407 + see also https://www.mongodb.com/community/forums/t/mongodb-5-0-cpu-intel-g4650-compatibility/116610/2 + see also https://github.com/docker-library/mongo/issues/485#issuecomment-891991814 +``` +If you see a message similar to this, try using the bitnami mongo instead. + +```shell +docker run --name homebrewery-mongodb -d --restart unless-stopped -v mongodata:/data/db -p 27017:27017 bitnami/mongo:latest +``` + +If your distribution is running on an arm device such as a Raspberry Pi, you will need to run the arm-built MongoDB v4.4. + +```shell +docker run --name homebrewery-mongodb -d --restart unless-stopped -v mongodata:/data/db -p 27017:27017 arm64v8/mongo:4.4 +``` + +## Run the Homebrewery Image +```shell +# Make sure you run this in the homebrewery directory +docker run --name homebrewery-app -d --restart unless-stopped -e NODE_ENV=docker -v $(pwd)/config/docker.json:/usr/src/app/config/docker.json -p 8000:8000 docker.io/library/homebrewery:latest +``` + +**NOTE:** If you are running from the Windows command line, this will not work as `$(pwd)` is not valid syntax. Use this command instead: +```shell +# Make sure you run this in the homebrewery directory +docker run --name homebrewery-app -d --restart unless-stopped -e NODE_ENV=docker -v %cd%/config/docker.json:/usr/src/app/config/docker.json -p 8000:8000 docker.io/library/homebrewery:latest +``` + + +## Updating the Image + +When Homebrewery code updates, your docker container will not automatically follow the changes. To do so you will need to rebuild your homebrewery image. + +First, return to your homebrewery clone (from Build Homebrewery Image above) or recreate the clone if you deleted your copy of the code. + +First, delete the existing image. + +```shell +docker rm -f homebrewery-app +``` + +Next, update the clone's code to the latest version. + +```shell +cd homebrewery +git checkout master +git pull upstream master +``` + +Finally, rebuild and restart the homebrewery image. + +```shell +docker-compose build homebrewery +docker run --name homebrewery-app -d --restart unless-stopped -e NODE_ENV=docker -v $(pwd)/config/docker.json:/usr/src/app/config/docker.json -p 8000:8000 docker.io/library/homebrewery:latest +``` + +**NOTE:** If you are running from the Windows command line, this will not work as `$(pwd)` is not valid syntax. Use this command instead: +```shell +# Make sure you run this in the homebrewery directory +docker run --name homebrewery-app -d --restart unless-stopped -e NODE_ENV=docker -v %cd%/config/docker.json:/usr/src/app/config/docker.json -p 8000:8000 docker.io/library/homebrewery:latest +``` -To stop the application and remove all data: -`docker-compose down -v` diff --git a/README.md b/README.md index df7f41503..a33f2f073 100644 --- a/README.md +++ b/README.md @@ -75,8 +75,9 @@ it using the two commands: 1. `npm install` 1. `npm start` -You should now be able to go to [http://localhost:8000](http://localhost:8000) -in your browser and use The Homebrewery offline. +When the Homebrewery server is started for the first time, it will modify the database to create the indexes required for better Homebrewery performance. This may take a few moments to complete for each index, dependent on how much content is in your local database - a brand new, empty database should be done in seconds. + +On completion, you should be able to go to [http://localhost:8000](http://localhost:8000) in your browser and use The Homebrewery offline. If you had any issue at all, here are some links that may be useful: - [Course](https://learn.mongodb.com/courses/m103-basic-cluster-administration) on cluster administration, useful for beginners @@ -144,3 +145,5 @@ your contribution to the project, please join our [gitter chat][gitter-url]. [github-mark-duplicate-url]: https://docs.github.com/en/free-pro-team@latest/github/managing-your-work-on-github/about-duplicate-issues-and-pull-requests [github-pr-docs-url]: https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request [gitter-url]: https://gitter.im/naturalcrit/Lobby + + diff --git a/babel.config.json b/babel.config.json new file mode 100644 index 000000000..5e768ec31 --- /dev/null +++ b/babel.config.json @@ -0,0 +1,10 @@ +{ + "presets": [ + "@babel/preset-env", + "@babel/preset-react" + ], + "plugins": [ + "@babel/plugin-transform-runtime", + "babel-plugin-transform-import-meta" + ] +} diff --git a/changelog.md b/changelog.md index 9d1ddf32d..1e1ac70e2 100644 --- a/changelog.md +++ b/changelog.md @@ -1,1934 +1,2361 @@ -```css -.beta { - color : white; - padding : 4px 6px; - line-height : 1em; - background : grey; - border-radius : 12px; - font-family : monospace; - font-size : 10px; - font-weight : 800; - margin-top : -5px; - margin-bottom : -5px; -} - -.fac { - height: 1em; - line-height: 2em; - margin-bottom: -0.05cm -} - -h5 { - font-size: .35cm !important; -} - -.page ul ul { - margin-left: 0px; -} - -.page .taskList { - display:block; - break-inside:auto; -} - -.taskList li input { - list-style-type : none; - margin-left : -0.52cm; - transform: translateY(.05cm); - filter: brightness(1.1) drop-shadow(1px 2px 1px #222); -} - -.taskList ul { - margin-bottom: 0px; - margin-top: 0px; -} - -.taskList li input[checked] { - filter: sepia(100%) hue-rotate(60deg) saturate(3.5) contrast(4) brightness(1.1) drop-shadow(1px 2px 1px #222); -} - -pre + * { - margin-top: 0.17cm; -} - -pre { - margin-top: 0.17cm; -} - -.page p + pre { - margin-top : 0.1cm; -} - -.page ul + h5 { - margin-top: 0.25cm; -} - -.page p + h5 { - margin-top: 0.25cm; -} - -.page .openSans { - font-family: 'Open Sans'; - font-size: 0.9em; -} - -.page { - padding-bottom: 1.5cm; -} - -.varSyntaxTable th:first-of-type { - width:6cm; -} -``` - -## changelog -For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery). - -### Wednesday 9/04/2024 - v3.15.0 - -{{taskList -##### 5e-Cleric, abquintic, calculuschild, Gazook89, G-Ambatte, Ericsheid, Kaiburr - -* [x] New {{openSans **VAULT** {{fas,fa-dungeon}}}} page 🎉🎉🎉 -: -All **PUBLISHED** brews ({{openSans :fas_circle_info: **Properties**}} menu) will be searchable, by title or author, and filtered by renderer. More features and adjustments will be coming. -: -Note: If any of your own brews are not showing up in search (particularly if stored on Google Drive), please edit and re-save to ensure our database has the data needed from document to be searchable. - -Fixes issue [#697](https://github.com/naturalcrit/homebrewery/issues/697) - -##### Gazook89 - -* [x] Auto-focus on text editor when switching editor tabs -}} - -### Wednesday 8/28/2024 - v3.14.3 - -{{taskList -##### calculuschild, G-Ambatte - -* [x] New {{openSans **IMAGES → {{fac,image-wrap-left}} IMAGE WRAP LEFT/RIGHT**}} snippets - -Fixes issue [#380](https://github.com/naturalcrit/homebrewery/issues/380) - -* [x] Fix v3.14.2 bug with `꞉꞉꞉꞉` failing after tables - -##### 5e-Cleric - -* [x] Fix Account page crash when not logged in - -Fixes issue [#3605](https://github.com/naturalcrit/homebrewery/issues/3605) - -##### abquintic - -* [x] Fix jump hotkeys conflicting with `CTRL + SHIFT`. Preview and Source movement shortcuts now use `CTRL + SHIFT + META + LEFT\RIGHTARROW` - -##### G-Ambatte - -* [x] Fix display issue with image wrap icons -}} - - -### Tuesday 8/27/2024 - v3.14.2 - -{{taskList -##### calculuschild - -* [x] Reroute invalid urls to homepage - -Fixes issues [#3269](https://github.com/naturalcrit/homebrewery/issues/3629) - -* [x] Background dependency updates - -##### G-Ambatte - -* [x] Add route to get brew styling via `/css/shareId` - -Fixes issues [#1097](https://github.com/naturalcrit/homebrewery/issues/1097) - -* [x] Fix `:emojis:` preventing code folding - -Fixes issues [#3604](https://github.com/naturalcrit/homebrewery/issues/3604) - -* [x] Fix mask image warping when rotated and stretched - -Fixes issues [#3636](https://github.com/naturalcrit/homebrewery/issues/3636) - -* [x] Fix Table of Contents uppercasing - -Fixes issues [#3572](https://github.com/naturalcrit/homebrewery/issues/3572) - -##### abquintic - -* [x] Create globally unique Header IDs across pages - -Fixes issues [#1430](https://github.com/naturalcrit/homebrewery/issues/1430) - -* [x] Fix colon `꞉꞉꞉꞉` being parsed in codeblocks - -* [x] Prevent crashes when loading undefined renderer or theme bundle - -* [x] Add Jump-To hotkeys - - * Use `CTRL/META + SHIFT + LEFTARROW` to brewJump - * Use `CTRL/META + SHIFT + RIGHTARROW` to sourceJump - -* [x] Prevent reload from clobbering modified fresh clones - -##### 5e-Cleric, Gazook89 - -* [x] Viewer tools for zoom/page navigation -}} - -### Tuesday 8/13/2024 - v3.14.1 - -{{taskList -##### abquintic - -* [x] Allow Table of Contents to flow across columns - -Fixes issues [#2563](https://github.com/naturalcrit/homebrewery/issues/2563) - -* [x] Fix unusual margin spacing for adjacent `.descriptive` and `.wide` blocks - -Fixes issues [#2688](https://github.com/naturalcrit/homebrewery/issues/2688) - -* [x] Add code folding to :fas_paintbrush: {{openSans **STYLE**}} tab - -##### G-Ambatte - -* [x] Fix edge case where Table of Contents generator changed capitalization of headings - -Fixes issues [#3572](https://github.com/naturalcrit/homebrewery/issues/3572) - -* [x] Fix **Ink Friendly** snippet causing unselectable PDF text - -Fixes issues [#3563](https://github.com/naturalcrit/homebrewery/issues/3563) - -* [x] Prevent brews selecting themselves as a theme - -Fixes issues [#3614](https://github.com/naturalcrit/homebrewery/issues/3614) - -* [x] Fix info pages (`/faq`, `/migrate`, etc.) showing blank authorship info - -Fixes issues [#3568](https://github.com/naturalcrit/homebrewery/issues/3568) - -* [x] Add `abs()`, `sign()` and `signed()` functions to variable syntax math handler - -Fixes issues [#3537](https://github.com/naturalcrit/homebrewery/issues/3537) - -* [x] Fix variable math handler not processing commas (i.e., in `$[max(varA,varB)]` - -Fixes issues [#3613](https://github.com/naturalcrit/homebrewery/issues/3613) - -* [x] Fix variable math handler scrambling variables with names that are subsets of other variables - -Fixes issues [#3622](https://github.com/naturalcrit/homebrewery/issues/3622) - -##### calculuschild - -* [x] Fix `/migrate` page using an editor context instead of share context - -##### 5e-Cleric - -* [x] Fix Monster Stat Blocks losing color in Safari -}} - -\page - -### Monday 7/29/2024 - v3.14.0 -{{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 - -* [x] Brew view count no longer increases when viewed by owner - -Fixes issue [#3037](https://github.com/naturalcrit/homebrewery/issues/3037) - -* [x] Small tweak to PHB H3 sizing - -Fixes issue [#2989](https://github.com/naturalcrit/homebrewery/issues/2989) - -* [x] Add **Fold/Unfold All** {{fas,fa-compress-alt}} / {{fas,fa-expand-alt}} buttons to editor bar - -Fixes issue [#2965](https://github.com/naturalcrit/homebrewery/issues/2965) - - -##### G-Ambatte - -* [x] Share link added to Editor Access error page - -Fixes issue [#3086](https://github.com/naturalcrit/homebrewery/issues/3086) - -* [x] Add Darkbrewery theme to Editor theme selector {{fas,fa-palette}} - -Fixes issue [#3034](https://github.com/naturalcrit/homebrewery/issues/3034) - -* [x] Fix Firefox prints with alternating blank pages - -Fixes issue [#3115](https://github.com/naturalcrit/homebrewery/issues/3115) - -* [x] Admin page working again - -Fixes issue [#2657](https://github.com/naturalcrit/homebrewery/issues/2657) - - -##### 5e-Cleric - -* [x] Fix indenting issue with Monster Blocks and italics in Class Feature - -Fixes issues [#527](https://github.com/naturalcrit/homebrewery/issues/527), -[#3247](https://github.com/naturalcrit/homebrewery/issues/3247) - -* [x] Allow CSS vars in curly syntax to be formatted as strings using single quotes - -`{{--customVar:"'a string'"}}` - -Fixes issue [#3066](https://github.com/naturalcrit/homebrewery/issues/3066) - -* [x] Add *Elderberry Inn* icons {{ei,action}} `{{ei,icon-name}}` - -Fixes issue [#3171](https://github.com/naturalcrit/homebrewery/issues/3171) - -* [x] New {{openSans **{{fas,fa-keyboard}} FONTS** }} snippets! - -Fixes issue [#3171](https://github.com/naturalcrit/homebrewery/issues/3171) - -* [x] New page now opens in a new tab - - -##### abquintic (new contributor!) - -* [x] Add ^super^ `^abc^` and ^^sub^^ `^^abc^^` syntax. - -Fixes issue [#2171](https://github.com/naturalcrit/homebrewery/issues/2171) - -* [x] Add HTML tag assignment to curly syntax `{{tag=value}}` - -Fixes issue [1488](https://github.com/naturalcrit/homebrewery/issues/1488) - -* [x] {{openSans **Brew → Clone to New**}} now clones tags - -Fixes issue [1488](https://github.com/naturalcrit/homebrewery/issues/1488) - -##### calculuschild - -* [x] Better error messages for "Out of Google Drive Storage" and "Not logged in to edit" - -Fixes issues [2510](https://github.com/naturalcrit/homebrewery/issues/2510), -[2975](https://github.com/naturalcrit/homebrewery/issues/2975) - -* [x] Brew Variables -}} - -\ - -{{wide - -### Brew Variable Syntax - -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 | -|:-------|-------------| -| `[var]:content` | Assigns a variable (must start on a line by itself, and ends at the next blank line) | -| `[var](content)` | Assigns a variable and outputs it (can be inline) | -| `[var]` | Outputs the variable contents as a link, if formatted as a valid link | -| `![var]` | Outputs as an image, if formatted as a valid image | -| `$[var]` | Outputs as Markdown | -| `$[var1 + var2 - 2 * var3]` | Performs math operations and outputs result if all variables are valid numbers | -}} - -}} - -{{wide,margin-top:0,margin-bottom:0 -### Examples -}} - -{{wide,columns:2,margin-top:0,margin-bottom:0 - -``` -[first]: Bob - -[last]: Jones - -My name is $[first] $[last]. -``` - -\column - -[first]: Bob - -[last]: Jones - -My name is $[first] $[last]. - -}} - -{{wide,columns:2,margin-top:0,margin-bottom:0 - -``` -[myTable]: -| h1 | h2 | -|----|----| -| c1 | c2 | - -Here is my table: -$[myTable] -``` - -\column - -[myTable]: -| h1 | h2 | -|----|----| -| c1 | c2 | - -Here is my table: -$[myTable] -}} - -{{wide,columns:2,margin-top:0,margin-bottom:0 - -``` -There are $[TableNum] tables total. - -#### Table $[TableNum](1): Horses - -#### Table $[TableNum]($[TableNum + 1]): Cows -``` - -\column - -There are $[TableNum] tables in this document. *(note: final value of `$[TableNum]` gets hoisted up if available)* - - -#### Table $[TableNum](1): Horses - -#### Table $[TableNum]($[TableNum + 1]): Cows -}} - -\page - -### Friday 13/10/2023 - v3.10.0 -{{taskList - -##### G-Ambatte - -* [x] Fix user preferred save location being ignored - -Fixes issue [#2993](https://github.com/naturalcrit/homebrewery/issues/2993) - -* [x] Fix crash to white screen when starting new brews while not signed in - -Fixes issue [#2999](https://github.com/naturalcrit/homebrewery/issues/2999) - -* [x] Fix FreeBSD install script - -Fixes issue [#3005](https://github.com/naturalcrit/homebrewery/issues/3005) - -* [x] Fix *"This brew has been changed on another device"* triggering when manually saving during auto-save - -Fixes issue [#2641](https://github.com/naturalcrit/homebrewery/issues/2641) - -* [x] Fix Firefox different column-flow behavior - -Fixes issue [#2982](https://github.com/naturalcrit/homebrewery/issues/2982) - -* [x] Fix brew titles being mis-sorted on user page - -Fixes issue [#2775](https://github.com/naturalcrit/homebrewery/issues/2775) - -* [x] Text Editor themes now available via new drop-down - -Fixes issue [#362](https://github.com/naturalcrit/homebrewery/issues/362) - -##### 5e-Cleric - -* [x] New {{openSans **PHB → {{fas,fa-quote-right}} QUOTE** }} snippet for V3! - -Fixes issue [#2920](https://github.com/naturalcrit/homebrewery/issues/2920) - -* [x] Several updates and fixes to FAQ and Welcome page - -Fixes issue [#2729](https://github.com/naturalcrit/homebrewery/issues/2729), -[#2787](https://github.com/naturalcrit/homebrewery/issues/2787) - -##### Gazook89 - -* [x] Add syntax highlighting for Definition Lists :\: -}} - - -### Thursday 17/08/2023 - v3.9.2 -{{taskList - -##### calculuschild - -* [x] Fix links to certain old Google Drive files - -Fixes issue [#2917](https://github.com/naturalcrit/homebrewery/issues/2917) - -##### G-Ambatte - -* [x] Menus now open on click, and internally consistent - -Fixes issue [#2702](https://github.com/naturalcrit/homebrewery/issues/2702), [#2782](https://github.com/naturalcrit/homebrewery/issues/2782) - -* [x] Add smarter footer snippet - -Fixes issue [#2289](https://github.com/naturalcrit/homebrewery/issues/2289) - -* [x] Add sanitization in Style editor - -Fixes issue [#1437](https://github.com/naturalcrit/homebrewery/issues/1437) - -* [x] Rework class table snippets to remove unnecessary randomness - -Fixes issue [#2964](https://github.com/naturalcrit/homebrewery/issues/2964) - -* [x] Add User Page link to Google Drive file for file owners, add icons for additional storage locations - -Fixes issue [#2954](https://github.com/naturalcrit/homebrewery/issues/2954) - -* [x] Add default save location selection to Account Page - -Fixes issue [#2943](https://github.com/naturalcrit/homebrewery/issues/2943) - -##### 5e-Cleric - -* [x] Exclude cover pages from Table of Content generation (editing on mobile is still not recommended) - -Fixes issue [#2920](https://github.com/naturalcrit/homebrewery/issues/2920) - -##### Gazook89 - -* [x] Adjustments to improve mobile viewing -}} - - - -### Wednesday 28/06/2023 - v3.9.1 -{{taskList - -##### G-Ambatte - -* [x] Better error pages with more useful information - -Fixes issue [#1924](https://github.com/naturalcrit/homebrewery/issues/1924) -}} - -### Friday 02/06/2023 - v3.9.0 -{{taskList - -##### calculuschild - -* [x] Fix some files not showing up on userpage when user has a large number of brews in Google Drive - -Fixes issue [#2408](https://github.com/naturalcrit/homebrewery/issues/2408) - -* [x] Pressing tab now indents with spaces instead of tab character; fixes several issues with Markdown lists - -Fixes issues [#2092](https://github.com/naturalcrit/homebrewery/issues/2092), [#1556](https://github.com/naturalcrit/homebrewery/issues/1556) - -* [x] Rename `naturalCritLogo.svg` to `naturalCritLogoRed.svg`. Those using the {{beta BETA}} coverPage snippet may need to update that text to make the NaturalCrit logo appear again. - -##### G-Ambatte - -* [x] Fix strange animation of image masks - -Fixes issue [#2790](https://github.com/naturalcrit/homebrewery/issues/2790) - -##### 5e-Cleric - -* [x] New {{openSans **PHB → {{fac,book-part-cover}} PART COVER PAGE** }} snippet for V3! - -* [x] New {{openSans **PHB → {{fac,book-back-cover}} BACK COVER PAGE** }} snippet for V3! (Thanks to /u/Kaiburr_Kath-Hound on Reddit for providing some of these resources!) - -* [x] New {{openSans **TEXT EDITOR → {{fas,fa-bars}} INDEX** }} snippet for V3! - -* [x] Fix highlighting of curly braces inside comments - -Fixes issue [#2784](https://github.com/naturalcrit/homebrewery/issues/2784) -}} - -\page - -### 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 `<\div>` 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-Cleric - -* [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) - -}} - -### Monday 13/03/2023 - v3.7.2 -{{taskList - -##### calculuschild - -* [x] Fix wide Monster Stat Blocks not spanning columns on Legacy -}} - -### Thursday 09/03/2023 - v3.7.1 -{{taskList - -##### Lucastucious (new contributor!) - -* [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) - -{{note -**NOTE:** If you create your PDF on a computer with an old version of Mac Preview (v10 or older) you may see shadows appear as solid gray. -}} - -##### MichielDeMey - -* [x] Updated the Google Drive icon -* [x] Backend fix to unit tests failing intermittently - -##### calculuschild - -* [x] Fix PDF pixelation on CoverPage text outlines -}} - -### Tuesday 28/02/2023 - v3.7.0 -{{taskList - -{{note -**NOTE:** Some new snippets will now show a {{beta BETA}} tag. Feel free to use them, but be aware we may change how they work depending on your feedback. -}} - -##### calculuschild - -* [x] New {{openSans **IMAGES → WATERCOLOR EDGE** {{fac,mask-edge}} }} and {{openSans **WATERCOLOR CORNER** {{fac,mask-corner}} }} snippets for V3, which adds a stylish watercolor texture to the edge of your images! (Thanks to /u/flamableconcrete on Reddit for providing these image masks!) - -* [x] Fix site not displaying on iOS devices - -##### 5e-Cleric - -* [x] New {{openSans **PHB → COVER PAGE** {{fac,book-front-cover}} }} snippet for V3, which adds a stylish coverpage to your brew! (Thanks to /u/Kaiburr_Kath-Hound on Reddit for providing some of these resources!) - -##### MichielDeMey (new contribuor!) - -* [x] Fix typo in testing scripts -* [x] Fix "mug" image not using HTTPS - -Fixes issues [#2687](https://github.com/naturalcrit/homebrewery/issues/2687) -}} - -### Saturday 18/02/2023 - v3.6.1 -{{taskList -##### G-Ambatte - -* [x] Fix users not being removed from Authors list - -Fixes issues [#2674](https://github.com/naturalcrit/homebrewery/issues/2674) -}} - -### Monday 23/01/2023 - v3.6.0 -{{taskList -##### calculuschild - -* [x] Fix Google Drive brews sometimes duplicating - -Fixes issues [#2603](https://github.com/naturalcrit/homebrewery/issues/2603) - -##### Jeddai - -* [x] Add unit tests with full coverage for the Homebrewery API - -* [x] Add message to refresh the browser if the user is missing an update to the Homebrewery - -Fixes issues [#2583](https://github.com/naturalcrit/homebrewery/issues/2583) -}} - -\page - -{{taskList -##### G-Ambatte - -* [x] Auto-compile Themes CSS on development server - -##### 5e-Cleric - -* [x] Fix cloned brews inheriting the parent view count -}} - - -### Friday 23/12/2022 - v3.5.0 -{{taskList - -##### Jeddai - -* [x] Only brew owners or invited authors can edit a brew - - - Visiting an `/edit` page of a brew that does not list you as an author will result in an error page. Authors can be added to any brew by opening its {{fa,fa-info-circle}} **Properties** menu and typing the author's username (case-sensitive) into the **Invited Authors** bubble. - - Warn user if a newer brew version has been saved on another device - -Fixes issues [#1987](https://github.com/naturalcrit/homebrewery/issues/1987) -}} - -### Saturday 10/12/2022 - v3.4.2 -{{taskList - -##### Jeddai - -* [x] Fix broken tags editor - -* [x] Reduce server load to fix some saving issues - -Fixes issues [#2322](https://github.com/naturalcrit/homebrewery/issues/2322) - -##### G-Ambatte - -* [x] Account page help link for Google Drive errors - -Fixes issues [#2520](https://github.com/naturalcrit/homebrewery/issues/2520) -}} - -### Monday 05/12/2022 - v3.4.1 -{{taskList - -##### G-Ambatte - -* [x] Fix Account page incorrect last login time - -Fixes issues [#2521](https://github.com/naturalcrit/homebrewery/issues/2521) - -##### Gazook - -* [x] Fix crashing on iOS and Safari browsers - -Fixes issues [#2531](https://github.com/naturalcrit/homebrewery/issues/2531) -}} - -### Monday 28/11/2022 - v3.4.0 -{{taskList - -##### G-Ambatte - -* [x] Fix for Chrome v108 handling of page size - -Fixes issues [#2445](https://github.com/naturalcrit/homebrewery/issues/2445), [#2516](https://github.com/naturalcrit/homebrewery/issues/2516) - -* [x] New account page with some user info, at {{openSans **USERNAME {{fa,fa-user}} → ACCOUNT {{fa,fa-user}}**}} - -Fixes issues [#2049](https://github.com/naturalcrit/homebrewery/issues/2049), [#2043](https://github.com/naturalcrit/homebrewery/issues/2043) - -* [x] Fix "Published/Private Brews" buttons on userpage - -Fixes issues [#2449](https://github.com/naturalcrit/homebrewery/issues/2449) - -##### Gazook - -* [x] Make autosave default on for new users - -* [x] Added link to our FAQ at {{openSans **NEED HELP? {{fa,fa-question-circle}} → FAQ {{fa,fa-question-circle}}**}} - -* [x] Fix curly blocks freezing with long property lists - -Fixes issues [#2393](https://github.com/naturalcrit/homebrewery/issues/2393) - -* [x] Items can now be removed from {{openSans **RECENT BREWS** {{fas,fa-history}} }} - -Fixes issues [#1918](https://github.com/naturalcrit/homebrewery/issues/1918) - -* [x] Curly injector syntax `{blue}` highlighting in editor - -Fixes issues [#1670](https://github.com/naturalcrit/homebrewery/issues/1670) - -}} - -### Thursday 28/10/2022 - v3.3.1 -{{taskList - -##### calculuschild - -* [x] Fixes to several broken CSS styles from v3.3.0 - -Fixes issues [#2468](https://github.com/naturalcrit/homebrewery/issues/2468) - -##### Jeddai - -* [x] Reduce size of thumbnails on social media links - -}} - -### Friday 19/10/2022 - v3.3.0 -{{taskList - -##### calculuschild - -* [x] Fix for tables broken by Chrome v106 - - -##### G-Ambatte: - -* [x] Fix Table of Contents broken by Chrome v106 - -Fixes issues [#2437](https://github.com/naturalcrit/homebrewery/issues/2437) - -* [x] Show brew thumbnails on user page - -Fixes issues [#2331](https://github.com/naturalcrit/homebrewery/issues/2331) - -* [x] Allow longer URLs for brew thumbnails - -Fixes issues [#2351](https://github.com/naturalcrit/homebrewery/issues/2351) - -* [x] Code no longer unfolds when inserting a snippet - -Fixes issues [#2135](https://github.com/naturalcrit/homebrewery/issues/2135) - -* [x] Fix brew settings being lost on first save - -Fixes issues [#2427](https://github.com/naturalcrit/homebrewery/issues/2427) - -##### Gazook: - -* [x] Several updates to bug reporting and error popups - -Fixes issues [#2376](https://github.com/naturalcrit/homebrewery/issues/2376) - -* [x] Fixes to userpage search bar - -Fixes issues [#1675](https://github.com/naturalcrit/homebrewery/issues/1675), [#2353](https://github.com/naturalcrit/homebrewery/issues/2353) - -* [x] Renderer *(legacy / V3)* now shown next to page # - -Fixes issues [#1928](https://github.com/naturalcrit/homebrewery/issues/1928) - -* [x] Prevent text selection when moving divider bar - -Fixes issues [#1632](https://github.com/naturalcrit/homebrewery/issues/1632) - -* [x] Tweak Monster Stat Block coloring - -Fixes issues [#2123](https://github.com/naturalcrit/homebrewery/issues/2123) - -* [x] Added dropdown button to toggle autosave - -Fixes issues [#1546](https://github.com/naturalcrit/homebrewery/issues/1546) - -}} - - -### Friday 08/09/2022 - v3.2.2 -{{taskList - -##### Jeddai: - -* [x] Fix brews not deleting from User page when removed from Google Drive externally. - - Fixes issues: [#2325](https://github.com/naturalcrit/homebrewery/issues/2325) - -##### G-Ambatte: - -* [x] Brew Tags are now searchable on the User page - -Fixes issues [#2317](https://github.com/naturalcrit/homebrewery/issues/2317), [#2319](https://github.com/naturalcrit/homebrewery/issues/2319), [#2334](https://github.com/naturalcrit/homebrewery/issues/2334) - -* [x] Several tweaks to the User page - - Fixes issues: [#1797](https://github.com/naturalcrit/homebrewery/issues/1797), [#2315](https://github.com/naturalcrit/homebrewery/issues/2315), [#2326](https://github.com/naturalcrit/homebrewery/issues/2326), [#2328](https://github.com/naturalcrit/homebrewery/issues/2328) -}} - - - -\page - -### Wednesday 31/08/2022 - v3.2.1 -{{taskList - -##### calculuschild - -* [x] Reference Links should now work inside tables - - Fixes issues: [#2307](https://github.com/naturalcrit/homebrewery/issues/2307) - -##### Jeddai: - -* [x] Fix printing from `/new` not working - - Fixes issues: [#1789](https://github.com/naturalcrit/homebrewery/issues/1789), [#1806](https://github.com/naturalcrit/homebrewery/issues/1806) - -* [x] Fix broken snippet buttons on `/new` - - Fixes issues: [#2311](https://github.com/naturalcrit/homebrewery/issues/2311) - -##### G-Ambatte: - -* [x] Several small tweaks to the User page - - Fixes issues: [#2301](https://github.com/naturalcrit/homebrewery/issues/2301), [#2303](https://github.com/naturalcrit/homebrewery/issues/2303), [#2121](https://github.com/naturalcrit/homebrewery/issues/2121) -}} - -### Saturday 27/08/2022 - v3.2.0 -{{taskList - -##### calculuschild - -* [x] The V3 renderer is now the default for new brews. - -* [x] Small tweaks to the spacing around the `classTable` style - -##### Jeddai: - -* [x] Brew transfers between Homebrewery and Google Drive now keep the same share and edit links! Metadata is now also kept across transfers. - - Fixes issues: [#1838](https://github.com/naturalcrit/homebrewery/issues/1838) - -* [x] Brews can now be labeled with tags; these will be searchable on the My Brews page in a future update. - - Fixes issues: [#758](https://github.com/naturalcrit/homebrewery/issues/758) - -##### Jlgraves: - -* [x] Small tweaks to the `ClassFeature` snippet - - Fixes issues: [#2215](https://github.com/naturalcrit/homebrewery/issues/2215) -}} - - -### Thursday 09/06/2022 - v3.1.1 -{{taskList - -##### calculuschild: - -* [x] Fixed class table decorations appearing on top of the table in PDF output. - - Fixes issues: [#1784](https://github.com/naturalcrit/homebrewery/issues/1784) - -* [x] Fix bottom decoration on half class tables disappearing when the table is too short. - - Fixes issues: [#2202](https://github.com/naturalcrit/homebrewery/issues/2202) -}} - -### Monday 06/06/2022 - v3.1.0 -{{taskList - -##### G-Ambatte: - -* [x] "Jump to Preview/Editor" buttons added to the divider bar. Easily sync between the editor and preview panels! - - Fixes issues: [#1756](https://github.com/naturalcrit/homebrewery/issues/1756) - -* [x] Speedups to the user page for users with large and/or many brews. - - Fixes issues: [#2147](https://github.com/naturalcrit/homebrewery/issues/2147) - -* [x] Search text on the user page is saved to the URL for easy bookmarking in your browser - - Fixes issues: [#1858](https://github.com/naturalcrit/homebrewery/issues/1858) - -* [x] Added easy login system for offline installs. - - Fixes issues: [#269](https://github.com/naturalcrit/homebrewery/issues/269) - -* [x] New **THUMBNAIL** option in the {{fa,fa-info-circle}} **Properties** menu. This image will show up in social media links. - - Fixes issues: [#820](https://github.com/naturalcrit/homebrewery/issues/820) -}} - -### Wednesday 27/03/2022 - v3.0.8 -{{taskList -* [x] Style updates to user page. - -* [x] Added a logout button (finally)! You can find it under {{openSans **USERNAME {{fa,fa-user}} → LOGOUT {{fas,fa-power-off}}**}} - - Fixes issues: [#303](https://github.com/naturalcrit/homebrewery/issues/303) - -* [x] Clarified the default text when submitting an issue via Reddit post. - -* [x] Fixed broken Table of Contents links in PDFs. (Thanks lucastucious!) - - Fixes issues: [#1749](https://github.com/naturalcrit/homebrewery/issues/1749) - -* [x] Fixed window resizing causing the edit page divider to get lost off of the edge of the page. - - Fixes issues: [#2053](https://github.com/naturalcrit/homebrewery/issues/2053) - -* [x] Fixed Class Table decorations overlapping main text. - - Fixes issues: [#1985](https://github.com/naturalcrit/homebrewery/issues/1985) - -* [x] Updated {{openSans **STYLE EDITOR {{fa,fa-pencil-alt}} → REMOVE DROP CAP {{fas,fa-remove-format}}**}} snippet to also remove small-caps first line font. - -* [x] Background work in preparation for brew themes. -}} - -### Wednesday 02/02/2022 - v3.0.7 -{{taskList -* [x] Revert active line highlighting. - - Fixes issues: [#1913](https://github.com/naturalcrit/homebrewery/issues/1913) - -* [x] Added install steps for Ubuntu. [HERE](https://github.com/naturalcrit/homebrewery/blob/master/install/README.UBUNTU.md) - - Fixes issues: [#1900](https://github.com/naturalcrit/homebrewery/issues/1900) - -* [x] Added social media links to home page. - -* [x] Increase brews visible on the user page to 1,000. - - Fixes issues: [#1943](https://github.com/naturalcrit/homebrewery/issues/1943) - -* [x] Added a Legacy to V3 migration guide under {{openSans **NEED HELP? {{fa,fa-question-circle}} → MIGRATE {{fas,fa-file-import}}**}} - -* [x] Background refactoring and unit tests. -}} - -### Saturday 18/12/2021 - v3.0.6 -{{taskList -* [x] Fixed text wrapping for long strings in code blocks. - - Fixes issues: [#1736](https://github.com/naturalcrit/homebrewery/issues/1736) - -* [x] Code search/replace PC: `CTRL F / CTRL SHIFT F` / Mac: `CMD F / OPTION CMD F` - - Fixes issues: [#1201](https://github.com/naturalcrit/homebrewery/issues/1201) - -* [x] Auto-closing HTML tags and curly braces `{{ }}` -* [x] Highlight current active line - - Fixes issues: [#1202](https://github.com/naturalcrit/homebrewery/issues/1202) - -* [x] Display tabs and trailing spaces - - Fixes issues: [#1622](https://github.com/naturalcrit/homebrewery/issues/1622) - -* [x] Make columns even in V3 Table of Contents. - - Fixes issues: [#1671](https://github.com/naturalcrit/homebrewery/issues/1671) - -* [x] Fix `CTRL P` failing to print from `/new` pages. - - Fixes issues: [#1815](https://github.com/naturalcrit/homebrewery/issues/1815) -}} - -\page - -### Tuesday 07/12/2021 - v3.0.5 -{{taskList -* [x] Fixed paragraph spacing for **note** and **descriptive** boxes in V3. - - Fixes issues: [#1836](https://github.com/naturalcrit/homebrewery/issues/1836) - -* [x] Added a whole bunch of hotkeys: - - * Page Break `CTRL + ENTER` - * Column Break `CTRL + SHIFT + ENTER` - * Bulleted Lists `CTRL + L` - * Numbered Lists `CTRL + SHIFT + L` - * Headers `CTRL + SHIFT + (1-6)` - * Underline `CTRL + U` - * Link `CTRL + K` - * Non-breaking space (\ ) `CTRL + .` - * Add Horizontal Space `CTRL + SHIFT + .` - * Remove Horizontal Space `CTRL + SHIFT + ,` - * Curly Span `CTRL + M` - * Curly Div `CTRL + SHIFT + M` - -* [x] Fixed page numbers in the editor panel getting scrambled when scrolling up and down. - -* [x] Faster swapping between tabs on long brews. - -* [x] Better error messages for common issue with Google Drive credentials expiring. -}} - -### Wednesday 17/11/2021 - v3.0.4 -{{taskList -* [x] Fixed incorrect sorting of Google brews by page count and views on the user page. - - Fixes issues: [#1793](https://github.com/naturalcrit/homebrewery/issues/1793) - -* [x] Added code folding! Only on a page-level for now. Hotkeys `CTRL + [` and `CTRL + ]` to fold/unfold all pages. (Thanks jeddai, new contributor!) - - Fixes issues: [#629](https://github.com/naturalcrit/homebrewery/issues/629) - -* [x] Fixed rendering issues due to the latest Chrome update to version 96. (Also thanks to jeddai!) - - Fixes issues: [#1828](https://github.com/naturalcrit/homebrewery/issues/1828) -}} - -### Wednesday 27/10/2021 - v3.0.3 - -{{taskList -* [x] Moved **Post To Reddit** button from {{fa,fa-info-circle}} **Properties** menu to the **SHARE** {{fa,fa-share-alt}} button as a dropdown. - -* [x] Added a **Copy URL** button to the **SHARE** {{fa,fa-share-alt}} button as a dropdown. - -* [x] Fixed pages being printed directly from `/new` not recognizing the V3 renderer. - - Fixes issues: [#1702](https://github.com/naturalcrit/homebrewery/issues/1702) - -* [x] Updated links to [r/UnearthedArcana](https://www.reddit.com/r/UnearthedArcana/) on home page. - - Fixes issues: [#1744](https://github.com/naturalcrit/homebrewery/issues/1744) - -* [x] Added a [FAQ page](https://homebrewery.naturalcrit.com/faq). - - Fixes issues: [#810](https://github.com/naturalcrit/homebrewery/issues/810) - -* [x] Added {{fa,fa-undo}} **Undo** and {{fa,fa-redo}} **Redo** buttons to the snippet bar. - -}} - -\column - -{{taskList - -* [x] Switching between the {{fa,fa-beer}} **Brew** and {{fa,fa-paint-brush}} **Style** tabs no longer loses your scroll position or undo history. - - Fixes issues: [#1735](https://github.com/naturalcrit/homebrewery/issues/1735) - -* [x] Divider bar between editor and preview panels can no longer be dragged off the edge of the screen. - - Fixes issues: [#1674](https://github.com/naturalcrit/homebrewery/issues/1674) -}} - - -### Wednesday 06/10/2021 - v3.0.2 - -{{taskList -* [x] Fixed V3 **EDITOR → QR Code** snippet not working on `/new` (unsaved) pages. - - Fixes issues: [#1710](https://github.com/naturalcrit/homebrewery/issues/1710) - -* [x] Reorganized several snippets from the **Brew Editor** panel into the **Style Editor** panel. - - Fixes issues: [Reported on Reddit](https://www.reddit.com/r/homebrewery/comments/pm6ki7/two_version_of_class_features_making_it_look_more/) - -* [x] Added a page counter to the right of each `\page` line in V3 to help navigate your brews. Starts counting from page 2. - - Fixes issues: [#846](https://github.com/naturalcrit/homebrewery/issues/846) - -* [x] Moved the changelog to be accessible by clicking on the Homebrewery version number. - - Fixes issues: [#1166](https://github.com/naturalcrit/homebrewery/issues/1166) -}} - -### Friday, 17/09/2021 - v3.0.1 - -{{taskList -* [x] Updated V3 **PHB → Class Feature** snippet to use V3 syntax. - - Fixes issues: [Reported on Reddit](https://www.reddit.com/r/homebrewery/comments/pm6ki7/two_version_of_class_features_making_it_look_more/) - -* [x] Improved V3 **PHB → Monster Stat Block** snippet and styling to allow for easier control of paragraph indentation in the Abilities text. - - Fixes issues: [#181](https://github.com/naturalcrit/homebrewery/issues/181) - -* [x] Improved Legacy **TABLES → Split Table** snippet by removing unneeded column-break backticks. - - Fixes issues: [#844](https://github.com/naturalcrit/homebrewery/issues/844) - -* [x] Changed block elements to use CSS `width` instead of `min-width`. This should make custom styles behave more predictably when trying to resize items. - - Fixes issues: [Reported on Reddit](https://www.reddit.com/r/homebrewery/comments/pohoy3/looking_for_help_with_basic_stuff_in_v3/) - -* [x] Fixed Partial Page Rendering in V3 for large brews - - Fixes issues: [Reported on Reddit](https://www.reddit.com/r/homebrewery/comments/pori3a/weird_behaviour_of_the_brew_after_page_50/) - -* [x] Fixed HTML validation to handle tags starting with 'a', as in `<​aside>`. - - Fixes issues: [#230](https://github.com/naturalcrit/homebrewery/issues/230) - -* [x] Fixed page footers switching side when printing. - - Fixes issues: [#1612](https://github.com/naturalcrit/homebrewery/issues/1612) -}} - - -\page - -### Saturday, 11/09/2021 - v3.0.0 - -We have been working on v3 for a *very* long time. We want to thank everyone for being paitent. - - -Some features planned for V3 have actually been released over the recent months as part of V2, and some are still on the way. But at its core, V3 provides brand new Markdown-to-Brew rendering system, which was no simple task. This has opened up access to all sorts of bugfixes, tweaks, and potential for new features that just wouldn't be possible on the old system. - -***BE WARNED:*** As we continue to develop V3, expect small tweaks in the styling, fonts, and snippets; your brews may look slightly different from day-to-day; some things might break completely while we tackle any bugs in this early stage. All of your old documents will continue to work as normal. We are not touching them. If you don't want to deal With the possibility of slight formatting changes, you may choose to stick with the Legacy renderer on any of your brews for as long as you like. However, most new features added from now on will only be available for brews using the V3 renderer. - -Massive changelog incoming: - -#### Markdown+ -With the latest major update to *The Homebrewery*, we've implemented an extended Markdown-like syntax for block and span elements, plus a few other changes, eliminating the need for HTML tags like `div`, and `span` in most cases. This should hopefully aid non-coders with readability, and also allows us a few tricks in the background to fix some old issues. No raw HTML tags should be needed in a brew, and going forward, raw HTML will no longer receive debugging support (*but can still be used if you insist*). - -All brews made prior to the release of v3.0.0 will still render normally, and you may switch between the "Legacy" brew renderer and the newer "V3" renderer via the {{fa,fa-info-circle}} **Properties** button on your brew. Much of the syntax and styling has changed in V3, so code in one version may be broken in the other. - -Visit [this page](/v3_preview) for brief examples of the new syntax! - -#### Extended Markdown Syntax: - -{{taskList -* [x] Add Divs and Spans for all your custom styling needs, via a simplified Markdown-like syntax: - ``` - {{myDivClass,#myId,color:red - My Div content - }} - - Hello {{mySpan,color:blue World}} ! - ``` - - Fixes issues: [#348](https://github.com/naturalcrit/homebrewery/issues/348) -}} - -\column - -{{taskList -* [x] Add inline CSS to Markdown objects via "curly injection" syntax: - ``` - Hello *world*{myClass,#id,color:red} - ``` - Fixes issues: [#403](https://github.com/naturalcrit/homebrewery/issues/403) - -* [x] Rowspan, Colspan, and multiple header rows with extended table syntax: -``` -| Header 1a | Header 1b | Header 1c | -| Header 2a | Header 2b | Header 2c | -|:---------:|:----------|:---------:| -| Span 2 columns || Span 2 | -| one col | one col | rows ^| -``` - Fixes issues: [#773](https://github.com/naturalcrit/homebrewery/issues/773), [#191](https://github.com/naturalcrit/homebrewery/issues/191) - -* [x] Hanging indents via `
` tags, as seen in the **PHB → Spell** snippet. Add via "double-colon" syntax: -``` -Term :: big long definition that bleeds onto multiple lines -``` - Fixes issues: [#182](https://github.com/naturalcrit/homebrewery/issues/182), [#149](https://github.com/naturalcrit/homebrewery/issues/149) - -* [x] Easier vertical spacing via colons alone on a line: - ``` - ::: - ``` - Fixes issues: [#374](https://github.com/naturalcrit/homebrewery/issues/374) - -* [x] Avoid paragraph indendation by ending the previous paragraph with a backslash `\` or two spaces ` ` - ``` - Paragraph one\ - Paragraph two - ``` - Fixes issues: [#636](https://github.com/naturalcrit/homebrewery/issues/636) - -* [x] Code blocks can be inserted by surrounding it with rows of three backticks ` ``` `, for demonstration purposes or to share custom styles. Inline-code can be inserted with single backticks `code` -
```
- Here is some code!
-```
-
- - Fixes issues: [#465](https://github.com/naturalcrit/homebrewery/issues/465) - -#### New and Fixed Snippets - -* [x] Column breaks now use `\column` instead of ` ``` ` backticks. - - Fixes issues: [#607](https://github.com/naturalcrit/homebrewery/issues/607) - -* [x] Page breaks using `\page` now only trigger when placed alone at the start of a line. - - Fixes issues: [#1147](https://github.com/naturalcrit/homebrewery/issues/1147) -}} - -\page -{{taskList -* [x] New **EDITOR → QR Code** snippet. - - Fixes issues: [#538](https://github.com/naturalcrit/homebrewery/issues/538) - -* [x] New **IMAGES → Watercolor Splatter** snippet, which adds one of a range of stylish stains to your brew. - -* [x] New **IMAGES → Watermark** snippet, which adds transparent text diagonally across the page. - -* [x] New **PHB → Magic Item** snippet. - - Fixes issues: [#671](https://github.com/naturalcrit/homebrewery/issues/671) - -* [x] New **TABLES → 1/3 Class Table** snippet for 1/3 casters. - - Fixes issues: [#191](https://github.com/naturalcrit/homebrewery/issues/191) - -* [x] Improved **EDITOR → Table of Contents** snippet to actually look like the PHB style. Will auto-generate based on the headers in your brew. - - Fixes issues: [#304](https://github.com/naturalcrit/homebrewery/issues/304) - -* [x] Improved **PHB → Monster Stat Block** snippet with textures, and an option to remove the frame entirely. - -* [x] Improved **PHB → Spell List** snippet can now be made single-column. - - Fixes issues: [#509](https://github.com/naturalcrit/homebrewery/issues/509), [#914](https://github.com/naturalcrit/homebrewery/issues/914) - -* [x] Improved **TABLES → Class Table** snippet is now cleaned up, has an option to remove the frame entirely, and includes additional boundary decorations. - - Fixes issues: [#773](https://github.com/naturalcrit/homebrewery/issues/773), [#302](https://github.com/naturalcrit/homebrewery/issues/302) - -#### Miscellaneous Formatting Fixes - -* [x] Paragraphs are now able to split across columns. - - Fixes issues: [#239](https://github.com/naturalcrit/homebrewery/issues/239) - -* [x] Multiple fixes for bold/italicize using asterisks `* *` - - Fixes issues: [#1321](https://github.com/naturalcrit/homebrewery/issues/1321), [#852](https://github.com/naturalcrit/homebrewery/issues/852) - -* [x] Multiple for list items not displaying correctly. - - Fixes issues: [#1085](https://github.com/naturalcrit/homebrewery/issues/1085), [#588](https://github.com/naturalcrit/homebrewery/issues/588) - -* [x] "Smart quotes", so left and right quotes are different. - - Fixes issues: [#849](https://github.com/naturalcrit/homebrewery/issues/849) - -* [x] Long URLs in links now wrap properly. - - Fixes issues: [#1136](https://github.com/naturalcrit/homebrewery/issues/1136) - -* [x] Better support for `wide` blocks that span across the whole page! No more problems with contents getting shunted off the edge, and each new wide element in a page will restart the next item back at column one. Manual `\column` breaks will help organize subsequent content between the columns as needed. - - Fixes issues: [#144](https://github.com/naturalcrit/homebrewery/issues/144), [#1024](https://github.com/naturalcrit/homebrewery/issues/1024) - -* [x] Fonts now support a wider range of latin characters for non-English brews, including áéíóúñ¡¿, etc... - - Fixes issues: [#116](https://github.com/naturalcrit/homebrewery/issues/116) - -* [x] Drop-caps (fancy first letters) have been re-styled and re-aligned to correct the ugly overlapping and cut-off on some characters like K and Y. - - Fixes issues: [#848](https://github.com/naturalcrit/homebrewery/issues/848) -}} - -\column - -### Under-the-Hood Stuff -We had to make a whole lot of background upgrades and changes to get all of this working, and now that the framework is in place, there's a lot more planned and upcoming *"sometime"* : - -{{taskList -* [ ] New Themes to style your brews. DMG, MM, a custom Homebrewery theme, and others. -* [ ] The ability to build your own custom themes using CSS, apply it to other brews, and share it with others! -* [ ] Easy control of item colors. Change your monster blocks, tables, and notes from yellow to green to red! -* [ ] New image-based snippets, including handwritten notes, title illustrations, and alternative decorations. -* [ ] New fun fonts like Elvish, Draconic, Orcish, etc. -* [ ] Better organization of personal brews using tags. -* [ ] ....a log-out button...? -* [ ] AND MORE. -}} - -### Interface -:: -#### Style Editor Panel - -{{fa,fa-paint-brush}} Technically released prior to v3 but still new to many users, check out the new **Style Editor** located on the right side of the Snippet bar. This editor accepts CSS for styling without requiring `'; - return
${cleanStyle} ` }} />; + const cleanStyle = safeHTML(`${themeStyles} \n\n `); + return
; }; const renderPage = (pageText, index)=>{ + + let styles = { + ...(!displayOptions.pageShadows ? { boxShadow: 'none' } : {}) + // Add more conditions as needed + }; + let classes = 'page'; + let attributes = {}; + if(props.renderer == 'legacy') { + pageText.replace(COLUMNBREAK_REGEX_LEGACY, '```\n````\n'); // Allow Legacy brews to use `\column(break)` const html = MarkdownLegacy.render(pageText); - return ; + + return ; } else { + if(pageText.startsWith('\\page')) { + const firstLineTokens = Markdown.marked.lexer(pageText.split('\n', 1)[0])[0].tokens; + const injectedTags = firstLineTokens?.find((obj)=>obj.injectedTags !== undefined)?.injectedTags; + if(injectedTags) { + styles = { ...styles, ...injectedTags.styles }; + styles = _.mapKeys(styles, (v, k)=>k.startsWith('--') ? k : _.camelCase(k)); // Convert CSS to camelCase for React + classes = [classes, injectedTags.classes].join(' ').trim(); + attributes = injectedTags.attributes; + } + pageText = pageText.includes('\n') ? pageText.substring(pageText.indexOf('\n') + 1) : ''; // Remove the \page line + } + + // DO NOT REMOVE!!! REQUIRED FOR BACKWARDS COMPATIBILITY WITH NON-UPGRADABLE VERSIONS OF CHROME. pageText += `\n\n \n\\column\n `; //Artificial column break at page end to emulate column-fill:auto (until `wide` is used, when column-fill:balance will reappear) + const html = Markdown.render(pageText, index); - return ; + + return ; } }; @@ -141,7 +224,8 @@ const BrewRenderer = (props)=>{ renderedPages.length = 0; // Render currently-edited page first so cross-page effects (variables, links) can propagate out first - renderedPages[props.currentEditorCursorPageNum - 1] = renderPage(rawPages[props.currentEditorCursorPageNum - 1], props.currentEditorCursorPageNum - 1); + if(rawPages.length > props.currentEditorCursorPageNum -1) + renderedPages[props.currentEditorCursorPageNum - 1] = renderPage(rawPages[props.currentEditorCursorPageNum - 1], props.currentEditorCursorPageNum - 1); _.forEach(rawPages, (page, index)=>{ if((isInView(index) || !renderedPages[index]) && typeof window !== 'undefined'){ @@ -161,10 +245,30 @@ const BrewRenderer = (props)=>{ } }; + const scrollToHash = (hash)=>{ + if(!hash) return; + + const iframeDoc = document.getElementById('BrewRenderer').contentDocument; + let anchor = iframeDoc.querySelector(hash); + + if(anchor) { + anchor.scrollIntoView({ behavior: 'smooth' }); + } else { + // Use MutationObserver to wait for the element if it's not immediately available + new MutationObserver((mutations, obs)=>{ + anchor = iframeDoc.querySelector(hash); + if(anchor) { + anchor.scrollIntoView({ behavior: 'smooth' }); + obs.disconnect(); + } + }).observe(iframeDoc, { childList: true, subtree: true }); + } + }; + const frameDidMount = ()=>{ //This triggers when iFrame finishes internal "componentDidMount" + scrollToHash(window.location.hash); + setTimeout(()=>{ //We still see a flicker where the style isn't applied yet, so wait 100ms before showing iFrame - updateSize(); - window.addEventListener('resize', updateSize); renderPages(); //Make sure page is renderable before showing setState((prevState)=>({ ...prevState, @@ -179,19 +283,25 @@ const BrewRenderer = (props)=>{ document.dispatchEvent(new MouseEvent('click')); }; - //Toolbar settings: - const handleZoom = (newZoom)=>{ - setState((prevState)=>({ - ...prevState, - zoom : newZoom - })); + const handleDisplayOptionsChange = (newDisplayOptions)=>{ + setDisplayOptions(newDisplayOptions); + localStorage.setItem(TOOLBAR_STATE_KEY, JSON.stringify(newDisplayOptions)); }; + const pagesStyle = { + zoom : `${displayOptions.zoomLevel}%`, + columnGap : `${displayOptions.columnGap}px`, + rowGap : `${displayOptions.rowGap}px` + }; + + const renderedStyle = useMemo(()=>renderStyle(), [props.style, props.themeBundle]); + renderedPages = useMemo(()=>renderPages(), [props.text, displayOptions]); + return ( <> {/*render dummy page while iFrame is mounting.*/} {!state.isMounted - ?
+ ?
{renderDummyPage(1)}
@@ -204,7 +314,7 @@ const BrewRenderer = (props)=>{
- + 0 ? state.visiblePages : [state.centerPage]} totalPages={rawPages.length} headerState={headerState} setHeaderState={setHeaderState}/> {/*render in iFrame so broken code doesn't crash the site.*/} { contentDidMount={frameDidMount} onClick={()=>{emitClick();}} > -
+ > {/* Apply CSS from Style tab and render pages from Markdown tab */} {state.isMounted && <> - {renderStyle()} -
- {renderPages()} + {renderedStyle} +
+ {renderedPages}
}
+ {headerState ? : <>} ); }; -module.exports = BrewRenderer; +export default BrewRenderer; diff --git a/client/homebrew/brewRenderer/brewRenderer.less b/client/homebrew/brewRenderer/brewRenderer.less index dca64c455..5769a13df 100644 --- a/client/homebrew/brewRenderer/brewRenderer.less +++ b/client/homebrew/brewRenderer/brewRenderer.less @@ -1,11 +1,42 @@ @import (multiple, less) 'shared/naturalcrit/styles/reset.less'; .brewRenderer { + height : 100vh; + padding-top : 60px; overflow-y : scroll; will-change : transform; - padding-top : 30px; + &:has(.facing, .flow) { padding : 60px 30px; } :where(.pages) { - margin : 30px 0px; + &.facing { + display : grid; + grid-template-rows : repeat(3, auto); + grid-template-columns : repeat(2, auto); + gap : 10px 10px; + justify-content : safe center; + &.recto .page:first-child { + // sets first page on 'right' ('recto') of the preview, as if for a Cover page. + // todo: add a checkbox to toggle this setting + grid-column-start : 2; + } + & :where(.page) { + margin-right : unset !important; + margin-left : unset !important; + } + } + + &.flow { + display : flex; + flex-wrap : wrap; + gap : 10px; + justify-content : safe center; + & :where(.page) { + flex : 0 0 auto; + margin-right : unset !important; + margin-left : unset !important; + } + + } + & > :where(.page) { width : 215.9mm; height : 279.4mm; @@ -14,6 +45,7 @@ margin-left : auto; box-shadow : 1px 4px 14px #000000; } + *[id] { scroll-margin-top : 100px; } } &::-webkit-scrollbar { width : 20px; @@ -27,19 +59,33 @@ } &-corner { visibility : hidden; } } + + @supports (break-after:always) { + .columnSplit { + margin-bottom: 100vh; + } + } } .pane { position : relative; } + @media print { .toolBar { display : none; } .brewRenderer { - height : 100%; - padding-top : unset; - overflow-y : unset; + height : 100%; + padding : unset; + overflow-y : unset; + &:has(.facing, .flow) { + padding : unset; + } .pages { - margin : 0px; + margin : 0px; + zoom : 100% !important; + display : block; & > .page { box-shadow : unset; } } } -} \ No newline at end of file + .headerNav { visibility : hidden; } + +} diff --git a/client/homebrew/brewRenderer/errorBar/errorBar.jsx b/client/homebrew/brewRenderer/errorBar/errorBar.jsx index d2f847306..b4522d759 100644 --- a/client/homebrew/brewRenderer/errorBar/errorBar.jsx +++ b/client/homebrew/brewRenderer/errorBar/errorBar.jsx @@ -1,75 +1,53 @@ -require('./errorBar.less'); -const React = require('react'); -const createClass = require('create-react-class'); -const _ = require('lodash'); +import './errorBar.less'; +import React from 'react'; -const ErrorBar = createClass({ - displayName : 'ErrorBar', - getDefaultProps : function() { - return { - errors : [] - }; - }, +import Dialog from '../../../components/dialog.jsx'; - hasOpenError : false, - hasCloseError : false, - hasMatchError : false, +const DISMISS_BUTTON = ; - renderErrors : function(){ - this.hasOpenError = false; - this.hasCloseError = false; - this.hasMatchError = false; +const ErrorBar = (props)=>{ + if(!props.errors.length) return null; + let hasOpenError = false, hasCloseError = false, hasMatchError = false; + props.errors.map((err)=>{ + if(err.id === 'OPEN') hasOpenError = true; + if(err.id === 'CLOSE') hasCloseError = true; + if(err.id === 'MISMATCH') hasMatchError = true; + }); - const errors = _.map(this.props.errors, (err, idx)=>{ - if(err.id == 'OPEN') this.hasOpenError = true; - if(err.id == 'CLOSE') this.hasCloseError = true; - if(err.id == 'MISMATCH') this.hasMatchError = true; - return
  • - Line {err.line} : {err.text}, '{err.type}' tag -
  • ; - }); + const renderErrors = ()=>( +
      + {props.errors.map((err, idx)=>{ + return
    • + Line {err.line} : {err.text}, '{err.type}' tag +
    • ; + })} +
    + ); - return
      {errors}
    ; - }, - - renderProtip : function(){ - const msg = []; - if(this.hasOpenError){ - msg.push(
    - An unmatched opening tag means there's an opened tag that isn't closed. You need to close your tags, like this {'
    '}. Make sure to match types! -
    ); - } - - if(this.hasCloseError){ - msg.push(
    - An unmatched closing tag means you closed a tag without opening it. Either remove it, or check to where you think you opened it. -
    ); - } - - if(this.hasMatchError){ - msg.push(
    - A type mismatch means you closed a tag, but the last open tag was a different type. -
    ); - } - return
    + const renderProtip = ()=>( +

    Protips!

    - {msg} -
    ; - }, + {hasOpenError &&
    Unmatched opening tag. Close your tags, like this {'
    '}. Match types!
    } + {hasCloseError &&
    Unmatched closing tag. Either remove it or check where it was opened.
    } + {hasMatchError &&
    Type mismatch. Closed a tag with a different type.
    } +
    + ); - render : function(){ - if(!this.props.errors.length) return null; - - return
    - -

    There are HTML errors in your markup

    - If these aren't fixed your brew will not render properly when you print it to PDF or share it - {this.renderErrors()} + return ( + +
    + +

    There are HTML errors in your markup

    + + If these aren't fixed your brew will not render properly when you print it to PDF or share it + + {renderErrors()} +

    - {this.renderProtip()} -
    ; - } -}); + {renderProtip()} + + ); +}; -module.exports = ErrorBar; +export default ErrorBar; diff --git a/client/homebrew/brewRenderer/errorBar/errorBar.less b/client/homebrew/brewRenderer/errorBar/errorBar.less index f3f2dbaae..163648533 100644 --- a/client/homebrew/brewRenderer/errorBar/errorBar.less +++ b/client/homebrew/brewRenderer/errorBar/errorBar.less @@ -1,60 +1,58 @@ -.errorBar{ +.errorBar { position : absolute; - z-index : 10000; - box-sizing : border-box; + top : 32px; + z-index : 1; width : 100%; - margin-right : 13px; - padding : 20px; - padding-bottom : 10px; - padding-left : 100px; - background-color : @red; color : white; - i{ - position : absolute; - left : 30px; - opacity : 0.8; - font-size : 3em; - } - h3{ - font-size : 1.1em; - font-weight : 800; - } - ul{ - margin-top : 15px; - font-size : 0.8em; - list-style-position : inside; - list-style-type : disc; - li{ - line-height : 1.6em; + background-color : @red; + border : unset; + + div { + > i { + float : left; + margin-right : 10px; + margin-bottom : 20px; + font-size : 3em; + opacity : 0.8; + } + h2 { font-weight : 800; } + ul { + margin-top : 15px; + font-size : 0.8em; + list-style-position : inside; + list-style-type : disc; + li { line-height : 1.6em; } } } - hr{ - box-sizing : border-box; + hr { height : 2px; - width : 150%; margin-top : 25px; margin-bottom : 15px; - margin-left : -100px; background-color : darken(@red, 8%); border : none; } - small{ - font-size: 0.6em; - opacity: 0.7; + small { + font-size : 0.6em; + opacity : 0.7; } - .protips{ - margin-left : -80px; - font-size : 0.6em; - &>div{ - margin-bottom : 10px; - line-height : 1.2em; - } - h4{ - opacity : 0.8; + .protips { + font-size : 0.6em; + line-height : 1.2em; + h4 { font-weight : 800; line-height : 1.5em; text-transform : uppercase; } } + button.dismiss { + position : absolute; + top : 20px; + right : 30px; + padding : unset; + font-size : 40px; + background-color : transparent; + opacity : 0.6; + &:hover { opacity : 1; } + } } \ No newline at end of file diff --git a/client/homebrew/brewRenderer/headerNav/headerNav.jsx b/client/homebrew/brewRenderer/headerNav/headerNav.jsx new file mode 100644 index 000000000..3b184aff0 --- /dev/null +++ b/client/homebrew/brewRenderer/headerNav/headerNav.jsx @@ -0,0 +1,113 @@ +import './headerNav.less'; + +import React from 'react'; +import _ from 'lodash'; + +const MAX_TEXT_LENGTH = 40; + +const HeaderNav = React.forwardRef(({}, pagesRef)=>{ + + const renderHeaderLinks = ()=>{ + if(!pagesRef.current) return; + + // Top Level Pages + // Pages that contain an element with a specified class (e.g. cover pages, table of contents) + // will NOT have its content scanned for navigation headers, instead displaying a custom label + // --- + // The property name is class that will be used for detecting the page is a top level page + // The property value is a function that returns the text to be used + + const topLevelPages = { + '.frontCover' : (el, pageType)=>{ const text = getHeaderContent(el); return text ? `Cover: ${text}` : 'Cover Page'; }, + '.insideCover' : (el, pageType)=>{ const text = getHeaderContent(el); return text ? `Interior: ${text}` : 'Interior Cover Page'; }, + '.partCover' : (el, pageType)=>{ const text = getHeaderContent(el); return text ? `Section: ${text}` : 'Section Cover Page'; }, + '.backCover' : (el, pageType)=>{ const text = getHeaderContent(el); return text ? `Back: ${text}` : 'Rear Cover Page'; }, + '.toc' : ()=>{ return 'Table of Contents'; }, + }; + + const getHeaderContent = (el)=>el.querySelector('h1')?.textContent; + + const topLevelPageSelector = Object.keys(topLevelPages).join(','); + + const selector = [ + '.pages > .page', // All page elements, which by definition have IDs + `.page:not(:has(${topLevelPageSelector})) > [id]`, // All direct children of non-excluded .pages with an ID (Legacy) + `.page:not(:has(${topLevelPageSelector})) > .columnWrapper > [id]`, // All direct children of non-excluded .page > .columnWrapper with an ID (V3) + `.page:not(:has(${topLevelPageSelector})) h2`, // All non-excluded H2 titles, like Monster frame titles + ]; + const elements = pagesRef.current.querySelectorAll(selector.join(',')); + if(!elements) return; + const navList = []; + + // navList is a list of objects which have the following structure: + // { + // depth : how deeply indented the item should be + // text : the text to display in the nav link + // link : the hyperlink to navigate to when clicked + // className : [optional] the class to apply to the nav link for styling + // } + + elements.forEach((el)=>{ + const navEntry = { // Default structure of a navList entry + depth : 7, // All unmatched elements with IDs are set to the maximum depth (7) + text : el.textContent, // Use `textContent` because `innerText` is affected by rendering, e.g. 'content-visibility: auto' + link : el.id + }; + if(el.classList.contains('page')) { + let text = `Page ${el.id.slice(1)}`; // Get the page # by trimming off the 'p' from the ID + const pageType = Object.keys(topLevelPages).find((pageType)=>el.querySelector(pageType)); + if(pageType) + text += ` - ${topLevelPages[pageType](el, pageType)}`; // If a Top Level Page, add extra label + + navEntry.depth = 0; // Pages are always at the least indented level + navEntry.text = text; + navEntry.className = 'pageLink'; + } else if(el.localName.match(/^h[1-6]/)){ // Header elements H1 through H6 + navEntry.depth = el.localName[1]; // Depth is set by the header level + } + navList.push(navEntry); + }); + + return _.map(navList, (navItem, index)=> + ); + }; + + return ; +}); + +const HeaderNavItem = ({ link, text, depth, className })=>{ + + const trimString = (text, prefixLength = 0)=>{ + // Sanity check nav link strings + let output = text; + + // If the string has a line break, only use the first line + if(text.indexOf('\n')){ + output = text.split('\n')[0]; + } + + // Trim unecessary spaces from string + output = output.trim(); + + // Reduce excessively long strings + const maxLength = MAX_TEXT_LENGTH - prefixLength; + if(output.length > maxLength){ + return `${output.slice(0, maxLength).trim()}...`; + } + return output; + }; + + if(!link || !text) return; + + return
  • + + {trimString(text, depth)} + +
  • ; +}; + +export default HeaderNav; \ No newline at end of file diff --git a/client/homebrew/brewRenderer/headerNav/headerNav.less b/client/homebrew/brewRenderer/headerNav/headerNav.less new file mode 100644 index 000000000..a5fd11f5e --- /dev/null +++ b/client/homebrew/brewRenderer/headerNav/headerNav.less @@ -0,0 +1,39 @@ +.headerNav { + position : fixed; + top : 32px; + left : 0px; + max-width : 40vw; + max-height : calc(100vh - 32px); + padding : 5px 10px; + overflow-y : auto; + background-color : #CCCCCC; + border-radius : 5px; + &.active { + padding-bottom : 10px; + .navIcon { padding-bottom : 10px; } + } + .navIcon { cursor : pointer; } + li { + list-style-type : none; + a { + display : inline-block; + width : 100%; + padding : 2px; + font-family : 'Open Sans'; + font-size : 12px; + color : inherit; + text-decoration : none; + cursor : pointer; + &:hover { text-decoration : underline; } + &.pageLink { font-weight : 900; } + + @depths: 0,1,2,3,4,5,6,7; + + each(@depths, { + &.depth-@{value} { + padding-left: ((@value) * 0.5em); + } + }); + } + } +} \ No newline at end of file diff --git a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx index cba6a629c..dd05391f0 100644 --- a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx +++ b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx @@ -1,46 +1,65 @@ -require('./notificationPopup.less'); -const React = require('react'); -const _ = require('lodash'); +import './notificationPopup.less'; +import React, { useEffect, useState } from 'react'; +import request from '../../utils/request-middleware.js'; +import Markdown from 'markdown.js'; import Dialog from '../../../components/dialog.jsx'; -const DISMISS_KEY = 'dismiss_notification04-09-24'; const DISMISS_BUTTON = ; const NotificationPopup = ()=>{ - return + const [notifications, setNotifications] = useState([]); + const [dissmissKeyList, setDismissKeyList] = useState([]); + const [error, setError] = useState(null); + + useEffect(()=>{ + getNotifications(); + }, []); + + const getNotifications = async ()=>{ + setError(null); + try { + const res = await request.get('/admin/notification/all'); + pickActiveNotifications(res.body || []); + } catch (err) { + console.log(err); + setError(`Error looking up notifications: ${err?.response?.body?.message || err.message}`); + } + }; + + const pickActiveNotifications = (notifs)=>{ + const now = new Date(); + const filteredNotifications = notifs.filter((notification)=>{ + const startDate = new Date(notification.startAt); + const stopDate = new Date(notification.stopAt); + const dismissed = localStorage.getItem(notification.dismissKey) ? true : false; + return now >= startDate && now <= stopDate && !dismissed; + }); + setNotifications(filteredNotifications); + setDismissKeyList(filteredNotifications.map((notif)=>notif.dismissKey)); + }; + + const renderNotificationsList = ()=>{ + if(error) return
    {error}
    ; + return notifications.map((notification)=>( +
  • + {notification.title}
    +

    +
  • + )); + }; + + if(!notifications.length) return; + return

    Notice

    This website is always improving and we are still adding new features and squashing bugs. Keep the following in mind:
      -
    • - Search brews with our new page!
      - We have been working very hard in making this possible, now you can share your work and look at it in the new Vault page! - All PUBLISHED brews will be available to anyone searching there, by title or author, and filtering by renderer. - - More features will be coming. -
    • - -
    • - Don't delete your Homebrewery folder on Google Drive!
      - We have had several reports of users losing their brews, not realizing - that they had deleted the files on their Google Drive. If you have a Homebrewery folder - on your Google Drive with *.txt files inside, do not delete it! - We cannot help you recover files that you have deleted from your own - Google Drive. -
    • - -
    • - Protect your work!
      - If you opt not to use your Google Drive, keep in mind that we do not save a history of your projects. Please make frequent backups of your brews!  - - See the FAQ - to learn how to avoid losing your work! -
    • + {renderNotificationsList()}
    ; }; -module.exports = NotificationPopup; +export default NotificationPopup; diff --git a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less index 2982055c8..85d4c8365 100644 --- a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less +++ b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less @@ -48,14 +48,46 @@ } ul { margin-top : 15px; - font-size : 0.8em; + font-size : 0.9em; list-style-position : outside; list-style-type : disc; li { - margin-top : 1.4em; - font-size : 0.8em; - line-height : 1.4em; - em { font-weight : 800; } + padding-left : 1em; + margin-top : 1.5em; + font-size : 0.9em; + line-height : 1.5em; + em { + font-weight : 800; + text-transform : capitalize; + } + li { + margin-top : 0; + line-height : 1.2em; + list-style-type : square; + } + } + ul ul,ol ol,ul ol,ol ul { + margin-bottom : 0px; + margin-left : 1.5em; } } -} + + /* Markdown styling */ + code { + padding : 0.1em 0.5em; + font-family : 'Courier New', 'Courier', monospace; + overflow-wrap : break-word; + white-space : pre-wrap; + background : #08115A; + border-radius : 2px; + } + pre code { + display : inline-block; + width : 100%; + } + .blank { + height : 1em; + margin-top : 0; + & + * { margin-top : 0; } + } +} \ No newline at end of file diff --git a/client/homebrew/brewRenderer/safeHTML.js b/client/homebrew/brewRenderer/safeHTML.js new file mode 100644 index 000000000..2574f4cfe --- /dev/null +++ b/client/homebrew/brewRenderer/safeHTML.js @@ -0,0 +1,46 @@ +// Derived from the vue-html-secure package, customized for Homebrewery + +let doc = null; +let div = null; + +function safeHTML(htmlString) { + // If the Document interface doesn't exist, exit + if(typeof document == 'undefined') return null; + // If the test document and div don't exist, create them + if(!doc) doc = document.implementation.createHTMLDocument(''); + if(!div) div = doc.createElement('div'); + + // Set the test div contents to the evaluation string + div.innerHTML = htmlString; + // Grab all nodes from the test div + const elements = div.querySelectorAll('*'); + + // Blacklisted tags + const blacklistTags = ['script', 'noscript', 'noembed']; + // Tests to remove attributes + const blacklistAttrs = [ + (test)=>{return test.localName.indexOf('on') == 0;}, + (test)=>{return test.localName.indexOf('type') == 0 && test.value.match(/submit/i);}, + (test)=>{return test.value.replace(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205f\u3000]/g, '').toLowerCase().trim().indexOf('javascript:') == 0;} + ]; + + + elements.forEach((element)=>{ + // Check each element for blacklisted type + if(blacklistTags.includes(element?.localName?.toLowerCase())) { + element.remove(); + return; + } + // Check remaining elements for blacklisted attributes + for (const attribute of element.attributes){ + if(blacklistAttrs.some((test)=>{return test(attribute);})) { + element.removeAttribute(attribute.localName); + break; + }; + }; + }); + + return div.innerHTML; +}; + +module.exports.safeHTML = safeHTML; \ No newline at end of file diff --git a/client/homebrew/brewRenderer/toolBar/toolBar.jsx b/client/homebrew/brewRenderer/toolBar/toolBar.jsx index 73b48d778..be0842f33 100644 --- a/client/homebrew/brewRenderer/toolBar/toolBar.jsx +++ b/client/homebrew/brewRenderer/toolBar/toolBar.jsx @@ -1,28 +1,38 @@ -require('./toolBar.less'); -const React = require('react'); -const { useState, useEffect } = React; -const _ = require('lodash'); +/* eslint-disable max-lines */ +import './toolBar.less'; +import React, { useState, useEffect } from 'react'; +import _ from 'lodash'; +import { Anchored, AnchoredBox, AnchoredTrigger } from '../../../components/Anchored.jsx'; const MAX_ZOOM = 300; const MIN_ZOOM = 10; -const ToolBar = ({ onZoomChange, currentPage, onPageChange, totalPages })=>{ +const TOOLBAR_VISIBILITY = 'HB_renderer_toolbarVisibility'; - const [zoomLevel, setZoomLevel] = useState(100); - const [pageNum, setPageNum] = useState(currentPage); +const ToolBar = ({ displayOptions, onDisplayOptionsChange, visiblePages, totalPages, headerState, setHeaderState })=>{ + + const [pageNum, setPageNum] = useState(1); const [toolsVisible, setToolsVisible] = useState(true); useEffect(()=>{ - onZoomChange(zoomLevel); - }, [zoomLevel]); + // format multiple visible pages as a range (e.g. "150-153") + const pageRange = visiblePages.length === 1 ? `${visiblePages[0]}` : `${visiblePages[0]} - ${visiblePages.at(-1)}`; + setPageNum(pageRange); + }, [visiblePages]); useEffect(()=>{ - setPageNum(currentPage); - }, [currentPage]); + const Visibility = localStorage.getItem(TOOLBAR_VISIBILITY); + if(Visibility) setToolsVisible(Visibility === 'true'); + + }, []); const handleZoomButton = (zoom)=>{ - setZoomLevel(_.round(_.clamp(zoom, MIN_ZOOM, MAX_ZOOM))); + handleOptionChange('zoomLevel', _.round(_.clamp(zoom, MIN_ZOOM, MAX_ZOOM))); + }; + + const handleOptionChange = (optionKey, newValue)=>{ + onDisplayOptionsChange({ ...displayOptions, [optionKey]: newValue }); }; const handlePageInput = (pageInput)=>{ @@ -30,16 +40,16 @@ const ToolBar = ({ onZoomChange, currentPage, onPageChange, totalPages })=>{ setPageNum(parseInt(pageInput)); // input type is 'text', so `page` comes in as a string, not number. }; + // scroll to a page, used in the Prev/Next Page buttons. const scrollToPage = (pageNumber)=>{ + if(typeof pageNumber !== 'number') return; pageNumber = _.clamp(pageNumber, 1, totalPages); const iframe = document.getElementById('BrewRenderer'); const brewRenderer = iframe?.contentWindow?.document.querySelector('.brewRenderer'); const page = brewRenderer?.querySelector(`#p${pageNumber}`); page?.scrollIntoView({ block: 'start' }); - setPageNum(pageNumber); }; - const calculateChange = (mode)=>{ const iframe = document.getElementById('BrewRenderer'); const iframeWidth = iframe.getBoundingClientRect().width; @@ -52,58 +62,87 @@ const ToolBar = ({ onZoomChange, currentPage, onPageChange, totalPages })=>{ // find widest page, in case pages are different widths, so that the zoom is adapted to not cut the widest page off screen. const widestPage = _.maxBy([...pages], 'offsetWidth').offsetWidth; - desiredZoom = (iframeWidth / widestPage) * 100; + if(displayOptions.spread === 'facing') + desiredZoom = (iframeWidth / ((widestPage * 2) + parseInt(displayOptions.columnGap))) * 100; + else + desiredZoom = (iframeWidth / (widestPage + 20)) * 100; } else if(mode == 'fit'){ // find the page with the largest single dim (height or width) so that zoom can be adapted to fit it. - const minDimRatio = [...pages].reduce((minRatio, page)=>Math.min(minRatio, iframeWidth / page.offsetWidth, iframeHeight / page.offsetHeight), Infinity); + let minDimRatio; + if(displayOptions.spread === 'single') + minDimRatio = [...pages].reduce( + (minRatio, page)=>Math.min(minRatio, + iframeWidth / page.offsetWidth, + iframeHeight / page.offsetHeight + ), + Infinity + ); + else + minDimRatio = [...pages].reduce( + (minRatio, page)=>Math.min(minRatio, + iframeWidth / ((page.offsetWidth * 2) + parseInt(displayOptions.columnGap)), + iframeHeight / page.offsetHeight + ), + Infinity + ); desiredZoom = minDimRatio * 100; } const margin = 5; // extra space so page isn't edge to edge (not truly "to fill") - const deltaZoom = (desiredZoom - zoomLevel) - margin; + const deltaZoom = (desiredZoom - displayOptions.zoomLevel) - margin; return deltaZoom; }; return ( -
    - +