0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2026-01-24 05:33:02 +00:00

Compare commits

..

363 Commits

Author SHA1 Message Date
Charlie Humphreys
e8b427ea21 fix a few issues 2023-07-18 22:13:40 -05:00
Charlie Humphreys
379f260de5 add color-selector component and colorings 2023-07-17 00:46:55 -05:00
Charlie Humphreys
46f413c656 update pill margin for snippet fields 2023-07-16 12:59:30 -05:00
Charlie Humphreys
77b0e93dd3 add more image snippets and other snippets 2023-07-16 12:35:08 -05:00
Charlie Humphreys
1b2d8d46a6 delete field component 2023-07-16 02:16:16 -05:00
Charlie Humphreys
62aae96012 Merge branch 'editor-widgets' of github.com:naturalcrit/homebrewery into editor-widgets 2023-07-16 02:15:17 -05:00
Charlie Humphreys
bef6b94dc4 add image selector field type, modal component, and new snippet widgets 2023-07-16 02:14:43 -05:00
Trevor Buckner
c113b8dd1f Merge branch 'editor-widgets' of https://github.com/naturalcrit/homebrewery into editor-widgets 2023-07-16 01:53:24 -04:00
Charlie Humphreys
e6055bd417 add support for function values 2023-07-15 01:05:41 -05:00
Charlie Humphreys
4c087e9aa5 refactor CodeMirror library instantiation 2023-07-15 01:05:41 -05:00
Charlie Humphreys
9d6a9c4ebf update component/key names 2023-07-15 01:05:41 -05:00
Charlie Humphreys
18c94f95f3 adjust field/checkbox styles 2023-07-15 01:05:41 -05:00
Charlie Humphreys
23f2f1f53b update based on feedback 2023-07-15 01:05:41 -05:00
Trevor Buckner
d044229b49 clean up codeEditor 2023-07-15 01:05:41 -05:00
Trevor Buckner
8e40cec051 tweak cClass logic 2023-07-15 01:05:41 -05:00
Trevor Buckner
ebbf0ca88b Simplify click-outside close widget logic 2023-07-15 01:05:41 -05:00
Charlie Humphreys
51760e02e7 fix ref issues and remove unneeded value 2023-07-15 01:05:41 -05:00
Charlie Humphreys
f52d42bef5 update widgets - add hints component and adjust autocomplete logic 2023-07-15 01:05:41 -05:00
Charlie Humphreys
3af5d27e3e add the concept of widgets and widget fields 2023-07-15 01:05:41 -05:00
Trevor Buckner
9d64740678 Merge pull request #2931 from naturalcrit/dependabot/npm_and_yarn/stylelint-config-recess-order-4.3.0
Bump stylelint-config-recess-order from 4.2.0 to 4.3.0
2023-07-10 23:52:35 -04:00
dependabot[bot]
053aadeff4 Bump stylelint-config-recess-order from 4.2.0 to 4.3.0
Bumps [stylelint-config-recess-order](https://github.com/stormwarning/stylelint-config-recess-order) from 4.2.0 to 4.3.0.
- [Release notes](https://github.com/stormwarning/stylelint-config-recess-order/releases)
- [Changelog](https://github.com/stormwarning/stylelint-config-recess-order/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stormwarning/stylelint-config-recess-order/compare/v4.2.0...v4.3.0)

---
updated-dependencies:
- dependency-name: stylelint-config-recess-order
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-11 03:45:53 +00:00
Trevor Buckner
d3763beb15 Merge pull request #2927 from naturalcrit/dependabot/npm_and_yarn/marked-5.1.1
Bump marked from 5.1.0 to 5.1.1
2023-07-10 22:23:20 -04:00
Trevor Buckner
8281051797 Merge pull request #2928 from naturalcrit/dependabot/npm_and_yarn/stylelint-stylistic-0.4.3
Bump stylelint-stylistic from 0.4.2 to 0.4.3
2023-07-10 22:23:12 -04:00
Trevor Buckner
5b0104fc10 Merge pull request #2929 from naturalcrit/dependabot/npm_and_yarn/semver-5.7.2
Bump semver from 5.7.1 to 5.7.2
2023-07-10 19:45:54 -04:00
dependabot[bot]
b3fa902d85 Bump semver from 5.7.1 to 5.7.2
Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 5.7.2.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-10 23:38:16 +00:00
dependabot[bot]
a22d223927 Bump stylelint-stylistic from 0.4.2 to 0.4.3
Bumps [stylelint-stylistic](https://github.com/elirasza/stylelint-stylistic) from 0.4.2 to 0.4.3.
- [Commits](https://github.com/elirasza/stylelint-stylistic/compare/0.4.2...0.4.3)

---
updated-dependencies:
- dependency-name: stylelint-stylistic
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-10 03:07:34 +00:00
dependabot[bot]
5c08926576 Bump marked from 5.1.0 to 5.1.1
Bumps [marked](https://github.com/markedjs/marked) from 5.1.0 to 5.1.1.
- [Release notes](https://github.com/markedjs/marked/releases)
- [Changelog](https://github.com/markedjs/marked/blob/master/.releaserc.json)
- [Commits](https://github.com/markedjs/marked/compare/v5.1.0...v5.1.1)

---
updated-dependencies:
- dependency-name: marked
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-10 03:07:24 +00:00
Trevor Buckner
797ca7e64e Merge pull request #2543 from naturalcrit/dependabot/npm_and_yarn/react-and-react-dom-18.2.0
Bump react and react-dom
2023-07-08 02:53:15 -04:00
dependabot[bot]
5b8f2d8e3c Bump react and react-dom
Bumps [react](https://github.com/facebook/react/tree/HEAD/packages/react) and [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom). These dependencies needed to be updated together.

Updates `react` from 17.0.2 to 18.2.0
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v18.2.0/packages/react)

Updates `react-dom` from 17.0.2 to 18.2.0
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v18.2.0/packages/react-dom)

---
updated-dependencies:
- dependency-name: react
  dependency-type: direct:production
  update-type: version-update:semver-major
- dependency-name: react-dom
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-08 06:31:42 +00:00
Trevor Buckner
bd0ef5da48 Merge pull request #2406 from G-Ambatte/addStyleSanitization-#1437
Add sanitization of Style content
2023-07-08 02:23:56 -04:00
Trevor Buckner
fe324d6822 Merge pull request #2417 from G-Ambatte/addSmartPageBreak-#2289
Add smarter footer shortcut/snippet
2023-07-08 02:17:37 -04:00
Trevor Buckner
3140299d73 Renderer is always V3. No need to check. 2023-07-08 01:48:49 -04:00
Trevor Buckner
96d04ad75a Fix TOC generators 2023-07-08 01:43:08 -04:00
Trevor Buckner
62532f788e Remove extra param sent to execute() 2023-07-08 01:42:47 -04:00
Trevor Buckner
69a3d04bb7 Merge branch 'master' into pr/2417 2023-07-08 01:11:45 -04:00
Trevor Buckner
21017e45fe Merge pull request #2901 from G-Ambatte/experimentalClickToOpen-#2702
Change dropdowns to stay open when clicked
2023-07-07 20:46:05 -04:00
Trevor Buckner
48474c6f7b Simplify dropdown & convert to Functional Component 2023-07-07 20:38:56 -04:00
Trevor Buckner
3d318f8863 Merge pull request #2926 from naturalcrit/dependabot/npm_and_yarn/jest-29.6.1
Bump jest from 29.6.0 to 29.6.1
2023-07-06 23:21:52 -04:00
Trevor Buckner
2b798f4ecb Merge pull request #2925 from naturalcrit/dependabot/npm_and_yarn/babel/plugin-transform-runtime-7.22.7
Bump @babel/plugin-transform-runtime from 7.22.6 to 7.22.7
2023-07-06 23:21:43 -04:00
Trevor Buckner
938802e1a3 Merge pull request #2924 from naturalcrit/dependabot/npm_and_yarn/mongoose-7.3.2
Bump mongoose from 7.3.1 to 7.3.2
2023-07-06 23:21:32 -04:00
Trevor Buckner
14f825f3b5 Merge pull request #2923 from naturalcrit/dependabot/npm_and_yarn/stylelint-15.10.1
Bump stylelint from 15.10.0 to 15.10.1
2023-07-06 23:21:03 -04:00
dependabot[bot]
37241a70eb Bump jest from 29.6.0 to 29.6.1
Bumps [jest](https://github.com/facebook/jest/tree/HEAD/packages/jest) from 29.6.0 to 29.6.1.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v29.6.1/packages/jest)

---
updated-dependencies:
- dependency-name: jest
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-07 03:08:55 +00:00
dependabot[bot]
bcd86a7f0c Bump @babel/plugin-transform-runtime from 7.22.6 to 7.22.7
Bumps [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-runtime) from 7.22.6 to 7.22.7.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.22.7/packages/babel-plugin-transform-runtime)

---
updated-dependencies:
- dependency-name: "@babel/plugin-transform-runtime"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-07 03:08:33 +00:00
dependabot[bot]
cf54594a4c Bump mongoose from 7.3.1 to 7.3.2
Bumps [mongoose](https://github.com/Automattic/mongoose) from 7.3.1 to 7.3.2.
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Automattic/mongoose/compare/7.3.1...7.3.2)

---
updated-dependencies:
- dependency-name: mongoose
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-07 03:08:12 +00:00
dependabot[bot]
535fdeaf62 Bump stylelint from 15.10.0 to 15.10.1
Bumps [stylelint](https://github.com/stylelint/stylelint) from 15.10.0 to 15.10.1.
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint/compare/15.10.0...15.10.1)

---
updated-dependencies:
- dependency-name: stylelint
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-07 03:07:59 +00:00
Trevor Buckner
77bf1b5258 Merge pull request #2922 from naturalcrit/dependabot/npm_and_yarn/babel/core-7.22.8
Bump @babel/core from 7.22.5 to 7.22.8
2023-07-06 14:41:49 -04:00
Trevor Buckner
63da418b60 Merge pull request #2921 from naturalcrit/dependabot/npm_and_yarn/babel/preset-env-7.22.7
Bump @babel/preset-env from 7.22.5 to 7.22.7
2023-07-06 14:41:40 -04:00
dependabot[bot]
67f5e53160 Bump @babel/core from 7.22.5 to 7.22.8
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.22.5 to 7.22.8.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.22.8/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-06 18:41:20 +00:00
dependabot[bot]
c6103d51c5 Bump @babel/preset-env from 7.22.5 to 7.22.7
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.22.5 to 7.22.7.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.22.7/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-06 18:41:14 +00:00
Trevor Buckner
a4a10783f6 Merge pull request #2915 from naturalcrit/dependabot/npm_and_yarn/stylelint-config-recommended-13.0.0
Bump stylelint-config-recommended from 12.0.0 to 13.0.0
2023-07-06 14:41:05 -04:00
Trevor Buckner
5ed53f75c5 Merge pull request #2912 from naturalcrit/dependabot/npm_and_yarn/jest-29.6.0
Bump jest from 29.5.0 to 29.6.0
2023-07-06 14:40:38 -04:00
Trevor Buckner
81b289923a Merge pull request #2911 from naturalcrit/dependabot/npm_and_yarn/babel/plugin-transform-runtime-7.22.6
Bump @babel/plugin-transform-runtime from 7.22.5 to 7.22.6
2023-07-06 14:40:30 -04:00
Trevor Buckner
c3d8364789 Merge pull request #2910 from naturalcrit/dependabot/npm_and_yarn/stylelint-15.10.0
Bump stylelint from 15.9.0 to 15.10.0
2023-07-06 14:40:24 -04:00
Trevor Buckner
82fec9901d Merge pull request #2916 from naturalcrit/dependabot/npm_and_yarn/npm-9.8.0
Bump npm from 9.7.2 to 9.8.0
2023-07-06 14:40:16 -04:00
Trevor Buckner
173d0a726b restore livereload
It might work after all. Takes some fiddling.
2023-07-06 00:55:00 -04:00
Trevor Buckner
e064219ca0 Merge pull request #2919 from naturalcrit/FixNodemonbehavior
Fix Nodemon config in `buildHomebrew.js`
2023-07-06 00:33:27 -04:00
Trevor Buckner
ec339f2717 Fix Nodemon config 2023-07-06 00:29:45 -04:00
Trevor Buckner
d9d27808a8 Merge pull request #2918 from naturalcrit/FixGoogleLinksWith10-charShareId
Fix google links with10 char shareid
2023-07-06 00:29:08 -04:00
Trevor Buckner
a4584dc78e Fix spec tests 2023-07-06 00:19:23 -04:00
Trevor Buckner
6344eaa17d Handle Old Google Drive links that used 10-char shareID
When the Homebrewery was first made, editIds and ShareIds only had 10 characters. We later increased this to 12.

However this means some old, old Google Drive links (in the form of `googleId + editId`) were being split incorrectly because they assumed the newer 12-char length, accidentally cutting the last 2 chars from the googleId.
2023-07-06 00:10:07 -04:00
dependabot[bot]
5c41110e50 Bump npm from 9.7.2 to 9.8.0
Bumps [npm](https://github.com/npm/cli) from 9.7.2 to 9.8.0.
- [Release notes](https://github.com/npm/cli/releases)
- [Changelog](https://github.com/npm/cli/blob/latest/CHANGELOG.md)
- [Commits](https://github.com/npm/cli/compare/v9.7.2...v9.8.0)

---
updated-dependencies:
- dependency-name: npm
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-06 03:11:38 +00:00
G.Ambatte
085cb99562 Merge branch 'master' into addStyleSanitization-#1437 2023-07-06 12:41:14 +12:00
G.Ambatte
568586541a Merge branch 'master' into addSmartPageBreak-#2289 2023-07-06 12:40:05 +12:00
G.Ambatte
0d44e1778f Emit click event when iFrame clicked 2023-07-05 15:48:54 +12:00
dependabot[bot]
4a5269e1f3 Bump stylelint-config-recommended from 12.0.0 to 13.0.0
Bumps [stylelint-config-recommended](https://github.com/stylelint/stylelint-config-recommended) from 12.0.0 to 13.0.0.
- [Release notes](https://github.com/stylelint/stylelint-config-recommended/releases)
- [Changelog](https://github.com/stylelint/stylelint-config-recommended/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint-config-recommended/compare/12.0.0...13.0.0)

---
updated-dependencies:
- dependency-name: stylelint-config-recommended
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-05 03:33:11 +00:00
dependabot[bot]
62cf0a4483 Bump jest from 29.5.0 to 29.6.0
Bumps [jest](https://github.com/facebook/jest/tree/HEAD/packages/jest) from 29.5.0 to 29.6.0.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v29.6.0/packages/jest)

---
updated-dependencies:
- dependency-name: jest
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-05 03:32:27 +00:00
dependabot[bot]
07c7352aa2 Bump @babel/plugin-transform-runtime from 7.22.5 to 7.22.6
Bumps [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-runtime) from 7.22.5 to 7.22.6.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.22.6/packages/babel-plugin-transform-runtime)

---
updated-dependencies:
- dependency-name: "@babel/plugin-transform-runtime"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-05 03:32:05 +00:00
dependabot[bot]
cf6c8bce88 Bump stylelint from 15.9.0 to 15.10.0
Bumps [stylelint](https://github.com/stylelint/stylelint) from 15.9.0 to 15.10.0.
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint/compare/15.9.0...15.10.0)

---
updated-dependencies:
- dependency-name: stylelint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-05 03:31:53 +00:00
G.Ambatte
45d32ebfc3 Merge branch 'master' into experimentalClickToOpen-#2702 2023-07-05 14:24:24 +12:00
Charlie
314275122d Merge pull request #2907 from naturalcrit/CleanCodeEditor.jsx
[Widgets] clean up codeEditor
2023-07-04 12:03:52 -05:00
Charlie
5716e4fcfd Merge pull request #2908 from naturalcrit/tweak-cClass-logic
[Widgets] Tweak cClass logic
2023-07-04 12:02:11 -05:00
Trevor Buckner
b9aaee43c2 tweak cClass logic 2023-07-04 03:31:21 -04:00
Trevor Buckner
35a74b3e46 clean up codeEditor 2023-07-03 17:16:29 -04:00
Charlie
f4fe08f8fd Merge pull request #2906 from naturalcrit/SimplifyMouseclickToggle 2023-07-03 15:58:47 -05:00
Trevor Buckner
65c0c81984 Merge branch 'master' into editor-widgets 2023-07-03 16:35:41 -04:00
Trevor Buckner
84496f51ba Merge pull request #2904 from naturalcrit/dependabot/npm_and_yarn/react-router-dom-6.14.1
Bump react-router-dom from 6.14.0 to 6.14.1
2023-07-03 15:48:45 -04:00
Trevor Buckner
4cf659e711 Merge pull request #2903 from naturalcrit/dependabot/npm_and_yarn/eslint-8.44.0
Bump eslint from 8.43.0 to 8.44.0
2023-07-03 15:48:38 -04:00
Trevor Buckner
712f0309e9 Simplify click-outside close widget logic 2023-07-03 15:27:18 -04:00
dependabot[bot]
e0bfef5231 Bump react-router-dom from 6.14.0 to 6.14.1
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.14.0 to 6.14.1.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.14.1/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-03 03:25:11 +00:00
dependabot[bot]
afb6962407 Bump eslint from 8.43.0 to 8.44.0
Bumps [eslint](https://github.com/eslint/eslint) from 8.43.0 to 8.44.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.43.0...v8.44.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-03 03:24:46 +00:00
Charlie Humphreys
b7be2d6463 fix ref issues and remove unneeded value 2023-06-30 00:37:20 -05:00
Charlie Humphreys
47c84d9f01 update widgets - add hints component and adjust autocomplete logic 2023-06-30 00:18:23 -05:00
Trevor Buckner
8d2945ee5c Fix changelog.md typos 2023-06-29 20:25:57 -04:00
G.Ambatte
1dad009298 Merge branch 'experimentalClickToOpen-#2702' of https://github.com/G-Ambatte/homebrewery into experimentalClickToOpen-#2702 2023-06-30 07:57:38 +12:00
G.Ambatte
aadf663623 Add scrollbar on dropdowns 2023-06-30 07:57:33 +12:00
G.Ambatte
8685f32b49 Merge branch 'master' into experimentalClickToOpen-#2702 2023-06-30 00:03:35 +12:00
G.Ambatte
678ac90cd0 Shift Recent Items to use Nav.dropdown 2023-06-29 23:58:52 +12:00
G.Ambatte
3cb5e8ed42 Initial functionality pass 2023-06-29 21:59:42 +12:00
G.Ambatte
273f0ca05d Merge branch 'master' into addStyleSanitization-#1437 2023-06-29 13:26:21 +12:00
G.Ambatte
3c929870cb Merge branch 'master' into addSmartPageBreak-#2289 2023-06-29 13:25:11 +12:00
Trevor Buckner
36df5a3212 Merge pull request #2899 from naturalcrit/v3.9.1
Up version to v3.9.1
2023-06-28 16:13:14 -04:00
Trevor Buckner
cea5f2e43a Up version to v3.9.1 2023-06-28 16:13:01 -04:00
Trevor Buckner
046845885d Merge pull request #2892 from G-Ambatte/experimentalErrorPage
Basic ErrorPage functionality
2023-06-28 16:05:23 -04:00
G.Ambatte
9713cc4be9 Merge branch 'master' into experimentalErrorPage 2023-06-27 15:35:28 +12:00
Trevor Buckner
8baf0fc849 Add additional test for when logged in, but not in author list 2023-06-26 23:26:59 -04:00
Sean Robertson
a7040e554a Fix test 2023-06-27 15:19:33 +12:00
Trevor Buckner
ba43055f32 another text tweak 2023-06-26 23:14:08 -04:00
Trevor Buckner
d0de7ca28c Rephrasing of error texts 2023-06-26 22:48:58 -04:00
Trevor Buckner
c0164dce6a Fix for username undefined (not logged in) 2023-06-26 17:02:28 -04:00
Trevor Buckner
9e2b8477a8 Merge pull request #2898 from naturalcrit/dependabot/npm_and_yarn/react-router-dom-6.14.0
Bump react-router-dom from 6.13.0 to 6.14.0
2023-06-26 16:44:09 -04:00
Trevor Buckner
5a32ae5cd4 Merge pull request #2897 from naturalcrit/dependabot/npm_and_yarn/stylelint-15.9.0
Bump stylelint from 15.8.0 to 15.9.0
2023-06-26 16:44:00 -04:00
G.Ambatte
e88e7f852c Add account check to Google File not found error 2023-06-26 20:40:11 +12:00
G.Ambatte
a3b2c6987f Fix test 2023-06-26 18:08:52 +12:00
G.Ambatte
3d47b5a0bc Fix test 2023-06-26 18:06:37 +12:00
G.Ambatte
c5f4793c23 Add owner info to missing Google file message 2023-06-26 17:43:19 +12:00
dependabot[bot]
10e14bfcfd Bump react-router-dom from 6.13.0 to 6.14.0
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.13.0 to 6.14.0.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/react-router-dom@6.14.0/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.14.0/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-26 03:57:17 +00:00
dependabot[bot]
f3c36ffb0a Bump stylelint from 15.8.0 to 15.9.0
Bumps [stylelint](https://github.com/stylelint/stylelint) from 15.8.0 to 15.9.0.
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint/compare/15.8.0...15.9.0)

---
updated-dependencies:
- dependency-name: stylelint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-26 03:56:53 +00:00
G.Ambatte
cff4f8eae5 Catch duplicate delete requests 2023-06-25 21:26:02 +12:00
G.Ambatte
4799e8b443 Fix test 2023-06-25 21:10:28 +12:00
G.Ambatte
fa38d5c892 Additional info in errors 2023-06-25 20:39:36 +12:00
G.Ambatte
04eb7d0556 Add brew title to Not an Author page 2023-06-25 20:13:13 +12:00
G.Ambatte
f175323221 Use common error object to reduce DRY 2023-06-25 18:22:22 +12:00
G.Ambatte
9f4de3c66e Fix test 2023-06-25 18:16:57 +12:00
G.Ambatte
800bff611a Fix test 2023-06-25 18:14:12 +12:00
G.Ambatte
e28b6e7a19 Differentiate Not an Author from Not logged in 2023-06-25 18:10:31 +12:00
G.Ambatte
4c6de90d82 Fix test 2023-06-25 17:13:37 +12:00
G.Ambatte
e5ef0aedd3 Pass all error properties to message generator 2023-06-25 17:10:25 +12:00
G.Ambatte
da8e7ec610 Change Not an Author to 401 2023-06-25 16:51:17 +12:00
G.Ambatte
d1412abe03 Increase specificity of ErrorPage.less 2023-06-25 16:48:50 +12:00
G.Ambatte
9de4a82977 Remove unneeded HR 2023-06-25 15:24:10 +12:00
G.Ambatte
9ddae7bbea Update UIPage.less to increase specificity 2023-06-25 15:23:58 +12:00
G.Ambatte
4fdc6b79ea Use Less var to not break server build process 2023-06-25 15:11:12 +12:00
G.Ambatte
0001cf16d9 Change UIPage width calculation 2023-06-25 15:00:10 +12:00
G.Ambatte
438cb7f26d Fix test 2023-06-25 14:41:15 +12:00
G.Ambatte
ffa240f78d Fix test 2023-06-25 14:39:42 +12:00
G.Ambatte
782aa8e658 Increase ESLint max lines in app.js 2023-06-25 14:23:14 +12:00
G.Ambatte
7efe8964f1 Change throw method, update HBErrors 2023-06-25 14:21:35 +12:00
G.Ambatte
853515e09e Switch Error gen from spread operator to func 2023-06-25 12:56:22 +12:00
Trevor Buckner
f6c5354ce0 Add support for custom HBErrorCodes 2023-06-24 02:57:03 -04:00
Trevor Buckner
6353341738 styleLint 2023-06-24 01:50:57 -04:00
Trevor Buckner
66b9a792e7 Change Missing Google error text 2023-06-24 01:47:07 -04:00
Trevor Buckner
2775614eab Add styling to errorPage 2023-06-24 01:46:44 -04:00
Trevor Buckner
32229c6e6e Change json file to js so we can use multiline strings 2023-06-24 00:40:10 -04:00
Trevor Buckner
37c88b83f1 Don't redirect/use cookies. Just render page. 2023-06-23 17:24:31 -04:00
Trevor Buckner
2fa1b2bb8b Break out page rendering into function 2023-06-23 16:29:17 -04:00
G.Ambatte
949d763e35 Detect heading from Markdown Lexer tokens 2023-06-23 17:58:54 +12:00
G.Ambatte
46cb2e6b5b Merge branch 'master' into addStyleSanitization-#1437 2023-06-23 09:44:05 +12:00
G.Ambatte
e7224e97ef Merge branch 'master' into addSmartPageBreak-#2289 2023-06-23 09:43:24 +12:00
G.Ambatte
e07d53aa5f Merge branch 'master' into experimentalErrorPage 2023-06-23 09:42:04 +12:00
Trevor Buckner
1e004977be Merge pull request #2895 from naturalcrit/dependabot/npm_and_yarn/npm-9.7.2
Bump npm from 9.7.1 to 9.7.2
2023-06-22 15:29:24 -04:00
Trevor Buckner
9110e7cf7e Merge pull request #2894 from naturalcrit/dependabot/npm_and_yarn/mongoose-7.3.1
Bump mongoose from 7.3.0 to 7.3.1
2023-06-22 15:29:17 -04:00
dependabot[bot]
27e8b54528 Bump npm from 9.7.1 to 9.7.2
Bumps [npm](https://github.com/npm/cli) from 9.7.1 to 9.7.2.
- [Release notes](https://github.com/npm/cli/releases)
- [Changelog](https://github.com/npm/cli/blob/latest/CHANGELOG.md)
- [Commits](https://github.com/npm/cli/compare/v9.7.1...v9.7.2)

---
updated-dependencies:
- dependency-name: npm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-22 19:11:53 +00:00
dependabot[bot]
aa31919563 Bump mongoose from 7.3.0 to 7.3.1
Bumps [mongoose](https://github.com/Automattic/mongoose) from 7.3.0 to 7.3.1.
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Automattic/mongoose/compare/7.3.0...7.3.1)

---
updated-dependencies:
- dependency-name: mongoose
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-22 19:11:27 +00:00
Trevor Buckner
7bf3295fc2 Merge pull request #2893 from naturalcrit/dependabot/npm_and_yarn/eslint-plugin-jest-27.2.2
Bump eslint-plugin-jest from 27.2.1 to 27.2.2
2023-06-22 15:10:31 -04:00
dependabot[bot]
9fd3f47689 Bump eslint-plugin-jest from 27.2.1 to 27.2.2
Bumps [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) from 27.2.1 to 27.2.2.
- [Release notes](https://github.com/jest-community/eslint-plugin-jest/releases)
- [Changelog](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jest-community/eslint-plugin-jest/compare/v27.2.1...v27.2.2)

---
updated-dependencies:
- dependency-name: eslint-plugin-jest
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-22 18:33:26 +00:00
Trevor Buckner
0ca7e43d73 Merge pull request #2896 from naturalcrit/extractMarkedSmartypantsIntoPackage
extract smartypants into package
2023-06-22 14:32:01 -04:00
Trevor Buckner
b33b3cd49b extract smartypants into package 2023-06-22 14:31:14 -04:00
G.Ambatte
71c384ee0b Fix tests 2023-06-20 16:45:36 +12:00
G.Ambatte
546b8d5725 Merge branch 'experimentalErrorPage' of https://github.com/G-Ambatte/homebrewery into experimentalErrorPage 2023-06-20 13:45:04 +12:00
G.Ambatte
4d6ac2b142 Update ErrorPage to use basePage/UIPage 2023-06-20 13:45:01 +12:00
G.Ambatte
ce538ebbfd Add errorIndex.json 2023-06-20 13:44:41 +12:00
G.Ambatte
cf17e73dfa Merge branch 'master' into experimentalErrorPage 2023-06-20 11:20:02 +12:00
Trevor Buckner
69ef4d7653 Merge pull request #2888 from naturalcrit/dependabot/npm_and_yarn/react-router-dom-6.13.0
Bump react-router-dom from 6.12.1 to 6.13.0
2023-06-19 11:03:13 -04:00
Trevor Buckner
c98224f3e4 Merge pull request #2887 from naturalcrit/dependabot/npm_and_yarn/mongoose-7.3.0
Bump mongoose from 7.2.3 to 7.3.0
2023-06-19 11:03:03 -04:00
Trevor Buckner
4f870de68f Merge pull request #2891 from naturalcrit/dependabot/npm_and_yarn/eslint-8.43.0
Bump eslint from 8.42.0 to 8.43.0
2023-06-19 11:02:54 -04:00
Trevor Buckner
2cfee2e8ad Merge pull request #2890 from naturalcrit/dependabot/npm_and_yarn/stylelint-15.8.0
Bump stylelint from 15.7.0 to 15.8.0
2023-06-19 11:02:46 -04:00
G.Ambatte
9e1d53a30c Basic ErrorPage functionality 2023-06-19 21:06:38 +12:00
dependabot[bot]
1fe9f0c8d0 Bump eslint from 8.42.0 to 8.43.0
Bumps [eslint](https://github.com/eslint/eslint) from 8.42.0 to 8.43.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.42.0...v8.43.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-19 03:57:15 +00:00
dependabot[bot]
adc7233cab Bump stylelint from 15.7.0 to 15.8.0
Bumps [stylelint](https://github.com/stylelint/stylelint) from 15.7.0 to 15.8.0.
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint/compare/15.7.0...15.8.0)

---
updated-dependencies:
- dependency-name: stylelint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-19 03:56:34 +00:00
G.Ambatte
1b2fc746d3 Remove script check from basic Markdown tests 2023-06-17 22:45:09 +12:00
G.Ambatte
b472fc1115 Move script tag sanitization to BrewRenderer 2023-06-17 20:25:15 +12:00
G.Ambatte
a7a47afaae Merge branch 'master' into addStyleSanitization-#1437 2023-06-17 20:09:45 +12:00
dependabot[bot]
509c7d8832 Bump react-router-dom from 6.12.1 to 6.13.0
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.12.1 to 6.13.0.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.13.0/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-15 03:57:17 +00:00
dependabot[bot]
caff1d8e2b Bump mongoose from 7.2.3 to 7.3.0
Bumps [mongoose](https://github.com/Automattic/mongoose) from 7.2.3 to 7.3.0.
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Automattic/mongoose/compare/7.2.3...7.3.0)

---
updated-dependencies:
- dependency-name: mongoose
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-15 03:57:03 +00:00
G.Ambatte
e06f5e17d9 Relocate from 5ePHB to Blank theme 2023-06-15 13:42:10 +12:00
G.Ambatte
ade61971d0 Remove snippet.params 2023-06-15 11:50:38 +12:00
Trevor Buckner
6451d79d92 Merge branch 'master' into pr/2417 2023-06-12 22:26:10 -04:00
Trevor Buckner
9202f9c8eb Merge pull request #2881 from naturalcrit/dependabot/npm_and_yarn/marked-5.1.0
Bump marked from 5.0.5 to 5.1.0
2023-06-12 16:42:18 -04:00
Trevor Buckner
097cc220f8 Merge pull request #2882 from naturalcrit/dependabot/npm_and_yarn/mongoose-7.2.3
Bump mongoose from 7.2.2 to 7.2.3
2023-06-12 16:42:07 -04:00
dependabot[bot]
2e3c10c35b Bump mongoose from 7.2.2 to 7.2.3
Bumps [mongoose](https://github.com/Automattic/mongoose) from 7.2.2 to 7.2.3.
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Automattic/mongoose/compare/7.2.2...7.2.3)

---
updated-dependencies:
- dependency-name: mongoose
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-12 03:57:24 +00:00
dependabot[bot]
a5aeb7dccd Bump marked from 5.0.5 to 5.1.0
Bumps [marked](https://github.com/markedjs/marked) from 5.0.5 to 5.1.0.
- [Release notes](https://github.com/markedjs/marked/releases)
- [Changelog](https://github.com/markedjs/marked/blob/master/.releaserc.json)
- [Commits](https://github.com/markedjs/marked/compare/v5.0.5...v5.1.0)

---
updated-dependencies:
- dependency-name: marked
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-12 03:56:39 +00:00
Charlie Humphreys
b6d37dd825 add the concept of widgets and widget fields 2023-06-10 13:02:13 -05:00
Trevor Buckner
92ff776270 Merge pull request #2877 from naturalcrit/dependabot/npm_and_yarn/babel/plugin-transform-runtime-7.22.5
Bump @babel/plugin-transform-runtime from 7.22.4 to 7.22.5
2023-06-09 11:11:20 -04:00
dependabot[bot]
bf1fb97789 Bump @babel/plugin-transform-runtime from 7.22.4 to 7.22.5
Bumps [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-runtime) from 7.22.4 to 7.22.5.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.22.5/packages/babel-plugin-transform-runtime)

---
updated-dependencies:
- dependency-name: "@babel/plugin-transform-runtime"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-09 15:10:52 +00:00
Trevor Buckner
2cddc2debe Merge pull request #2876 from naturalcrit/dependabot/npm_and_yarn/babel/preset-env-7.22.5
Bump @babel/preset-env from 7.22.4 to 7.22.5
2023-06-09 11:09:42 -04:00
dependabot[bot]
0d4a1a11c1 Bump @babel/preset-env from 7.22.4 to 7.22.5
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.22.4 to 7.22.5.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.22.5/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-09 15:04:42 +00:00
Trevor Buckner
aa3cf1d9c1 Merge pull request #2875 from naturalcrit/dependabot/npm_and_yarn/babel/core-7.22.5
Bump @babel/core from 7.22.1 to 7.22.5
2023-06-09 11:02:39 -04:00
Trevor Buckner
5d0062f610 Merge pull request #2874 from naturalcrit/dependabot/npm_and_yarn/react-router-dom-6.12.1
Bump react-router-dom from 6.11.2 to 6.12.1
2023-06-09 11:02:28 -04:00
Trevor Buckner
7976917bb9 Merge pull request #2873 from naturalcrit/dependabot/npm_and_yarn/babel/preset-react-7.22.5
Bump @babel/preset-react from 7.22.3 to 7.22.5
2023-06-09 11:02:16 -04:00
Trevor Buckner
023071c874 Merge pull request #2869 from naturalcrit/dependabot/npm_and_yarn/stylelint-config-recess-order-4.2.0
Bump stylelint-config-recess-order from 4.0.0 to 4.2.0
2023-06-09 11:01:03 -04:00
dependabot[bot]
7da42d3742 Bump stylelint-config-recess-order from 4.0.0 to 4.2.0
Bumps [stylelint-config-recess-order](https://github.com/stormwarning/stylelint-config-recess-order) from 4.0.0 to 4.2.0.
- [Release notes](https://github.com/stormwarning/stylelint-config-recess-order/releases)
- [Changelog](https://github.com/stormwarning/stylelint-config-recess-order/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stormwarning/stylelint-config-recess-order/compare/v4.0.0...v4.2.0)

---
updated-dependencies:
- dependency-name: stylelint-config-recess-order
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-09 15:00:36 +00:00
Trevor Buckner
3269e94757 Merge pull request #2872 from naturalcrit/dependabot/npm_and_yarn/npm-9.7.1
Bump npm from 9.6.7 to 9.7.1
2023-06-09 10:59:26 -04:00
Trevor Buckner
c69f4289ed Merge pull request #2867 from naturalcrit/dependabot/npm_and_yarn/stylelint-15.7.0
Bump stylelint from 15.6.3 to 15.7.0
2023-06-09 10:59:13 -04:00
Trevor Buckner
8752a32626 Merge pull request #2863 from naturalcrit/dependabot/npm_and_yarn/marked-gfm-heading-id-3.0.4
Bump marked-gfm-heading-id from 3.0.3 to 3.0.4
2023-06-09 10:58:54 -04:00
Trevor Buckner
8735d1f222 Merge pull request #2862 from naturalcrit/dependabot/npm_and_yarn/eslint-8.42.0
Bump eslint from 8.41.0 to 8.42.0
2023-06-09 10:58:42 -04:00
Trevor Buckner
21929e676d Merge pull request #2871 from naturalcrit/dependabot/npm_and_yarn/marked-5.0.5
Bump marked from 5.0.4 to 5.0.5
2023-06-09 10:58:30 -04:00
dependabot[bot]
5ca61935a8 Bump @babel/core from 7.22.1 to 7.22.5
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.22.1 to 7.22.5.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.22.5/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-09 03:57:54 +00:00
dependabot[bot]
10143cec93 Bump react-router-dom from 6.11.2 to 6.12.1
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.11.2 to 6.12.1.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.12.1/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-09 03:57:22 +00:00
dependabot[bot]
643c8503c0 Bump @babel/preset-react from 7.22.3 to 7.22.5
Bumps [@babel/preset-react](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-react) from 7.22.3 to 7.22.5.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.22.5/packages/babel-preset-react)

---
updated-dependencies:
- dependency-name: "@babel/preset-react"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-09 03:57:04 +00:00
dependabot[bot]
e92d3ecd68 Bump npm from 9.6.7 to 9.7.1
Bumps [npm](https://github.com/npm/cli) from 9.6.7 to 9.7.1.
- [Release notes](https://github.com/npm/cli/releases)
- [Changelog](https://github.com/npm/cli/blob/latest/CHANGELOG.md)
- [Commits](https://github.com/npm/cli/compare/v9.6.7...v9.7.1)

---
updated-dependencies:
- dependency-name: npm
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-08 03:57:47 +00:00
dependabot[bot]
4f092828ac Bump marked from 5.0.4 to 5.0.5
Bumps [marked](https://github.com/markedjs/marked) from 5.0.4 to 5.0.5.
- [Release notes](https://github.com/markedjs/marked/releases)
- [Changelog](https://github.com/markedjs/marked/blob/master/.releaserc.json)
- [Commits](https://github.com/markedjs/marked/compare/v5.0.4...v5.0.5)

---
updated-dependencies:
- dependency-name: marked
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-08 03:57:08 +00:00
dependabot[bot]
2d4c211483 Bump stylelint from 15.6.3 to 15.7.0
Bumps [stylelint](https://github.com/stylelint/stylelint) from 15.6.3 to 15.7.0.
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint/compare/15.6.3...15.7.0)

---
updated-dependencies:
- dependency-name: stylelint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-06 03:56:50 +00:00
Trevor Buckner
7d30abc4d9 Merge pull request #2865 from G-Ambatte/bumpNodeInDocker-#2861
[Docker] - Bump Node from 16.13 to 18
2023-06-05 07:47:29 -04:00
G.Ambatte
1d513f7a0e Bump Node from 16.13 to 18 2023-06-05 20:33:46 +12:00
Trevor Buckner
44922f5261 Merge pull request #2860 from G-Ambatte/fixTestFailure-#2859
Fix test failure
2023-06-05 00:17:05 -04:00
dependabot[bot]
f695cc6948 Bump marked-gfm-heading-id from 3.0.3 to 3.0.4
Bumps [marked-gfm-heading-id](https://github.com/markedjs/marked-gfm-heading-id) from 3.0.3 to 3.0.4.
- [Release notes](https://github.com/markedjs/marked-gfm-heading-id/releases)
- [Changelog](https://github.com/markedjs/marked-gfm-heading-id/blob/main/release.config.cjs)
- [Commits](https://github.com/markedjs/marked-gfm-heading-id/compare/v3.0.3...v3.0.4)

---
updated-dependencies:
- dependency-name: marked-gfm-heading-id
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-05 04:13:33 +00:00
dependabot[bot]
3722387f1f Bump eslint from 8.41.0 to 8.42.0
Bumps [eslint](https://github.com/eslint/eslint) from 8.41.0 to 8.42.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.41.0...v8.42.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-05 04:13:30 +00:00
Trevor Buckner
8950cb944f Merge pull request #2864 from naturalcrit/dependabot/npm_and_yarn/stylelint-15.6.3
Bump stylelint from 15.6.2 to 15.6.3
2023-06-05 00:12:10 -04:00
dependabot[bot]
66fb70a5f8 Bump stylelint from 15.6.2 to 15.6.3
Bumps [stylelint](https://github.com/stylelint/stylelint) from 15.6.2 to 15.6.3.
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint/compare/15.6.2...15.6.3)

---
updated-dependencies:
- dependency-name: stylelint
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-05 03:57:36 +00:00
G.Ambatte
69c242425b Update test output 2023-06-03 14:20:45 +12:00
G.Ambatte
9093f610bd Add params from snippet to function 2023-06-03 14:09:50 +12:00
G.Ambatte
d2b2e69123 Shift Footer generation to snippet 2023-06-03 13:30:32 +12:00
G.Ambatte
052c255068 Lint fixes 2023-06-03 13:23:39 +12:00
G.Ambatte
e6ad8aefde Lint fix 2023-06-03 12:18:22 +12:00
G.Ambatte
43ae80e80d Merge branch 'master' into addSmartPageBreak-#2289 2023-06-03 12:16:18 +12:00
Trevor Buckner
e6e04ad21d Fix changelog.md typos 2023-06-02 17:48:01 -04:00
Trevor Buckner
7be6b913b0 Merge pull request #2858 from naturalcrit/v3.9.0
Up version to v3.9.0
2023-06-02 17:14:05 -04:00
Trevor Buckner
94b7c89252 Up version to v3.9.0 2023-06-02 17:13:45 -04:00
Trevor Buckner
c2e8967ed9 Merge pull request #2857 from naturalcrit/FixSlowSmartypants
Replace SmartyPants plugin with custom
2023-06-02 17:03:30 -04:00
Trevor Buckner
942fdb8095 Replace SmartyPants plugin with custom 2023-06-02 17:02:45 -04:00
Trevor Buckner
95873ac158 Update coverpage.gen.js 2023-06-02 15:01:03 -04:00
Trevor Buckner
3b4b0583cf Merge pull request #2856 from naturalcrit/dependabot/npm_and_yarn/marked-5.0.4
Bump marked from 4.3.0 to 5.0.4
2023-05-31 11:51:45 -04:00
Trevor Buckner
2c9e3d2f2f Update package-lock.json 2023-05-31 11:51:07 -04:00
Trevor Buckner
5fca0a77d3 Merge branch 'dependabot/npm_and_yarn/marked-5.0.4' of https://github.com/naturalcrit/homebrewery into dependabot/npm_and_yarn/marked-5.0.4 2023-05-31 11:50:43 -04:00
Trevor Buckner
2c73e59eb0 Remove deprecated options 2023-05-31 11:14:57 -04:00
Trevor Buckner
f5db5c7bf2 Merge pull request #2755 from 5e-Cleric/Index-snippet
Index Snippet - PHB
2023-05-31 09:33:21 -04:00
Trevor Buckner
37abc38426 Move snippet to "Text Editor" group 2023-05-31 09:33:01 -04:00
dependabot[bot]
855fabb89e Bump marked from 4.3.0 to 5.0.4
Bumps [marked](https://github.com/markedjs/marked) from 4.3.0 to 5.0.4.
- [Release notes](https://github.com/markedjs/marked/releases)
- [Changelog](https://github.com/markedjs/marked/blob/master/.releaserc.json)
- [Commits](https://github.com/markedjs/marked/compare/v4.3.0...v5.0.4)

---
updated-dependencies:
- dependency-name: marked
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-31 13:26:37 +00:00
Trevor Buckner
bc35490ba2 Merge pull request #2855 from naturalcrit/dependabot/npm_and_yarn/mongoose-7.2.2
Bump mongoose from 7.2.1 to 7.2.2
2023-05-31 09:25:20 -04:00
Trevor Buckner
8b5404606e Merge pull request #2854 from naturalcrit/dependabot/npm_and_yarn/babel/preset-env-7.22.4
Bump @babel/preset-env from 7.22.2 to 7.22.4
2023-05-31 09:25:11 -04:00
dependabot[bot]
c5d3605c11 Bump @babel/preset-env from 7.22.2 to 7.22.4
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.22.2 to 7.22.4.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.22.4/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-31 13:21:19 +00:00
Trevor Buckner
43ab292391 Merge pull request #2853 from naturalcrit/dependabot/npm_and_yarn/babel/plugin-transform-runtime-7.22.4
Bump @babel/plugin-transform-runtime from 7.22.2 to 7.22.4
2023-05-31 09:20:27 -04:00
dependabot[bot]
3ed9702ef2 Bump marked from 4.3.0 to 5.0.4
Bumps [marked](https://github.com/markedjs/marked) from 4.3.0 to 5.0.4.
- [Release notes](https://github.com/markedjs/marked/releases)
- [Changelog](https://github.com/markedjs/marked/blob/master/.releaserc.json)
- [Commits](https://github.com/markedjs/marked/compare/v4.3.0...v5.0.4)

---
updated-dependencies:
- dependency-name: marked
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-31 03:57:03 +00:00
dependabot[bot]
755b43179b Bump mongoose from 7.2.1 to 7.2.2
Bumps [mongoose](https://github.com/Automattic/mongoose) from 7.2.1 to 7.2.2.
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Automattic/mongoose/compare/7.2.1...7.2.2)

---
updated-dependencies:
- dependency-name: mongoose
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-31 03:56:45 +00:00
Trevor Buckner
66b827ee2f linting 2023-05-30 17:20:17 -04:00
Trevor Buckner
483a1c44ef Merge branch 'master' into pr/2755 2023-05-30 17:18:03 -04:00
Trevor Buckner
47680f07df Change to nested lists, shrink font to match PHB 2023-05-30 17:17:17 -04:00
dependabot[bot]
9e43986d24 Bump @babel/plugin-transform-runtime from 7.22.2 to 7.22.4
Bumps [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-runtime) from 7.22.2 to 7.22.4.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.22.4/packages/babel-plugin-transform-runtime)

---
updated-dependencies:
- dependency-name: "@babel/plugin-transform-runtime"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-30 03:56:54 +00:00
Trevor Buckner
7a198fe8b8 Merge pull request #2850 from naturalcrit/dependabot/npm_and_yarn/babel/plugin-transform-runtime-7.22.2
Bump @babel/plugin-transform-runtime from 7.21.4 to 7.22.2
2023-05-29 00:17:31 -04:00
dependabot[bot]
e3e5cb1dff Bump @babel/plugin-transform-runtime from 7.21.4 to 7.22.2
Bumps [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-runtime) from 7.21.4 to 7.22.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.22.2/packages/babel-plugin-transform-runtime)

---
updated-dependencies:
- dependency-name: "@babel/plugin-transform-runtime"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-29 04:16:23 +00:00
Trevor Buckner
f44ea92d4f Merge pull request #2851 from naturalcrit/dependabot/npm_and_yarn/babel/core-7.22.1
Bump @babel/core from 7.21.8 to 7.22.1
2023-05-29 00:15:32 -04:00
Trevor Buckner
5781b9d177 Merge pull request #2849 from naturalcrit/dependabot/npm_and_yarn/babel/preset-env-7.22.2
Bump @babel/preset-env from 7.21.5 to 7.22.2
2023-05-29 00:15:13 -04:00
dependabot[bot]
817539dfda Bump @babel/preset-env from 7.21.5 to 7.22.2
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.21.5 to 7.22.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.22.2/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-29 04:13:21 +00:00
dependabot[bot]
4e083aece8 Bump @babel/core from 7.21.8 to 7.22.1
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.21.8 to 7.22.1.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.22.1/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-29 04:13:19 +00:00
Trevor Buckner
27a12dfa79 Merge pull request #2852 from naturalcrit/dependabot/npm_and_yarn/babel/preset-react-7.22.3
Bump @babel/preset-react from 7.18.6 to 7.22.3
2023-05-29 00:07:31 -04:00
dependabot[bot]
3b5ebf8f60 Bump @babel/preset-react from 7.18.6 to 7.22.3
Bumps [@babel/preset-react](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-react) from 7.18.6 to 7.22.3.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.22.3/packages/babel-preset-react)

---
updated-dependencies:
- dependency-name: "@babel/preset-react"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-29 03:58:54 +00:00
Trevor Buckner
daea4419ff Merge pull request #2847 from naturalcrit/FixStylelint
Fix stylelint
2023-05-27 21:34:28 -04:00
Trevor Buckner
3b76a12505 merge with master 2023-05-27 14:11:36 -04:00
Trevor Buckner
dda3ba8215 Merge branch 'master' into FixStylelint 2023-05-27 13:59:17 -04:00
Trevor Buckner
6ea05d8ec2 Tweak rule order, rename custom plugin 2023-05-27 13:58:39 -04:00
Trevor Buckner
71ec9034b7 Change snippet to nested list 2023-05-26 17:17:56 -04:00
Trevor Buckner
86dce0ae24 Merge pull request #2845 from naturalcrit/dependabot/npm_and_yarn/mongoose-7.2.1
Bump mongoose from 7.2.0 to 7.2.1
2023-05-26 17:05:20 -04:00
Trevor Buckner
1ebdf318bf Add some "avoid errors" rules 2023-05-26 03:00:25 -04:00
Trevor Buckner
f05e0db14b Fix single-line detection rule. Linting. 2023-05-26 01:10:49 -04:00
dependabot[bot]
43fd6c451e Bump mongoose from 7.2.0 to 7.2.1
Bumps [mongoose](https://github.com/Automattic/mongoose) from 7.2.0 to 7.2.1.
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Automattic/mongoose/compare/7.2.0...7.2.1)

---
updated-dependencies:
- dependency-name: mongoose
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-25 03:56:41 +00:00
Trevor Buckner
e621f2d19b Merge pull request #2839 from naturalcrit/ChangeTabToSpaces
Custom function to use spaces for indent
2023-05-22 22:40:52 -04:00
Trevor Buckner
ca34ca499d Remove duplicate tabs 2023-05-22 22:40:18 -04:00
Trevor Buckner
0715e365f1 Merge pull request #2843 from Gazook89/StringArrayEditor-Unique-ID-Fix
Fix StringArrayEditor unique `key` error
2023-05-22 22:38:48 -04:00
Trevor Buckner
55d265069c Merge pull request #2844 from naturalcrit/FixNodemonWatchfileForBuildScript
Fix redundant build/ properly watch .less
2023-05-22 22:20:35 -04:00
Trevor Buckner
52ee7d9dbf Fix redundant build/ properly watch .less 2023-05-22 22:17:32 -04:00
Gazook89
d0346650c4 add key to <p> in notes 2023-05-22 14:19:23 -05:00
Trevor Buckner
96b26d72fd Merge pull request #2842 from naturalcrit/dependabot/npm_and_yarn/eslint-8.41.0
Bump eslint from 8.40.0 to 8.41.0
2023-05-22 00:02:57 -04:00
Trevor Buckner
d51757b8b9 Merge pull request #2841 from naturalcrit/dependabot/npm_and_yarn/mongoose-7.2.0
Bump mongoose from 7.1.2 to 7.2.0
2023-05-22 00:02:00 -04:00
dependabot[bot]
beccef2685 Bump eslint from 8.40.0 to 8.41.0
Bumps [eslint](https://github.com/eslint/eslint) from 8.40.0 to 8.41.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.40.0...v8.41.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-22 03:57:58 +00:00
dependabot[bot]
06f74c6b64 Bump mongoose from 7.1.2 to 7.2.0
Bumps [mongoose](https://github.com/Automattic/mongoose) from 7.1.2 to 7.2.0.
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Automattic/mongoose/compare/7.1.2...7.2.0)

---
updated-dependencies:
- dependency-name: mongoose
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-22 03:57:23 +00:00
Trevor Buckner
288b407e3e Turn off smartIndent 2023-05-20 01:32:07 -04:00
Trevor Buckner
57eea5c69f Custom function to use spaces for indent 2023-05-20 01:24:36 -04:00
Trevor Buckner
fbfb92735c Merge branch 'master' into pr/2755 2023-05-19 19:28:14 -04:00
Trevor Buckner
95376db055 Merge pull request #2838 from naturalcrit/dependabot/npm_and_yarn/mongoose-7.1.2
Bump mongoose from 7.1.1 to 7.1.2
2023-05-19 00:21:20 -04:00
Trevor Buckner
01d3ec9d58 Merge pull request #2837 from naturalcrit/dependabot/npm_and_yarn/npm-9.6.7
Bump npm from 9.6.6 to 9.6.7
2023-05-19 00:20:43 -04:00
dependabot[bot]
a1eb09225a Bump mongoose from 7.1.1 to 7.1.2
Bumps [mongoose](https://github.com/Automattic/mongoose) from 7.1.1 to 7.1.2.
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Automattic/mongoose/compare/7.1.1...7.1.2)

---
updated-dependencies:
- dependency-name: mongoose
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-19 03:57:46 +00:00
dependabot[bot]
5c2e2edbed Bump npm from 9.6.6 to 9.6.7
Bumps [npm](https://github.com/npm/cli) from 9.6.6 to 9.6.7.
- [Release notes](https://github.com/npm/cli/releases)
- [Changelog](https://github.com/npm/cli/blob/latest/CHANGELOG.md)
- [Commits](https://github.com/npm/cli/compare/v9.6.6...v9.6.7)

---
updated-dependencies:
- dependency-name: npm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-19 03:57:09 +00:00
Trevor Buckner
4bb7d143aa Merge pull request #2835 from naturalcrit/dependabot/npm_and_yarn/react-router-dom-6.11.2
Bump react-router-dom from 6.11.1 to 6.11.2
2023-05-18 00:07:42 -04:00
dependabot[bot]
f5cefc4db4 Bump react-router-dom from 6.11.1 to 6.11.2
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.11.1 to 6.11.2.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.11.2/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-18 03:56:49 +00:00
Trevor Buckner
efbde81853 typo 2023-05-17 21:36:29 -04:00
Trevor Buckner
69a18d365a Merge pull request #2828 from naturalcrit/dependabot/npm_and_yarn/mongoose-7.1.1
Bump mongoose from 7.1.0 to 7.1.1
2023-05-17 20:02:41 -04:00
dependabot[bot]
34e73ee69b Bump mongoose from 7.1.0 to 7.1.1
Bumps [mongoose](https://github.com/Automattic/mongoose) from 7.1.0 to 7.1.1.
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Automattic/mongoose/compare/7.1.0...7.1.1)

---
updated-dependencies:
- dependency-name: mongoose
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-17 23:35:01 +00:00
Trevor Buckner
ee1ee801a7 Merge pull request #2834 from naturalcrit/styleLint
Set up Stylelint and add custom plugins
2023-05-17 19:33:47 -04:00
Trevor Buckner
99d441d9ff command line options 2023-05-17 19:31:03 -04:00
Trevor Buckner
d2be324bb0 One more custom plugin 2023-05-17 19:30:50 -04:00
Trevor Buckner
6ceba54631 Fix merge conflict 2023-05-17 18:55:24 -04:00
Trevor Buckner
53e77718e1 Merge branch 'master' into styleLint 2023-05-17 18:54:14 -04:00
Trevor Buckner
0342dfed4c Merge pull request #2833 from naturalcrit/BumpToNode18
Bump node version to 18.16.x
2023-05-17 18:52:29 -04:00
Trevor Buckner
0864f4ced0 Bump node version to 18.16.x 2023-05-17 18:50:40 -04:00
Trevor Buckner
ebd729b78f Set up Stylelint and add custom plugins 2023-05-17 18:48:25 -04:00
Trevor Buckner
32454a3f12 Merge pull request #2711 from 5e-Cleric/back-cover-snippet
Back cover snippet
2023-05-13 23:03:37 -04:00
Trevor Buckner
9781c8e633 Add some randomness to the snippet 2023-05-13 23:01:53 -04:00
Trevor Buckner
8a2aacebeb Add white version of Naturalcrit logo 2023-05-13 22:45:00 -04:00
Trevor Buckner
5889c2f1e0 Tweak CSS sizes and spacing 2023-05-13 22:44:38 -04:00
Trevor Buckner
b135ce2ae9 compress and resize backgroundCover image 2023-05-13 22:36:32 -04:00
Trevor Buckner
8f2a114e1c Add wide version of NodestoCaps font 2023-05-13 22:30:06 -04:00
Trevor Buckner
11c8446c9c Merge pull request #2823 from naturalcrit/GoogleDriveQueryNextPage
Get next page if GDrive file listing is incomplete
2023-05-09 10:48:16 -04:00
Trevor Buckner
0e1b30eced Get next page if end of files not reached 2023-05-09 10:44:18 -04:00
Trevor Buckner
b8372ebdcc tweak snippet 2023-05-08 14:06:44 -04:00
Trevor Buckner
42fdb0ebb1 Fix build error 2023-05-08 14:06:28 -04:00
Trevor Buckner
b2ebf724f5 Merge pull request #2822 from naturalcrit/dependabot/npm_and_yarn/eslint-8.40.0
Bump eslint from 8.39.0 to 8.40.0
2023-05-08 13:50:55 -04:00
dependabot[bot]
a4bea1c3be Bump eslint from 8.39.0 to 8.40.0
Bumps [eslint](https://github.com/eslint/eslint) from 8.39.0 to 8.40.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.39.0...v8.40.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-08 03:57:06 +00:00
Trevor Buckner
c800195e95 Merge pull request #2819 from naturalcrit/dependabot/npm_and_yarn/marked-extended-tables-1.0.6
Bump marked-extended-tables from 1.0.5 to 1.0.6
2023-05-05 07:09:04 -04:00
dependabot[bot]
26ec222a33 Bump marked-extended-tables from 1.0.5 to 1.0.6
Bumps [marked-extended-tables](https://github.com/calculuschild/marked-extended-tables) from 1.0.5 to 1.0.6.
- [Release notes](https://github.com/calculuschild/marked-extended-tables/releases)
- [Changelog](https://github.com/calculuschild/marked-extended-tables/blob/main/release.config.cjs)
- [Commits](https://github.com/calculuschild/marked-extended-tables/commits/v1.0.6)

---
updated-dependencies:
- dependency-name: marked-extended-tables
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-05 03:56:42 +00:00
Trevor Buckner
618e594acf Merge pull request #2817 from naturalcrit/dependabot/npm_and_yarn/react-router-dom-6.11.1
Bump react-router-dom from 6.11.0 to 6.11.1
2023-05-04 14:38:41 -04:00
Trevor Buckner
dde500004d Merge pull request #2818 from naturalcrit/dependabot/npm_and_yarn/npm-9.6.6
Bump npm from 9.6.5 to 9.6.6
2023-05-04 13:46:55 -04:00
dependabot[bot]
1cf1750887 Bump npm from 9.6.5 to 9.6.6
Bumps [npm](https://github.com/npm/cli) from 9.6.5 to 9.6.6.
- [Release notes](https://github.com/npm/cli/releases)
- [Changelog](https://github.com/npm/cli/blob/latest/CHANGELOG.md)
- [Commits](https://github.com/npm/cli/compare/v9.6.5...v9.6.6)

---
updated-dependencies:
- dependency-name: npm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-04 03:57:00 +00:00
dependabot[bot]
cbf281f211 Bump react-router-dom from 6.11.0 to 6.11.1
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.11.0 to 6.11.1.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.11.1/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-04 03:56:31 +00:00
Trevor Buckner
34c73c3d09 Merge pull request #2811 from 5e-Cleric/text-color-change
correct highlight of .cm-comment elements in editor
2023-05-03 12:48:28 -04:00
Trevor Buckner
9d61fc85a0 Merge pull request #2814 from naturalcrit/dependabot/npm_and_yarn/googleapis/drive-5.1.0
Bump @googleapis/drive from 5.0.2 to 5.1.0
2023-05-03 12:47:57 -04:00
Trevor Buckner
6825bb3bac Merge pull request #2815 from naturalcrit/dependabot/npm_and_yarn/babel/core-7.21.8
Bump @babel/core from 7.21.5 to 7.21.8
2023-05-03 12:47:49 -04:00
dependabot[bot]
0cb96f6fe6 Bump @babel/core from 7.21.5 to 7.21.8
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.21.5 to 7.21.8.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.21.8/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-03 03:58:01 +00:00
dependabot[bot]
2b7e0c3fb8 Bump @googleapis/drive from 5.0.2 to 5.1.0
Bumps [@googleapis/drive](https://github.com/googleapis/google-api-nodejs-client) from 5.0.2 to 5.1.0.
- [Release notes](https://github.com/googleapis/google-api-nodejs-client/releases)
- [Changelog](https://github.com/googleapis/google-api-nodejs-client/blob/5.1.0/CHANGELOG.md)
- [Commits](https://github.com/googleapis/google-api-nodejs-client/compare/drive-v5.0.2...5.1.0)

---
updated-dependencies:
- dependency-name: "@googleapis/drive"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-03 03:57:05 +00:00
Victor Losada Hernandez
2cce7aebfc correct highlight of curly elements 2023-05-02 21:25:00 +02:00
Trevor Buckner
b5508b7a24 Merge pull request #2810 from naturalcrit/dependabot/npm_and_yarn/babel/preset-env-7.21.5
Bump @babel/preset-env from 7.21.4 to 7.21.5
2023-05-01 11:15:47 -04:00
dependabot[bot]
273dfdce40 Bump @babel/preset-env from 7.21.4 to 7.21.5
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.21.4 to 7.21.5.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.21.5/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-01 03:58:10 +00:00
Trevor Buckner
1848dc8182 Merge pull request #2808 from naturalcrit/dependabot/npm_and_yarn/babel/core-7.21.5
Bump @babel/core from 7.21.4 to 7.21.5
2023-04-30 23:58:02 -04:00
Trevor Buckner
6fd26a2d0b Merge pull request #2809 from naturalcrit/dependabot/npm_and_yarn/react-router-dom-6.11.0
Bump react-router-dom from 6.10.0 to 6.11.0
2023-04-30 23:57:48 -04:00
dependabot[bot]
528efc8b98 Bump react-router-dom from 6.10.0 to 6.11.0
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.10.0 to 6.11.0.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.11.0/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-01 03:57:04 +00:00
dependabot[bot]
ef50b1966b Bump @babel/core from 7.21.4 to 7.21.5
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.21.4 to 7.21.5.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.21.5/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-01 03:56:47 +00:00
Victor Losada Hernandez
2397f41b52 image change 2023-04-28 23:17:02 +02:00
Victor Losada Hernandez
5554ad9c26 engaging text 2023-04-28 23:13:33 +02:00
Victor Losada Hernandez
f5a07cac44 merge cover gen files 2023-04-28 23:07:02 +02:00
Victor Losada Hernandez
51dfd9a38c merging headache 2023-04-28 22:59:45 +02:00
Victor Losada Hernandez
11da8b1dac Merge master into back cover 2023-04-28 22:57:13 +02:00
Trevor Buckner
22aed68200 Merge branch 'master' into pr/2711 2023-04-28 16:56:49 -04:00
Trevor Buckner
1da329fb78 Merge pull request #2654 from 5e-Cleric/part-cover-snippet
Part cover - PHB + DMG
2023-04-28 16:52:29 -04:00
Trevor Buckner
d455e8c270 Add icon 2023-04-28 16:52:03 -04:00
Trevor Buckner
e235c705ae Move snippet to common CoverPage.gen 2023-04-28 16:51:53 -04:00
Trevor Buckner
f771e24788 Simplify CSS 2023-04-28 16:51:29 -04:00
Trevor Buckner
55941f0318 Merge branch 'master' into pr/2654 2023-04-28 15:39:12 -04:00
Trevor Buckner
ea38540e3b Merge pull request #2799 from naturalcrit/dependabot/npm_and_yarn/eslint-8.39.0
Bump eslint from 8.38.0 to 8.39.0
2023-04-28 15:06:10 -04:00
Trevor Buckner
1500ed071f Merge pull request #2807 from naturalcrit/dependabot/npm_and_yarn/mongoose-7.1.0
Bump mongoose from 7.0.4 to 7.1.0
2023-04-28 15:06:01 -04:00
Trevor Buckner
a568ab3b8a Merge pull request #2806 from G-Ambatte/fixFlyIn-#2790
Stop image movement in Image Masks
2023-04-28 15:05:51 -04:00
dependabot[bot]
3c8660442b Bump mongoose from 7.0.4 to 7.1.0
Bumps [mongoose](https://github.com/Automattic/mongoose) from 7.0.4 to 7.1.0.
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Automattic/mongoose/compare/7.0.4...7.1.0)

---
updated-dependencies:
- dependency-name: mongoose
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-28 03:56:59 +00:00
Trevor Buckner
2525fa2a53 Merge pull request #2805 from G-Ambatte/experimentalDockerBuildChanges-#2801
Dockerfile - Change to npm
2023-04-27 13:38:54 -04:00
G.Ambatte
3f7aff587c Remove transition rules from style.less 2023-04-27 21:23:55 +12:00
G.Ambatte
00dd030ee2 Change to npm from yarn 2023-04-27 17:54:30 +12:00
dependabot[bot]
a8179cae7b Bump eslint from 8.38.0 to 8.39.0
Bumps [eslint](https://github.com/eslint/eslint) from 8.38.0 to 8.39.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.38.0...v8.39.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-24 03:56:53 +00:00
Trevor Buckner
0425e61be2 Merge pull request #2794 from naturalcrit/dependabot/npm_and_yarn/npm-9.6.5
Bump npm from 9.6.4 to 9.6.5
2023-04-21 09:41:27 -04:00
dependabot[bot]
a2ebb025a2 Bump npm from 9.6.4 to 9.6.5
Bumps [npm](https://github.com/npm/cli) from 9.6.4 to 9.6.5.
- [Release notes](https://github.com/npm/cli/releases)
- [Changelog](https://github.com/npm/cli/blob/latest/CHANGELOG.md)
- [Commits](https://github.com/npm/cli/compare/v9.6.4...v9.6.5)

---
updated-dependencies:
- dependency-name: npm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-20 03:56:46 +00:00
Trevor Buckner
a43ea5abb9 Merge pull request #2792 from naturalcrit/dependabot/npm_and_yarn/mongoose-7.0.4
Bump mongoose from 7.0.3 to 7.0.4
2023-04-19 11:14:52 -04:00
Trevor Buckner
1ceb1dccca Merge pull request #2754 from 5e-Cleric/image-monster-block
Image Inside Blocks
2023-04-19 11:14:43 -04:00
Trevor Buckner
d375cdf10b Move rule to the ".block" section 2023-04-19 11:14:29 -04:00
dependabot[bot]
24639f1c29 Bump mongoose from 7.0.3 to 7.0.4
Bumps [mongoose](https://github.com/Automattic/mongoose) from 7.0.3 to 7.0.4.
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Automattic/mongoose/compare/7.0.3...7.0.4)

---
updated-dependencies:
- dependency-name: mongoose
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-18 03:57:16 +00:00
Trevor Buckner
62a9901676 Merge pull request #2788 from naturalcrit/TidyNavbarLess
Tidy NavBar Less
2023-04-17 16:18:14 -04:00
Trevor Buckner
c48dccb0d3 spaces to tabs 2023-04-17 16:16:47 -04:00
Victor Losada Hernandez
65c738d3b2 css cleanup 2023-04-15 21:37:00 +02:00
Victor Losada Hernandez
08ee142f6e Upstream master into back cover snippet 2023-04-13 23:08:30 +02:00
Trevor Buckner
891bf528cd Tidy NavBar Less 2023-04-12 17:35:18 -04:00
Trevor Buckner
45b7d7da88 Merge pull request #2785 from naturalcrit/v3.8.0
Update to v3.8.0
2023-04-12 16:13:58 -04:00
Victor Losada Hernandez
78ca5f5107 undo isolation, raising image z-index 2023-04-09 15:32:03 +02:00
Victor Losada Hernandez
d278c52571 Initial draft 2023-03-26 23:28:29 +02:00
Victor Losada Hernandez
1c38d30665 type error 2023-03-25 23:47:25 +01:00
Victor Losada Hernandez
ab058b31b1 icons 2023-03-25 22:56:45 +01:00
Victor Losada Hernandez
cdcd68bc92 upstream master into branch 2023-03-25 22:56:35 +01:00
Victor Losada Hernandez
2ed669d95e upstream master into part cover 2023-03-25 21:36:56 +01:00
Victor Losada Hernandez
5bce76bcba isolation stacking context 2023-03-25 19:28:32 +01:00
Victor Losada Hernandez
9870ff369e title variation included 2023-03-23 23:26:15 +01:00
Victor Losada Hernandez
d46736b7e6 update - DMG svg 2023-03-17 00:12:48 +01:00
Victor Losada Hernandez
810a5b295d actual icon 2023-03-01 17:40:15 +01:00
Victor Losada Hernandez
a956f57a56 delete fa-file-c 2023-03-01 17:11:00 +01:00
Victor Losada Hernandez
9b4577c65b Merge upstream 'master' into back-cover-snippet 2023-03-01 17:10:34 +01:00
Victor Losada Hernandez
a5a59ac058 initial draft 2023-03-01 17:04:21 +01:00
Victor Losada Hernandez
7df2d39a6d second markdown fix(sorry) 2023-02-28 22:32:07 +01:00
Victor Losada Hernandez
3cdb15ba79 fix mask 2023-02-28 22:30:45 +01:00
Victor Losada Hernandez
7c09956d7d last draft 2023-02-28 22:27:51 +01:00
Victor Losada Hernandez
63b088762e Merge upstream 'master' into part-cover-snippet 2023-02-28 22:27:37 +01:00
Victor Losada Hernandez
ac8c79ee63 unit change and has update 2023-02-25 22:39:25 +01:00
Victor Losada Hernandez
f7783aba07 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into part-cover-snippet 2023-02-04 17:23:40 +01:00
Victor Losada Hernandez
3380befe21 Diff mask for even/odd pages 2023-02-04 12:13:48 +01:00
Victor Losada Hernandez
14507c388e Merge branch 'master' of https://github.com/naturalcrit/homebrewery into part-cover-snippet 2023-02-04 11:53:04 +01:00
Victor Losada Hernandez
5cc654a908 Part cover first draft 2023-01-31 17:11:46 +01:00
G.Ambatte
c30eb9056a Break up text generation for legibility 2022-10-05 22:11:03 +13:00
G.Ambatte
ee3cd21486 Add to base snippets 2022-10-05 21:29:49 +13:00
G.Ambatte
5de63799c2 Update default footnote text 2022-10-05 21:20:39 +13:00
G.Ambatte
dfa8aea1ec Add newPageWithFooter function 2022-10-05 20:37:05 +13:00
G.Ambatte
8e26161244 Add sanitization of Style content 2022-09-28 17:27:11 +13:00
76 changed files with 20372 additions and 16707 deletions

View File

@@ -15,7 +15,7 @@ module.exports = {
rules : {
/** Errors **/
'camelcase' : ['error', { properties: 'never' }],
'func-style' : ['error', 'expression', { allowArrowFunctions: true }],
//'func-style' : ['error', 'expression', { allowArrowFunctions: true }],
'no-array-constructor' : 'error',
'no-iterator' : 'error',
'no-nested-ternary' : 'error',

48
.stylelintrc.json Normal file
View File

@@ -0,0 +1,48 @@
{
"extends": [
"stylelint-config-recess-order",
"stylelint-config-recommended"],
"plugins": [
"stylelint-stylistic",
"./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
}
}

View File

@@ -1,4 +1,4 @@
FROM node:16.13-alpine
FROM node:18-alpine
RUN apk --no-cache add git
ENV NODE_ENV=docker
@@ -10,11 +10,11 @@ WORKDIR /usr/src/app
# This improves caching so we don't have to download the dependencies every time the code changes
COPY package.json ./
# --ignore-scripts tells yarn not to run postbuild. We run it explicitly later
RUN yarn install --ignore-scripts
RUN npm install --ignore-scripts
# Bundle app source and build application
COPY . .
RUN yarn build
RUN npm run build
EXPOSE 8000
CMD [ "yarn", "start" ]
CMD [ "npm", "start" ]

View File

@@ -80,6 +80,50 @@ pre {
## changelog
For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery).
### 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)
}}
### Wednesday 12/04/2023 - v3.8.0
{{taskList
@@ -101,7 +145,7 @@ Fixes issue [#2595](https://github.com/naturalcrit/homebrewery/issues/2595)
Fixes issues [#2657](https://github.com/naturalcrit/homebrewery/issues/2657)
* [x] Fix internal links inside `<div>` blocks not receiving the `target=_self` attribute
* [x] Fix internal links inside `<\div>` blocks not receiving the `target=_self` attribute
Fixes issues [#2680](https://github.com/naturalcrit/homebrewery/issues/2680)
@@ -111,7 +155,7 @@ Fixes issues [#1679](https://github.com/naturalcrit/homebrewery/issues/1679)
* [x] Add local Windows install script via Chocolatey
##### 5e-Clerc
##### 5e-Cleric
* [x] New {{openSans **TABLES → {{fas,fa-language}} RUNE TABLE**}} snippets for V3. Adds an alphabetic script translation table.

View File

@@ -108,6 +108,12 @@ const BrewRenderer = createClass({
return false;
},
sanitizeScriptTags : function(content) {
return content
.replace(/<script/ig, '&lt;script')
.replace(/<\/script>/ig, '&lt;/script&gt;');
},
renderPageInfo : function(){
return <div className='pageInfo' ref='main'>
<div>
@@ -135,18 +141,20 @@ const BrewRenderer = createClass({
renderStyle : function() {
if(!this.props.style) return;
//return <div style={{ display: 'none' }} dangerouslySetInnerHTML={{ __html: `<style>@layer styleTab {\n${this.props.style}\n} </style>` }} />;
return <div style={{ display: 'none' }} dangerouslySetInnerHTML={{ __html: `<style>\n${this.props.style}\n</style>` }} />;
const cleanStyle = this.sanitizeScriptTags(this.props.style);
//return <div style={{ display: 'none' }} dangerouslySetInnerHTML={{ __html: `<style>@layer styleTab {\n${this.sanitizeScriptTags(this.props.style)}\n} </style>` }} />;
return <div style={{ display: 'none' }} dangerouslySetInnerHTML={{ __html: `<style> ${cleanStyle} </style>` }} />;
},
renderPage : function(pageText, index){
const cleanPageText = this.sanitizeScriptTags(pageText);
if(this.props.renderer == 'legacy')
return <div className='phb page' id={`p${index + 1}`} dangerouslySetInnerHTML={{ __html: MarkdownLegacy.render(pageText) }} key={index} />;
return <div className='phb page' id={`p${index + 1}`} dangerouslySetInnerHTML={{ __html: MarkdownLegacy.render(cleanPageText) }} key={index} />;
else {
pageText += `\n\n&nbsp;\n\\column\n&nbsp;`; //Artificial column break at page end to emulate column-fill:auto (until `wide` is used, when column-fill:balance will reappear)
return (
<div className='page' id={`p${index + 1}`} key={index} >
<div className='columnWrapper' dangerouslySetInnerHTML={{ __html: Markdown.render(pageText) }} />
<div className='columnWrapper' dangerouslySetInnerHTML={{ __html: Markdown.render(cleanPageText) }} />
</div>
);
}
@@ -185,6 +193,12 @@ const BrewRenderer = createClass({
}, 100);
},
emitClick : function(){
// console.log('iFrame clicked');
if(!window || !document) return;
document.dispatchEvent(new MouseEvent('click'));
},
render : function(){
//render in iFrame so broken code doesn't crash the site.
//Also render dummy page while iframe is mounting.
@@ -203,7 +217,9 @@ const BrewRenderer = createClass({
<Frame id='BrewRenderer' initialContent={this.state.initialContent}
style={{ width: '100%', height: '100%', visibility: this.state.visibility }}
contentDidMount={this.frameDidMount}>
contentDidMount={this.frameDidMount}
onClick={()=>{this.emitClick();}}
>
<div className={'brewRenderer'}
onScroll={this.handleScroll}
style={{ height: this.state.height }}>

View File

@@ -25,14 +25,13 @@ const NotificationPopup = createClass({
return (
<>
<li key='psa'>
<em>Broken <b>CoverPage</b> snippet</em> <br />
Those of you who have been trying out our Cover Page snippet may
notice that the cover page no longer displays correctly. Due to some
small tweaks of this BETA feature, the CSS class has been renamed
from "coverPage" to "frontCover". Simply change the text to "frontCover"
and it should again function as before. Remember that any snippet
marked "beta" may have a similar change in the future as we
encounter any bugs or reworks.
<em>Broken default logo on <b>CoverPage</b> </em> <br />
If you have used the Cover Page snippet and notice the Naturalcrit
logo is showing as a broken image, this is due to some small tweaks
of this BETA feature. To fix the logo in your cover page, rename
the image link <b>"/assets/naturalCritLogoRed.svg"</b>. Remember
that any snippet marked "BETA" may have a similar change in the
future as we encounter any bugs or reworks.
</li>
<li key='googleDriveFolder'>

View File

@@ -269,7 +269,7 @@ const Editor = createClass({
view={this.state.view}
value={this.props.brew.text}
onChange={this.props.onTextChange}
rerenderParent={this.rerenderParent} />
rerenderParent={this.rerenderParent}/>
</>;
}
if(this.isStyle()){
@@ -323,7 +323,8 @@ const Editor = createClass({
theme={this.props.brew.theme}
undo={this.undo}
redo={this.redo}
historySize={this.historySize()} />
historySize={this.historySize()}
cursorPos={this.refs.codeEditor?.getCursorPosition() || {}} />
{this.renderEditor()}
</div>

View File

@@ -19,17 +19,17 @@
background-color : fade(#299, 15%);
border-bottom : #299 solid 1px;
}
.block{
.block:not(.cm-comment){
color : purple;
font-weight : bold;
//font-style: italic;
}
.inline-block{
.inline-block:not(.cm-comment){
color : red;
font-weight : bold;
//font-style: italic;
}
.injection{
.injection:not(.cm-comment){
color : green;
font-weight : bold;
}

View File

@@ -15,8 +15,8 @@ ThemeSnippets['V3_5eDMG'] = require('themes/V3/5eDMG/snippets.js');
ThemeSnippets['V3_Journal'] = require('themes/V3/Journal/snippets.js');
ThemeSnippets['V3_Blank'] = require('themes/V3/Blank/snippets.js');
const execute = function(val, brew){
if(_.isFunction(val)) return val(brew);
const execute = function(val, props){
if(_.isFunction(val)) return val(props);
return val;
};
@@ -33,7 +33,8 @@ const Snippetbar = createClass({
renderer : 'legacy',
undo : ()=>{},
redo : ()=>{},
historySize : ()=>{}
historySize : ()=>{},
cursorPos : {}
};
},
@@ -105,6 +106,7 @@ const Snippetbar = createClass({
snippets={snippetGroup.snippets}
key={snippetGroup.groupName}
onSnippetClick={this.handleSnippetClick}
cursorPos={this.props.cursorPos}
/>;
});
},
@@ -165,7 +167,7 @@ const SnippetGroup = createClass({
},
handleSnippetClick : function(e, snippet){
e.stopPropagation();
this.props.onSnippetClick(execute(snippet.gen, this.props.brew));
this.props.onSnippetClick(execute(snippet.gen, this.props));
},
renderSnippets : function(snippets){
return _.map(snippets, (snippet)=>{

View File

@@ -140,7 +140,7 @@ const StringArrayEditor = createClass({
</div>
</div>
{this.props.notes ? this.props.notes.map((n)=><p><small>{n}</small></p>) : null}
{this.props.notes ? this.props.notes.map((n, index)=><p key={index}><small>{n}</small></p>) : null}
</div>
</div>;
}

View File

@@ -9,7 +9,7 @@ const EditPage = require('./pages/editPage/editPage.jsx');
const UserPage = require('./pages/userPage/userPage.jsx');
const SharePage = require('./pages/sharePage/sharePage.jsx');
const NewPage = require('./pages/newPage/newPage.jsx');
//const ErrorPage = require('./pages/errorPage/errorPage.jsx');
const ErrorPage = require('./pages/errorPage/errorPage.jsx');
const PrintPage = require('./pages/printPage/printPage.jsx');
const AccountPage = require('./pages/accountPage/accountPage.jsx');
@@ -78,6 +78,7 @@ const Homebrew = createClass({
<Route path='/faq' element={<WithRoute el={SharePage} brew={this.props.brew} />} />
<Route path='/account' element={<WithRoute el={AccountPage} brew={this.props.brew} uiItems={this.props.brew.uiItems} />} />
<Route path='/legacy' element={<WithRoute el={HomePage} brew={this.props.brew} />} />
<Route path='/error' element={<WithRoute el={ErrorPage} brew={this.props.brew} />} />
<Route path='/' element={<WithRoute el={HomePage} brew={this.props.brew} />} />
<Route path='/*' element={<WithRoute el={HomePage} brew={this.props.brew} />} />
</Routes>

View File

@@ -1,277 +1,272 @@
@import 'naturalcrit/styles/colors.less';
@navbarHeight : 28px;
@keyframes pinkColoring {
//from {color: white;}
//to {color: red;}
0% {color: pink;}
50% {color: pink;}
75% {color: red;}
100% {color: pink;}
}
.homebrew nav{
.homebrewLogo{
.animate(color);
font-family : CodeBold;
font-size : 12px;
color : white;
div{
margin-top : 2px;
margin-bottom : -2px;
}
&:hover{
color : @blue;
}
}
.editTitle.navItem{
padding : 2px 12px;
input{
width : 250px;
margin : 0;
padding : 2px;
background-color : transparent;
font-family : 'Open Sans', sans-serif;
font-size : 12px;
font-weight : 800;
color : white;
text-align : center;
border : 1px solid @blue;
outline : none;
}
.charCount{
display : inline-block;
vertical-align : bottom;
margin-left : 8px;
color : #666;
text-align : right;
&.max{
color : @red;
}
}
}
.brewTitle.navItem{
height: 100%;
font-size : 12px;
font-weight : 800;
color : white;
text-align : center;
text-transform : initial;
flex-grow : 1;
background-color: transparent;
}
.save-menu {
.dropdown {
z-index: 1000;
}
.navItem i.fa-power-off {
color : red;
&.active {
color : rgb(0, 182, 52);
filter : drop-shadow(0 0 2px rgba(0, 182, 52, 0.765))
}
}
}
.patreon.navItem{
border-left : 1px solid #666;
border-right : 1px solid #666;
&:hover i {
color: red;
}
i{
.animate(color);
animation-name: pinkColoring;
animation-duration: 2s;
color: pink;
}
}
.recent.navItem {
position : relative;
.dropdown{
position : absolute;
top : 28px;
left : 0px;
z-index : 10000;
width : 100%;
overflow : hidden auto;
max-height : ~"calc(100vh - 28px)";
scrollbar-color : #666 #333;
scrollbar-width : thin;
h4{
display : block;
box-sizing : border-box;
padding : 5px 0px;
background-color : #333;
font-size : 0.8em;
color : #bbb;
text-align : center;
border-top : 1px solid #888;
&:nth-of-type(1){ background-color: darken(@teal, 20%); }
&:nth-of-type(2){ background-color: darken(@purple, 30%); }
}
.item{
#backgroundColorsHover;
.animate(background-color);
position : relative;
display : block;
box-sizing : border-box;
padding : 8px 5px 13px;
background-color : #333;
color : white;
text-decoration : none;
border-top : 1px solid #888;
overflow : clip;
.clear{
display : none;
position : absolute;
top : 50%;
transform : translateY(-50%);
right : 0px;
width : 20px;
height : 100%;
background-color : #333;
opacity : 70%;
border-radius : 3px;
&:hover {
opacity : 100%;
}
i {
text-align : center;
font-size : 10px;
margin : 0;
height :100%;
width :100%;
}
}
&:hover{
background-color : @blue;
.clear{
display : grid;
place-content : center;
}
}
.title{
display : inline-block;
overflow : hidden;
width : 100%;
text-overflow : ellipsis;
white-space : nowrap;
}
.time{
position : absolute;
right : 2px;
bottom : 2px;
font-size : 0.7em;
color : #888;
}
}
}
}
.metadata.navItem {
position : relative;
padding: 0;
align-items: center;
display : flex;
flex-grow: 1;
height: 100%;
i{
margin-right: 10px;
}
.window{
position : absolute;
bottom : 0;
width : 440px;
left : 50%;
max-height : ~"calc(100vh - 28px)";
background-color : #333;
border : 3px solid #444;
border-top : unset;
border-radius : 0 0 5px 5px;
box-shadow : inset 0 7px 9px -7px #111;
display : flex;
flex-flow : row wrap;
justify-content : flex-start;
align-content : baseline;
padding : 0px 10px 5px;
margin : 0 auto;
z-index : -1;
transition : transform 0.4s, opacity 0.4s;
&.active{
transform: translateX(-50%) translateY(100%);
opacity: 1;
}
&.inactive{
transform: translateX(-50%) translateY(0%);
opacity: 0;
}
.row{
display : flex;
flex-flow : row wrap;
width : 100%;
h4{
display : block;
box-sizing : border-box;
padding : 5px 0px;
color : #bbb;
text-align : center;
flex-basis : 20%;
flex-grow : 1;
min-width : 76px;
}
p{
font-family : 'Open Sans', sans-serif;
font-size : 10px;
font-weight : normal;
text-transform : initial;
padding : 5px 0;
flex-basis : 80%;
flex-grow : 1;
.tag{
border : 2px solid grey;
padding : 2px;
margin : 2px 2px;
display : inline-block;
border-radius : 5px;
background-color : #444;
}
a.userPageLink{
text-decoration: none;
color: white;
&:hover{
text-decoration: underline;
}
}
}
&:nth-of-type(even){
background-color: #555;
}
}
}
}
.warning.navItem{
position : relative;
background-color : @orange;
color : white;
&:hover>.dropdown{
visibility : visible;
}
.dropdown{
position : absolute;
display : block;
top : 28px;
left : 0px;
visibility : hidden;
z-index : 10000;
box-sizing : border-box;
width : 100%;
padding : 13px 5px;
background-color : #333;
text-align : center;
}
}
.account.navItem{
min-width: 100px;
}
.account.username.navItem{
text-transform: none;
}
}
@import "naturalcrit/styles/colors.less";
@navbarHeight : 28px;
@keyframes pinkColoring {
0% {color : pink;}
50% {color : pink;}
75% {color : red;}
100% {color : pink;}
}
.homebrew nav {
.homebrewLogo {
.animate(color);
font-family : CodeBold;
font-size : 12px;
color : white;
div {
margin-top : 2px;
margin-bottom : -2px;
}
&:hover {
color : @blue;
}
}
.editTitle.navItem {
padding : 2px 12px;
input {
font-family : "Open Sans", sans-serif;
font-size : 12px;
font-weight : 800;
width : 250px;
margin : 0;
padding : 2px;
text-align : center;
color : white;
border : 1px solid @blue;
outline : none;
background-color : transparent;
}
.charCount {
display : inline-block;
margin-left : 8px;
text-align : right;
vertical-align : bottom;
color : #666;
&.max {
color : @red;
}
}
}
.brewTitle.navItem {
font-size : 12px;
font-weight : 800;
height : 100%;
text-align : center;
text-transform : initial;
color : white;
background-color : transparent;
flex-grow : 1;
}
.save-menu {
.dropdown {
z-index : 1000;
}
.navItem i.fa-power-off {
color : red;
&.active {
color : rgb(0, 182, 52);
filter : drop-shadow(0 0 2px rgba(0, 182, 52, 0.765));
}
}
}
.patreon.navItem {
border-right : 1px solid #666;
border-left : 1px solid #666;
&:hover i {
color : red;
}
i {
.animate(color);
animation-name : pinkColoring;
animation-duration : 2s;
color : pink;
}
}
.recent.navDropdownContainer {
position : relative;
.navDropdown .navItem {
overflow : hidden auto;
max-height : ~"calc(100vh - 28px)";
scrollbar-color : #666 #333;
scrollbar-width : thin;
#backgroundColorsHover;
.animate(background-color);
position : relative;
display : block;
overflow : clip;
box-sizing : border-box;
padding : 8px 5px 13px;
text-decoration : none;
color : white;
border-top : 1px solid #888;
background-color : #333;
.clear {
position : absolute;
top : 50%;
right : 0;
display : none;
width : 20px;
height : 100%;
transform : translateY(-50%);
opacity : 70%;
border-radius : 3px;
background-color : #333;
&:hover {
opacity : 100%;
}
i {
font-size : 10px;
width : 100%;
height : 100%;
margin : 0;
text-align : center;
}
}
&:hover {
background-color : @blue;
.clear {
display : grid;
place-content : center;
}
}
.title {
display : inline-block;
overflow : hidden;
width : 100%;
white-space : nowrap;
text-overflow : ellipsis;
}
.time {
font-size : 0.7em;
position : absolute;
right : 2px;
bottom : 2px;
color : #888;
}
&.header {
display : block;
box-sizing : border-box;
padding : 5px 0;
text-align : center;
color : #BBB;
border-top : 1px solid #888;
background-color : #333;
&:nth-of-type(1) {
background-color : darken(@teal, 20%);
}
&:nth-of-type(2) {
background-color : darken(@purple, 30%);
}
}
}
}
.metadata.navItem {
position : relative;
display : flex;
align-items : center;
height : 100%;
padding : 0;
flex-grow : 1;
i {
margin-right : 10px;
}
.window {
position : absolute;
z-index : -1;
bottom : 0;
left : 50%;
display : flex;
justify-content : flex-start;
width : 440px;
max-height : ~"calc(100vh - 28px)";
margin : 0 auto;
padding : 0 10px 5px;
transition : transform 0.4s, opacity 0.4s;
border : 3px solid #444;
border-top : unset;
border-radius : 0 0 5px 5px;
background-color : #333;
box-shadow : inset 0 7px 9px -7px #111;
flex-flow : row wrap;
align-content : baseline;
&.active {
transform : translateX(-50%) translateY(100%);
opacity : 1;
}
&.inactive {
transform : translateX(-50%) translateY(0%);
opacity : 0;
}
.row {
display : flex;
width : 100%;
flex-flow : row wrap;
h4 {
display : block;
box-sizing : border-box;
min-width : 76px;
padding : 5px 0;
text-align : center;
color : #BBB;
flex-basis : 20%;
flex-grow : 1;
}
p {
font-family : "Open Sans", sans-serif;
font-size : 10px;
font-weight : normal;
padding : 5px 0;
text-transform : initial;
flex-basis : 80%;
flex-grow : 1;
.tag {
display : inline-block;
margin : 2px 2px;
padding : 2px;
border : 2px solid grey;
border-radius : 5px;
background-color : #444;
}
a.userPageLink {
text-decoration : none;
color : white;
&:hover {
text-decoration : underline;
}
}
}
&:nth-of-type(even) {
background-color : #555;
}
}
}
}
.warning.navItem {
position : relative;
color : white;
background-color : @orange;
&:hover > .dropdown {
visibility : visible;
}
.dropdown {
position : absolute;
z-index : 10000;
top : 28px;
left : 0;
display : block;
visibility : hidden;
box-sizing : border-box;
width : 100%;
padding : 13px 5px;
text-align : center;
background-color : #333;
}
}
.account.navItem {
min-width : 100px;
}
.account.username.navItem {
text-transform : none;
}
}

View File

@@ -121,6 +121,7 @@ const RecentItems = createClass({
removeItem : function(url, evt){
evt.preventDefault();
evt.stopPropagation();
let edited = JSON.parse(localStorage.getItem(EDIT_KEY) || '[]');
let viewed = JSON.parse(localStorage.getItem(VIEW_KEY) || '[]');
@@ -139,11 +140,11 @@ const RecentItems = createClass({
},
renderDropdown : function(){
if(!this.state.showDropdown) return null;
// if(!this.state.showDropdown) return null;
const makeItems = (brews)=>{
return _.map(brews, (brew, i)=>{
return <a href={brew.url} className='item' key={`${brew.id}-${i}`} target='_blank' rel='noopener noreferrer' title={brew.title || '[ no title ]'}>
return <a className='navItem' href={brew.url} key={`${brew.id}-${i}`} target='_blank' rel='noopener noreferrer' title={brew.title || '[ no title ]'}>
<span className='title'>{brew.title || '[ no title ]'}</span>
<span className='time'>{Moment(brew.ts).fromNow()}</span>
<div className='clear' title='Remove from Recents' onClick={(e)=>{this.removeItem(`${brew.url}`, e);}}><i className='fas fa-times'></i></div>
@@ -151,25 +152,25 @@ const RecentItems = createClass({
});
};
return <div className='dropdown'>
return <>
{(this.props.showEdit && this.props.showView) ?
<h4>edited</h4> : null }
<Nav.item className='header'>edited</Nav.item> : null }
{this.props.showEdit ?
makeItems(this.state.edit) : null }
{(this.props.showEdit && this.props.showView) ?
<h4>viewed</h4> : null }
<Nav.item className='header'>viewed</Nav.item> : null }
{this.props.showView ?
makeItems(this.state.view) : null }
</div>;
</>;
},
render : function(){
return <Nav.item icon='fas fa-history' color='grey' className='recent'
onMouseEnter={()=>this.handleDropdown(true)}
onMouseLeave={()=>this.handleDropdown(false)}>
{this.props.text}
return <Nav.dropdown className='recent'>
<Nav.item icon='fas fa-history' color='grey' >
{this.props.text}
</Nav.item>
{this.renderDropdown()}
</Nav.item>;
</Nav.dropdown>;
}
});

View File

@@ -1,47 +1,52 @@
.uiPage{
.content{
overflow-y : hidden;
width : 90vw;
background-color: #f0f0f0;
font-family: 'Open Sans';
margin-left: auto;
margin-right: auto;
margin-top: 25px;
padding: 2% 4%;
font-size: 0.8em;
line-height: 1.8em;
.dataGroup{
padding: 6px 20px 15px;
border: 2px solid black;
border-radius: 5px;
margin: 5px 0px;
}
h1, h2, h3, h4{
font-weight: 900;
text-transform: uppercase;
margin: 0.5em 30% 0.25em 0;
border-bottom: 2px solid slategrey;
}
h1 {
font-size: 2em;
border-bottom: 2px solid darkslategrey;
margin-bottom: 0.5em;
margin-right: 0;
}
h2 {
font-size: 1.75em;
}
h3 {
font-size: 1.5em;
svg {
width: 19px;
.homebrew {
.uiPage.sitePage {
.content {
width : ~"min(90vw, 1000px)";
padding : 2% 4%;
margin-top : 25px;
margin-right : auto;
margin-left : auto;
overflow-y : scroll;
font-family : 'Open Sans';
font-size : 0.8em;
line-height : 1.8em;
background-color : #F0F0F0;
.dataGroup {
padding : 6px 20px 15px;
margin : 5px 0px;
border : 2px solid black;
border-radius : 5px;
}
h1, h2, h3, h4 {
width : 100%;
margin : 0.5em 30% 0.25em 0;
font-weight : 900;
text-transform : uppercase;
border-bottom : 2px solid slategrey;
}
h1 {
margin-right : 0;
margin-bottom : 0.5em;
font-size : 2em;
border-bottom : 2px solid darkslategrey;
}
h2 { font-size : 1.75em; }
h3 {
font-size : 1.5em;
svg { width : 19px; }
}
h4 { font-size : 1.25em; }
strong { font-weight : bold; }
em { font-style : italic; }
ul {
padding-left : 1.25em;
list-style : square;
}
.blank {
height : 1em;
margin-top : 0;
& + * { margin-top : 0; }
}
}
h4 {
font-size: 1.25em;
}
strong {
font-weight: bold;
}
}
}
}

View File

@@ -4,44 +4,37 @@ const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
const Nav = require('naturalcrit/nav/nav.jsx');
const Navbar = require('../../navbar/navbar.jsx');
const PatreonNavItem = require('../../navbar/patreon.navitem.jsx');
const RecentNavItem = require('../../navbar/recent.navitem.jsx').both;
const HelpNavItem = require('../../navbar/help.navitem.jsx');
const UIPage = require('../basePages/uiPage/uiPage.jsx');
const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
const Markdown = require('../../../../shared/naturalcrit/markdown.js');
const ErrorIndex = require('./errors/errorIndex.js');
const ErrorPage = createClass({
displayName : 'ErrorPage',
getDefaultProps : function() {
return {
ver : '0.0.0',
errorId : ''
errorId : '',
text : '# Oops \n We could not find a brew with that id. **Sorry!**',
error : {}
};
},
text : '# Oops \n We could not find a brew with that id. **Sorry!**',
render : function(){
return <div className='errorPage sitePage'>
<Navbar ver={this.props.ver}>
<Nav.section>
<Nav.item className='errorTitle'>
Crit Fail!
</Nav.item>
</Nav.section>
const errorText = ErrorIndex(this.props)[this.props.brew.HBErrorCode.toString()] || '';
<Nav.section>
<PatreonNavItem />
<HelpNavItem />
<RecentNavItem />
</Nav.section>
</Navbar>
<div className='content'>
<BrewRenderer text={this.text} />
return <UIPage brew={{ title: 'Crit Fail!' }}>
<div className='dataGroup'>
<div className='errorTitle'>
<h1>{`Error ${this.props.brew.status || '000'}`}</h1>
<h4>{this.props.brew.text || 'No error text'}</h4>
</div>
<hr />
<div dangerouslySetInnerHTML={{ __html: Markdown.render(errorText) }} />
</div>
</div>;
</UIPage>;
}
});

View File

@@ -1,5 +1,13 @@
.errorPage{
.errorTitle{
background-color: @orange;
.homebrew {
.uiPage.sitePage {
.errorTitle {
//background-color: @orange;
color : #D02727;
text-align : center;
}
.content {
h1, h2, h3, h4 { border-bottom : none; }
hr { border-bottom : 2px solid slategrey; }
}
}
}

View File

@@ -0,0 +1,126 @@
const dedent = require('dedent-tabs').default;
const loginUrl = 'https://www.naturalcrit.com/login';
const errorIndex = (props)=>{
return {
// Default catch all
'00' : dedent`
## An unknown error occurred!
We aren't sure what happened, but our server wasn't able to find what you
were looking for.`,
// General Google load error
'01' : dedent`
## An error occurred while retrieving this brew from Google Drive!
Google reported an error while attempting to retrieve a brew from this link.`,
// Google Drive - 404 : brew deleted or access denied
'02' : dedent`
## We can't find this brew in Google Drive!
This file was saved on Google Drive, but this link doesn't work anymore.
${ props.brew.authors?.length > 0
? `Note that this brew belongs to the Homebrewery account **${ props.brew.authors[0] }**,
${ props.brew.account
? `which is
${props.brew.authors[0] == props.brew.account
? `your account.`
: `not your account (you are currently signed in as **${props.brew.account}**).`
}`
: 'and you are not currently signed in to any account.'
}`
: ''
}
The Homebrewery cannot delete files from Google Drive on its own, so there
are three most likely possibilities:
:
- **The Google Drive files may have been accidentally deleted.** Look in
the Google Drive account that owns this brew (or ask the owner to do so),
and make sure the Homebrewery folder is still there, and that it holds your brews
as text files.
- **You may have changed the sharing settings for your files.** If the files
are still on Google Drive, change all of them to be shared *with everyone who has
the link* so the Homebrewery can access them.
- **The Google Account may be closed.** Google may have removed the account
due to inactivity or violating a Google policy. Make sure the owner can
still access Google Drive normally and upload/download files to it.
:
If the file isn't found, Google Drive usually puts your file in your Trash folder for
30 days. Assuming the trash hasn't been emptied yet, it might be worth checking.
You can also find the Activity tab on the right side of the Google Drive page, which
shows the recent activity on Google Drive. This can help you pin down the exact date
the brew was deleted or moved, and by whom.
:
If the brew still isn't found, some people have had success asking Google to recover
accidentally deleted files at this link:
https://support.google.com/drive/answer/1716222?hl=en&ref_topic=7000946.
At the bottom of the page there is a button that says *Send yourself an Email*
and you will receive instructions on how to request the files be restored.
:
Also note, if you prefer not to use your Google Drive for storage, you can always
change the storage location of a brew by clicking the Google drive icon by the
brew title and choosing *transfer my brew to/from Google Drive*.`,
// User is not Authors list
'03' : dedent`
## Current signed-in user does not have editor access to this brew.
If you believe you should have access to this brew, ask one of its authors to invite you
as an author by opening the Edit page for the brew, viewing the {{fa,fa-info-circle}}
**Properties** tab, and adding your username to the "invited authors" list. You can
then try to access this document again.
**Brew Title:** ${props.brew.brewTitle || 'Unable to show title'}
**Current Authors:** ${props.brew.authors?.map((author)=>{return `${author}`;}).join(', ') || 'Unable to list authors'}`,
// User is not signed in; must be a user on the Authors List
'04' : dedent`
## Sign-in required to edit this brew.
You must be logged in to one of the accounts listed as an author of this brew.
User is not logged in. Please log in [here](${loginUrl}).
**Brew Title:** ${props.brew.brewTitle || 'Unable to show title'}
**Current Authors:** ${props.brew.authors?.map((author)=>{return `${author}`;}).join(', ') || 'Unable to list authors'}`,
// Brew load error
'05' : dedent`
## No Homebrewery document could be found.
The server could not locate the Homebrewery document. It was likely deleted by
its owner.
**Requested access:** ${props.brew.accessType}
**Brew ID:** ${props.brew.brewId}`,
// Brew save error
'06' : dedent`
## Unable to save Homebrewery document.
An error occurred wil attempting to save the Homebrewery document.`,
// Brew delete error
'07' : dedent`
## Unable to delete Homebrewery document.
An error occurred while attempting to remove the Homebrewery document.
**Brew ID:** ${props.brew.brewId}`,
// Author delete error
'08' : dedent`
## Unable to remove user from Homebrewery document.
An error occurred while attempting to remove the user from the Homebrewery document author list!
**Brew ID:** ${props.brew.brewId}`,
};
};
module.exports = errorIndex;

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 541.53217 512"
version="1.1"
id="back-cover-icon"
sodipodi:docname="book-front-cover.svg"
width="541.53217"
height="512"
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs22131" />
<sodipodi:namedview
id="namedview22129"
pagecolor="#ffffff"
bordercolor="#111111"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="0.39257813"
inkscape:cx="-263.64179"
inkscape:cy="444.49751"
inkscape:window-width="1920"
inkscape:window-height="991"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg22127" />
<!--! Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
<g id="g20308" transform="matrix(3.7795276,0,0,3.7795276,-201.76367,-251.58203)">
<path id="rect20232" d="M95.1,66.6h-8.5c-4.7,0-8.5,3.8-8.5,8.5v21.4c3.5-0.4,7.4-0.5,12-0.5c0.7,0,0.6,0,1.2,0
c0-2.4,0-4.2,0.3-6.2c0.3-2.2,2.2-5.8,3.5-7c0.9-0.9,3-3.2,7-3.7c1-0.1,2-0.1,2.8,0c2.6,0.3,4.6,1.6,6.1,2.6
c3.9,2.7,7.4,6.4,14.8,13.8c6.3,6.3,9.8,9.8,12,12.4c1.1,1.3,2.1,2.4,2.9,4c0.9,1.7,1.4,4.2,1.4,5.6c0,1.4-0.5,4-1.4,5.6
c-0.9,1.6-1.8,2.7-2.9,4c-2.2,2.6-5.6,6-11.8,12.2c-3.8,3.8-7.4,7.3-10.2,9.9c-1.4,1.3-2.6,2.4-3.6,3.3c-0.5,0.4-1,0.8-1.5,1.2
c-0.3,0.2-0.5,0.4-1,0.7s-0.7,0.7-2.8,1.2c-4.3,1.1-6.3,0.4-9.4-1.3c-0.5-0.3-1.9-0.9-3.3-2.6c-1.4-1.7-2.1-3.7-2.4-5.1
c-0.5-2.4-0.5-4.3-0.6-7.2c-3.9,0-6,0.1-6.5,0.1c-0.5,0.1,0.2-0.2-1.2,0.5c-1.7,0.8-3.6,2.8-4.4,4.5c-0.3,0.8-0.5,1-0.6,6.6
c-0.1,2.2-0.2,4.3-0.4,6c0,0.3-0.1,0.6-0.1,0.8v1.9c0,4.7,3.8,8.5,8.5,8.5v16.9c-4.7,0-8.5,3.8-8.5,8.5c0,4.7,3.8,8.5,8.5,8.5h8.5
h76.2c14,0,25.4-11.4,25.4-25.4V92c0-14-11.4-25.4-25.4-25.4L95.1,66.6z M171.3,168.2c4.7,0,8.5,3.8,8.5,8.5c0,4.7-3.8,8.5-8.5,8.5
h-67.7v-16.9L171.3,168.2L171.3,168.2z"/>
<path id="path20297" d="M63.4,158c1.8,1.6,4.5,1.9,5.5,0.7c0.3-0.4,0.7-4,0.8-8.1c0.2-5.9,0.5-7.9,1.4-10c1.7-3.7,4.9-7,8.6-8.9
c3.1-1.5,3.6-1.6,11.7-1.6h8.5l0.3,7.6c0.3,7.5,0.3,7.7,1.7,8.5c0.8,0.5,2.1,0.7,2.8,0.5c0.8-0.2,7.4-6.4,14.9-13.9
c12.4-12.4,13.5-13.7,13.5-15.5c0-1.8-1.1-3.1-13.8-15.7c-14.7-14.7-15.4-15.2-18-12.7c-1,1-1.1,1.9-1.1,7.6c0,3.6-0.2,6.9-0.3,7.4
c-0.3,0.8-1.7,0.9-9.8,0.9c-15.6,0-21.1,1.7-27.9,8.5c-6.5,6.5-8.8,12-8.8,21.1c0,4.7,0.3,6.8,1.3,9.8
C56.2,148.6,60.7,155.7,63.4,158L63.4,158z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -2,7 +2,7 @@
<svg
viewBox="0 0 541.53217 512"
version="1.1"
id="svg22127"
id="front-cover-icon"
sodipodi:docname="book-front-cover.svg"
width="541.53217"
height="512"

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 704.00001 512"
version="1.1"
id="svg22127"
sodipodi:docname="book-part-cover.svg"
width="704"
height="512"
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
inkscape:export-filename="InsideCover3.png"
inkscape:export-xdpi="300"
inkscape:export-ydpi="300"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs22131" />
<sodipodi:namedview
id="namedview22129"
pagecolor="#ffffff"
bordercolor="#111111"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="0.6685671"
inkscape:cx="299.8951"
inkscape:cy="80.021886"
inkscape:window-width="1920"
inkscape:window-height="991"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg22127" />
<!--! Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
<path
id="path2161-6"
style="color:#000000;fill:#000000;stroke-width:1;-inkscape-stroke:none;paint-order:stroke fill markers"
d="M 208,0 C 147.0078,0 94.429433,14.25071 60.367188,26.66992 23.520854,39.96036 0,76.16076 0,112.95896 v 317.8321 c 0,59.8499 56.949847,92.6546 107.47266,76.6035 l -0.1543,0.049 c 26.46715,-8.335 74.84649,-18.3965 100.68164,-18.3965 17.25807,0 61.31688,10.6183 85.14453,18.8438 l 0.0508,0.018 0.0527,0.018 c 19.82627,6.5858 40.84117,4.9222 58.99804,-3.0762 18.04267,7.8799 38.84257,9.6126 58.33594,3.1328 l 0.13672,-0.045 0.13672,-0.047 c 23.88445,-8.0588 67.88646,-18.8437 85.14453,-18.8437 25.83515,0 74.22549,10.0266 100.68164,18.3964 l 0.1543,0.049 0.15625,0.049 C 647.13371,523.05316 704,490.64216 704,430.79226 v -317.8321 c 0,-36.8274 -23.49583,-72.8235 -60.00977,-86.25583 l -0.16015,-0.0606 -0.16211,-0.0566 C 609.79193,14.33005 557.11269,0.0012 496,0.0012 434.5671,0.0012 387.12553,14.01354 352,34.94261 316.87446,14.01344 269.4331,0.0012 208,0.0012 Z m 0,32.00977 c 58.3999,0 103.40004,18.89469 123,33.63279 3.3,2.4564 5,6.4246 5,10.3926 v 356.5508 c 0,10.7702 -11.70041,18.2326 -22.40039,14.6426 -26.59996,-8.9751 -71.69966,-22.2012 -105.59961,-22.2012 -38.49993,0 -88.40045,11.4317 -119.900391,21.3516 C 76.799621,449.96896 64,442.03166 64,430.78906 V 80.94726 C 64,69.51586 70.799631,58.93546 82.099609,54.87306 110.29956,44.57516 157.50009,32.00977 208,32.00977 Z m 288,0 c 50.49991,0 97.70044,12.56619 125.90039,22.76949 C 633.20037,58.93616 640,69.51586 640,80.94726 v 349.8418 c 0,11.2426 -12.79963,19.0854 -24.09961,15.5899 -31.49995,-9.9199 -81.40046,-21.3516 -119.90039,-21.3516 -33.89995,0 -78.99966,13.2261 -105.59961,22.2012 C 379.60041,450.81856 368,443.35616 368,432.58596 V 76.03516 c 0,-3.968 1.60001,-7.9362 5,-10.3926 19.59997,-14.7381 64.6001,-33.63279 123,-33.63279 z M 335.52734,45.75386 c -0.1289,0.093 -0.23137,0.2032 -0.35937,0.2969 -0.198,0.1477 -0.428,0.2796 -0.625,0.4278 z m 33.67969,0.5372 0.24805,0.1875 c -0.0427,-0.033 -0.0937,-0.061 -0.13672,-0.094 -0.0393,-0.03 -0.0713,-0.064 -0.11133,-0.094 z" />
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:64;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 417.64553,213.53304 c 88.71546,-18.9285 95.50522,-18.6158 172.79707,0.054"
id="path2371-8"
sodipodi:nodetypes="cc" />
<path
id="path2315"
style="stroke-width:67.6532;stroke-linejoin:bevel;paint-order:stroke markers fill;stop-color:#000000"
inkscape:transform-center-x="-3.4164388e-06"
inkscape:transform-center-y="-8.443352"
d="m 505.27489,52.89544 25.98603,52.6535 58.10652,8.4434 -42.04628,40.985 9.92578,57.8717 -51.97205,-27.3234 -51.97204,27.3234 9.92578,-57.8717 -42.04627,-40.985 58.10651,-8.4434 z" />
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -34,15 +34,18 @@
.mask-center {
content: url('../icons/mask-center.svg');
}
.fa-file-c {
content: url('../icons/fa-file-c.svg');
}
.book-front-cover {
content: url('../icons/book-front-cover.svg');
}
.book-back-cover {
content: url('../icons/book-back-cover.svg');
}
.book-inside-cover {
content: url('../icons/book-inside-cover.svg');
}
.book-part-cover {
content: url('../icons/book-part-cover.svg');
}
.davek {
content: url('../icons/Davek.svg');
}

View File

@@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 610.4 816.5" style="enable-background:new 0 0 610.4 816.5;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
.st1{fill:#FFFFFF;stroke:#FFFFFF;stroke-width:20;stroke-miterlimit:10;}
</style>
<title>fa-file-c</title>
<g id="Layer_2_1_">
<g id="Layer_1-2">
<g id="page">
<path id="page-2" d="M610.3,468.3c0,77.3,0.2,154.5,0,231.8s-39.8,116.5-116.8,116.4c-127.6,0-255.1,0-382.7,0
c-68.1,0-110.5-41.7-110.6-109.8c-0.2-197.7-0.2-395.5,0-593.2c0-68.4,43.2-110.9,112.1-111c90-0.1,180,0.2,270-0.2
c12.8,0,21.5,0.6,32.9,4c17.1,5,152.7,150.7,190.7,188.8c-0.7,18-6,5.7,1.4,35.1c0,6.8,3.1,11.2,3.1,18.1
C610.2,320.8,610.3,395.7,610.3,468.3z"/>
<path id="white_corner" class="st0" d="M364.1,0v200c0,9.3,1.7,25.6,13.1,36.8c12,11.7,28.8,12.1,37.5,12.2
c119.8,1.3,195.6,0.4,195.6,0.4l0,0l-0.3-54.3l-197,1l3-192L364.1,0z"/>
</g>
<path class="st1" d="M317.7,719.8c-38.3,0-71-8.1-98.3-24.3c-27.2-16.2-48.1-39.2-62.7-69C142.3,596.8,135,561.2,135,520
c0-30.9,4.1-58.6,12.4-83.1c8.3-24.5,20.2-45.3,35.9-62.4c15.6-17.1,34.9-30.4,57.7-39.8s48.4-14.1,76.7-14.1
c22.1-0.1,44,3.1,65.1,9.7c20.6,6.4,38.4,15.9,53.5,28.4c4.8,3.7,8,7.8,9.7,12.4c1.6,4.2,1.8,8.9,0.6,13.2
c-1.2,4.1-3.5,7.7-6.6,10.5c-3.1,2.8-7.2,4.2-11.3,4.1c-4.4,0-9.4-1.8-14.9-5.5c-13-10.5-27.7-18.6-43.6-23.7
c-16.6-5.3-33.9-7.9-51.3-7.7c-29.1,0-53.7,6.2-74,18.5s-35.5,30.3-45.8,53.8c-10.3,23.6-15.4,52.1-15.4,85.5s5.1,62.1,15.4,85.9
c10.3,23.7,25.6,41.8,45.8,54.1c20.2,12.3,44.9,18.5,74,18.5c17.4,0.1,34.8-2.6,51.3-8c16.2-5.3,31.3-13.5,44.7-24
c5.5-3.7,10.5-5.4,14.9-5.3c4,0.1,7.9,1.5,11,4.1c3,2.7,5.2,6.1,6.4,9.9c1.3,4.1,1.3,8.6,0,12.7c-1.3,4.4-4.1,8.3-8.6,11.6
c-15.5,13.3-33.6,23.3-54.4,30.1C362.7,716.6,340.3,720,317.7,719.8z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

33538
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,9 @@
{
"name": "homebrewery",
"description": "Create authentic looking D&D homebrews using only markdown",
"version": "3.8.0",
"version": "3.9.1",
"engines": {
"node": "16.13.x"
"node": ">=18.16.x"
},
"repository": {
"type": "git",
@@ -16,6 +16,8 @@
"builddev": "node scripts/buildHomebrew.js --dev",
"lint": "eslint --fix **/*.{js,jsx}",
"lint:dry": "eslint **/*.{js,jsx}",
"stylelint": "stylelint --fix **/*.{less}",
"stylelint:dry": "stylelint **/*.less",
"circleci": "npm test && eslint **/*.{js,jsx} --max-warnings=0",
"verify": "npm run lint && npm test",
"test": "jest --runInBand",
@@ -76,11 +78,11 @@
]
},
"dependencies": {
"@babel/core": "^7.21.4",
"@babel/plugin-transform-runtime": "^7.21.4",
"@babel/preset-env": "^7.21.4",
"@babel/preset-react": "^7.18.6",
"@googleapis/drive": "^5.0.2",
"@babel/core": "^7.22.8",
"@babel/plugin-transform-runtime": "^7.22.7",
"@babel/preset-env": "^7.22.7",
"@babel/preset-react": "^7.22.5",
"@googleapis/drive": "^5.1.0",
"body-parser": "^1.20.2",
"classnames": "^2.3.2",
"codemirror": "^5.65.6",
@@ -95,28 +97,35 @@
"jwt-simple": "^0.5.6",
"less": "^3.13.1",
"lodash": "^4.17.21",
"marked": "4.3.0",
"marked-extended-tables": "^1.0.5",
"marked": "5.1.1",
"marked-extended-tables": "^1.0.6",
"marked-gfm-heading-id": "^3.0.4",
"marked-smartypants-lite": "^1.0.0",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.29.4",
"mongoose": "^7.0.3",
"mongoose": "^7.3.2",
"nanoid": "3.3.4",
"nconf": "^0.12.0",
"npm": "^9.6.4",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"npm": "^9.8.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-frame-component": "^4.1.3",
"react-router-dom": "6.10.0",
"react-router-dom": "6.14.1",
"sanitize-filename": "1.6.3",
"superagent": "^6.1.0",
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
},
"devDependencies": {
"eslint": "^8.38.0",
"eslint": "^8.44.0",
"eslint-plugin-jest": "^27.2.2",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-jest": "^27.2.1",
"jest": "^29.5.0",
"jest": "^29.6.1",
"jest-expect-message": "^1.1.3",
"postcss-less": "^6.0.0",
"stylelint": "^15.10.1",
"stylelint-config-recess-order": "^4.3.0",
"stylelint-config-recommended": "^13.0.0",
"stylelint-stylistic": "^0.4.3",
"supertest": "^6.3.3"
}
}

View File

@@ -135,10 +135,12 @@ fs.emptyDirSync('./build');
})().catch(console.error);
//In development set up a watch server and livereload
//In development, set up LiveReload (refreshes browser), and Nodemon (restarts server)
if(isDev){
livereload('./build');
watchFile('./server.js', {
watch : ['./client', './server', './themes'] // Watch additional folders if you want
livereload('./build'); // Install the Chrome extension LiveReload to automatically refresh the browser
watchFile('./server.js', { // Restart server when change detected to this file or any nested directory from here
ignore : ['./build', './client', './themes'], // Ignore folders that are not running server code / avoids unneeded restarts
ext : 'js json' // Extensions to watch (only .js/.json by default)
//watch : ['./server', './themes'], // Watch additional folders if needed
});
}

View File

@@ -1,4 +1,4 @@
/*eslint max-lines: ["warn", {"max": 400, "skipBlankLines": true, "skipComments": true}]*/
/*eslint max-lines: ["warn", {"max": 500, "skipBlankLines": true, "skipComments": true}]*/
// Set working directory to project root
process.chdir(`${__dirname}/..`);
@@ -324,8 +324,8 @@ app.get('/share/:id', asyncHandler(getBrew('share')), asyncHandler(async (req, r
};
if(req.params.id.length > 12 && !brew._id) {
const googleId = req.params.id.slice(0, -12);
const shareId = req.params.id.slice(-12);
const googleId = brew.googleId;
const shareId = brew.shareId;
await GoogleActions.increaseView(googleId, shareId, 'share', brew)
.catch((err)=>{next(err);});
} else {
@@ -397,7 +397,6 @@ app.get('/account', asyncHandler(async (req, res, next)=>{
return next();
}));
const nodeEnv = config.get('node_env');
const isLocalEnvironment = config.get('local_environments').includes(nodeEnv);
// Local only
@@ -414,8 +413,7 @@ if(isLocalEnvironment){
//Render the page
const templateFn = require('./../client/template.js');
app.use(asyncHandler(async (req, res, next)=>{
const renderPage = async (req, res)=>{
// Create configuration object
const configuration = {
local : isLocalEnvironment,
@@ -424,7 +422,7 @@ app.use(asyncHandler(async (req, res, next)=>{
};
const props = {
version : require('./../package.json').version,
url : req.originalUrl,
url : req.customUrl || req.originalUrl,
brew : req.brew,
brews : req.brews,
googleBrews : req.googleBrews,
@@ -438,15 +436,20 @@ app.use(asyncHandler(async (req, res, next)=>{
const page = await templateFn('homebrew', title, props)
.catch((err)=>{
console.log(err);
return res.sendStatus(500);
});
return page;
};
//Send rendered page
app.use(asyncHandler(async (req, res, next)=>{
const page = await renderPage(req, res);
if(!page) return;
res.send(page);
}));
//v=====----- Error-Handling Middleware -----=====v//
//Format Errors so all fields will be sent
const replaceErrors = (key, value)=>{
//Format Errors as plain objects so all fields will appear in the string sent
const formatErrors = (key, value)=>{
if(value instanceof Error) {
const error = {};
Object.getOwnPropertyNames(value).forEach(function (key) {
@@ -458,13 +461,30 @@ const replaceErrors = (key, value)=>{
};
const getPureError = (error)=>{
return JSON.parse(JSON.stringify(error, replaceErrors));
return JSON.parse(JSON.stringify(error, formatErrors));
};
app.use((err, req, res, next)=>{
const status = err.status || 500;
app.use(async (err, req, res, next)=>{
const status = err.status || err.code || 500;
console.error(err);
res.status(status).send(getPureError(err));
req.ogMeta = { ...defaultMetaTags,
title : 'Error Page',
description : 'Something went wrong!'
};
req.brew = {
...err,
title : 'Error - Something went wrong!',
text : err.errors?.map((error)=>{return error.message;}).join('\n\n') || err.message || 'Unknown error!',
status : status,
HBErrorCode : err.HBErrorCode ?? '00',
pureError : getPureError(err)
};
req.customUrl= '/error';
const page = await renderPage(req, res);
if(!page) return;
res.send(page);
});
app.use((req, res)=>{

View File

@@ -99,23 +99,31 @@ const GoogleActions = {
listGoogleBrews : async (auth)=>{
const drive = googleDrive.drive({ version: 'v3', auth });
const obj = await drive.files.list({
pageSize : 1000,
fields : 'nextPageToken, files(id, name, description, createdTime, modifiedTime, properties)',
q : 'mimeType != \'application/vnd.google-apps.folder\' and trashed = false'
})
.catch((err)=>{
console.log(`Error Listing Google Brews`);
console.error(err);
throw (err);
//TODO: Should break out here, but continues on for some reason.
});
const fileList = [];
let NextPageToken = '';
if(!obj.data.files.length) {
do {
const obj = await drive.files.list({
pageSize : 1000,
pageToken : NextPageToken || '',
fields : 'nextPageToken, files(id, name, description, createdTime, modifiedTime, properties)',
q : 'mimeType != \'application/vnd.google-apps.folder\' and trashed = false'
})
.catch((err)=>{
console.log(`Error Listing Google Brews`);
console.error(err);
throw (err);
//TODO: Should break out here, but continues on for some reason.
});
fileList.push(...obj.data.files);
NextPageToken = obj.data.nextPageToken;
} while (NextPageToken);
if(!fileList.length) {
console.log('No files found.');
}
const brews = obj.data.files.map((file)=>{
const brews = fileList.map((file)=>{
return {
text : '',
shareId : file.properties.shareId,
@@ -235,9 +243,9 @@ const GoogleActions = {
if(obj) {
if(accessType == 'edit' && obj.data.properties.editId != accessId){
throw ('Edit ID does not match');
throw ({ message: 'Edit ID does not match' });
} else if(accessType == 'share' && obj.data.properties.shareId != accessId){
throw ('Share ID does not match');
throw ({ message: 'Share ID does not match' });
}
const file = await drive.files.get({

View File

@@ -27,8 +27,13 @@ const api = {
// If the id is longer than 12, then it's a google id + the edit id. This splits the longer id up.
if(id.length > 12) {
googleId = id.slice(0, -12);
id = id.slice(-12);
if(id.length >= (33 + 12)) { // googleId is minimum 33 chars (may increase)
googleId = id.slice(0, -12); // current editId is 12 chars
} else { // old editIds used to be 10 chars;
googleId = id.slice(0, -10); // if total string is too short, must be old brew
console.log('Old brew, using 10-char Id');
}
id = id.slice(googleId.length);
}
return { id, googleId };
},
@@ -57,7 +62,14 @@ const api = {
googleError = err;
});
// Throw any error caught while attempting to retrieve Google brew.
if(googleError) throw googleError;
if(googleError) {
const reason = googleError.errors?.[0].reason;
if(reason == 'notFound') {
throw { ...googleError, HBErrorCode: '02', authors: stub?.authors, account: req.account?.username };
} else {
throw { ...googleError, HBErrorCode: '01' };
}
}
// Combine the Homebrewery stub with the google brew, or if the stub doesn't exist just use the google brew
stub = stub ? _.assign({ ...api.excludeStubProps(stub), stubbed: true }, api.excludeGoogleProps(googleBrew)) : googleBrew;
}
@@ -65,14 +77,16 @@ const api = {
const isAuthor = stub?.authors?.includes(req.account?.username);
const isInvited = stub?.invitedAuthors?.includes(req.account?.username);
if(accessType === 'edit' && (authorsExist && !(isAuthor || isInvited))) {
throw `The current logged in user does not have editor access to this brew.
If you believe you should have access to this brew, ask the file owner to invite you as an author by opening the brew, viewing the Properties tab, and adding your username to the "invited authors" list. You can then try to access this document again.`;
const accessError = { name: 'Access Error', status: 401 };
if(req.account){
throw { ...accessError, message: 'User is not an Author', HBErrorCode: '03', authors: stub.authors, brewTitle: stub.title };
}
throw { ...accessError, message: 'User is not logged in', HBErrorCode: '04', authors: stub.authors, brewTitle: stub.title };
}
// If after all of that we still don't have a brew, throw an exception
if(!stub && !stubOnly) {
throw 'Brew not found in Homebrewery database or Google Drive';
throw { name: 'BrewLoad Error', message: 'Brew not found', status: 404, HBErrorCode: '05', accessType: accessType, brewId: id };
}
// Clean up brew: fill in missing fields with defaults / fix old invalid values
@@ -181,7 +195,7 @@ If you believe you should have access to this brew, ask the file owner to invite
saved = await newHomebrew.save()
.catch((err)=>{
console.error(err, err.toString(), err.stack);
throw `Error while creating new brew, ${err.toString()}`;
throw { name: 'BrewSave Error', message: `Error while creating new brew, ${err.toString()}`, status: 500, HBErrorCode: '06' };
});
if(!saved) return;
saved = saved.toObject();
@@ -283,10 +297,13 @@ If you believe you should have access to this brew, ask the file owner to invite
try {
await api.getBrew('edit')(req, res, ()=>{});
} catch (err) {
const { id, googleId } = api.getId(req);
console.warn(`No google brew found for id ${googleId}, the stub with id ${id} will be deleted.`);
await HomebrewModel.deleteOne({ editId: id });
return next();
// Only if the error code is HBErrorCode '02', that is, Google returned "404 - Not Found"
if(err.HBErrorCode == '02') {
const { id, googleId } = api.getId(req);
console.warn(`No google brew found for id ${googleId}, the stub with id ${id} will be deleted.`);
await HomebrewModel.deleteOne({ editId: id });
return next();
}
}
let brew = req.brew;
@@ -308,7 +325,7 @@ If you believe you should have access to this brew, ask the file owner to invite
await HomebrewModel.deleteOne({ _id: brew._id })
.catch((err)=>{
console.error(err);
throw { status: 500, message: 'Error while removing' };
throw { name: 'BrewDelete Error', message: 'Error while removing', status: 500, HBErrorCode: '07', brewId: brew._id };
});
} else {
if(shouldDeleteGoogleBrew) {
@@ -320,7 +337,7 @@ If you believe you should have access to this brew, ask the file owner to invite
brew.markModified('authors'); //Mongo will not properly update arrays without markModified()
await brew.save()
.catch((err)=>{
throw { status: 500, message: err };
throw { name: 'BrewAuthorDelete Error', message: err, status: 500, HBErrorCode: '08', brewId: brew._id };
});
}
}

View File

@@ -111,21 +111,32 @@ describe('Tests for api', ()=>{
expect(googleId).toEqual('12345');
});
it('should return id and google id from params', ()=>{
it('should return 12-char id and google id from params', ()=>{
const { id, googleId } = api.getId({
params : {
id : '123456789012abcdefghijkl'
id : '123456789012345678901234567890123abcdefghijkl'
}
});
expect(googleId).toEqual('123456789012345678901234567890123');
expect(id).toEqual('abcdefghijkl');
expect(googleId).toEqual('123456789012');
});
it('should return 10-char id and google id from params', ()=>{
const { id, googleId } = api.getId({
params : {
id : '123456789012345678901234567890123abcdefghij'
}
});
expect(googleId).toEqual('123456789012345678901234567890123');
expect(id).toEqual('abcdefghij');
});
});
describe('getBrew', ()=>{
const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew }));
const notFoundError = 'Brew not found in Homebrewery database or Google Drive';
const notFoundError = { HBErrorCode: '05', message: 'Brew not found', name: 'BrewLoad Error', status: 404, accessType: 'share', brewId: '1' };
it('returns middleware', ()=>{
const getFn = api.getBrew('share');
@@ -183,7 +194,7 @@ describe('Tests for api', ()=>{
expect(next).toHaveBeenCalled();
});
it('throws if invalid author', async ()=>{
it('throws if not logged in as author', async ()=>{
api.getId = jest.fn(()=>({ id: '1', googleId: undefined }));
model.get = jest.fn(()=>toBrewPromise({ title: 'test brew', authors: ['a'] }));
@@ -197,9 +208,24 @@ describe('Tests for api', ()=>{
err = e;
}
expect(err).toEqual(`The current logged in user does not have editor access to this brew.
expect(err).toEqual({ HBErrorCode: '04', message: 'User is not logged in', name: 'Access Error', status: 401, brewTitle: 'test brew', authors: ['a'] });
});
If you believe you should have access to this brew, ask the file owner to invite you as an author by opening the brew, viewing the Properties tab, and adding your username to the "invited authors" list. You can then try to access this document again.`);
it('throws if logged in as invalid author', async ()=>{
api.getId = jest.fn(()=>({ id: '1', googleId: undefined }));
model.get = jest.fn(()=>toBrewPromise({ title: 'test brew', authors: ['a'] }));
const fn = api.getBrew('edit', true);
const req = { brew: {}, account: { username: 'b' } };
let err;
try {
await fn(req, null, null);
} catch (e) {
err = e;
}
expect(err).toEqual({ HBErrorCode: '03', message: 'User is not an Author', name: 'Access Error', status: 401, brewTitle: 'test brew', authors: ['a'] });
});
it('does not throw if no authors', async ()=>{
@@ -545,7 +571,7 @@ brew`);
describe('deleteBrew', ()=>{
it('should handle case where fetching the brew returns an error', async ()=>{
api.getBrew = jest.fn(()=>async ()=>{ throw 'err'; });
api.getBrew = jest.fn(()=>async ()=>{ throw { message: 'err', HBErrorCode: '02' }; });
api.getId = jest.fn(()=>({ id: '1', googleId: '2' }));
model.deleteOne = jest.fn(async ()=>{});
const next = jest.fn(()=>{});

View File

@@ -0,0 +1,36 @@
let CodeMirror;
if(typeof navigator !== 'undefined'){
CodeMirror = require('codemirror');
//Language Modes
require('codemirror/mode/gfm/gfm.js'); //Github flavoured markdown
require('codemirror/mode/css/css.js');
require('codemirror/mode/javascript/javascript.js');
//Addons
//Code folding
require('codemirror/addon/fold/foldcode.js');
require('codemirror/addon/fold/foldgutter.js');
//Search and replace
require('codemirror/addon/search/search.js');
require('codemirror/addon/search/searchcursor.js');
require('codemirror/addon/search/jump-to-line.js');
require('codemirror/addon/search/match-highlighter.js');
require('codemirror/addon/search/matchesonscrollbar.js');
require('codemirror/addon/dialog/dialog.js');
//Trailing space highlighting
// require('codemirror/addon/edit/trailingspace.js');
//Active line highlighting
// require('codemirror/addon/selection/active-line.js');
//Scroll past last line
require('codemirror/addon/scroll/scrollpastend.js');
//Auto-closing
//XML code folding is a requirement of the auto-closing tag feature and is not enabled
require('codemirror/addon/fold/xml-fold.js');
require('codemirror/addon/edit/closetag.js');
const foldCode = require('./helpers/fold-code');
foldCode.registerHomebreweryHelper(CodeMirror);
}
module.exports = CodeMirror;

View File

@@ -4,58 +4,32 @@ const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
const closeTag = require('./close-tag');
const closeTag = require('./helpers/close-tag');
const Hints = require('./helpers/widget-elements/hints/hints.jsx');
const CodeMirror = require('./code-mirror.js');
let CodeMirror;
if(typeof navigator !== 'undefined'){
CodeMirror = require('codemirror');
//Language Modes
require('codemirror/mode/gfm/gfm.js'); //Github flavoured markdown
require('codemirror/mode/css/css.js');
require('codemirror/mode/javascript/javascript.js');
//Addons
//Code folding
require('codemirror/addon/fold/foldcode.js');
require('codemirror/addon/fold/foldgutter.js');
//Search and replace
require('codemirror/addon/search/search.js');
require('codemirror/addon/search/searchcursor.js');
require('codemirror/addon/search/jump-to-line.js');
require('codemirror/addon/search/match-highlighter.js');
require('codemirror/addon/search/matchesonscrollbar.js');
require('codemirror/addon/dialog/dialog.js');
//Trailing space highlighting
// require('codemirror/addon/edit/trailingspace.js');
//Active line highlighting
// require('codemirror/addon/selection/active-line.js');
//Scroll past last line
require('codemirror/addon/scroll/scrollpastend.js');
//Auto-closing
//XML code folding is a requirement of the auto-closing tag feature and is not enabled
require('codemirror/addon/fold/xml-fold.js');
require('codemirror/addon/edit/closetag.js');
const foldCode = require('./fold-code');
foldCode.registerHomebreweryHelper(CodeMirror);
}
const themeWidgets = require('../../../themes/V3/5ePHB/widgets');
const CodeEditor = createClass({
displayName : 'CodeEditor',
hintsRef : React.createRef(),
getDefaultProps : function() {
return {
language : '',
value : '',
wrap : true,
onChange : ()=>{},
enableFolding : true
enableFolding : true,
};
},
getInitialState : function() {
return {
docs : {}
docs : {},
widgetUtils : {},
widgets : {},
hints : [],
hintsField : undefined,
};
},
@@ -91,17 +65,23 @@ const CodeEditor = createClass({
} else {
this.codeMirror.setOption('foldOptions', false);
}
this.state.widgetUtils.updateWidgetGutter();
this.state.widgetUtils.updateAllLineWidgets();
},
buildEditor : function() {
this.codeMirror = CodeMirror(this.refs.editor, {
lineNumbers : true,
lineWrapping : this.props.wrap,
indentWithTabs : true,
indentWithTabs : false,
tabSize : 2,
smartIndent : false,
historyEventDelay : 250,
scrollPastEnd : true,
extraKeys : {
'Tab' : this.indent,
'Shift-Tab' : this.dedent,
'Ctrl-B' : this.makeBold,
'Cmd-B' : this.makeBold,
'Ctrl-I' : this.makeItalic,
@@ -152,7 +132,7 @@ const CodeEditor = createClass({
},
foldGutter : true,
foldOptions : this.foldOptions(this.codeMirror),
gutters : ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
gutters : ['CodeMirror-linenumbers', 'CodeMirror-foldgutter', 'widget-gutter'],
autoCloseTags : true,
styleActiveLine : true,
showTrailingSpace : false,
@@ -166,9 +146,82 @@ const CodeEditor = createClass({
});
closeTag.autoCloseCurlyBraces(CodeMirror, this.codeMirror);
this.setState({
widgetUtils : require('./helpers/widgets')(themeWidgets, this.codeMirror, (hints, field)=>{
this.setState({
hints,
hintsField : field
});
})
});
// Note: codeMirror passes a copy of itself in this callback. cm === this.codeMirror. Either one works.
this.codeMirror.on('change', (cm)=>{this.props.onChange(cm.getValue());});
this.codeMirror.on('change', (cm)=>{
this.props.onChange(cm.getValue());
this.state.widgetUtils.updateWidgetGutter();
});
this.codeMirror.on('cursorActivity', (cm)=>{
const { line } = cm.getCursor();
for (const key in this.state.widgets) {
if(key != line) {
this.state.widgetUtils.removeLineWidget(key, this.state.widgets[key]);
}
}
this.setState({
hints : [],
hintsField : undefined
});
const { widgets } = this.codeMirror.lineInfo(line);
if(!widgets) {
const widget = this.state.widgetUtils.updateLineWidgets(line);
if(widget) {
this.setState({
widgets : {
[line] : widget
}
});
}
}
});
this.updateSize();
this.codeMirror.on('gutterClick', (cm, n)=>{
// Open line widgets when 'widget-gutter' marker clicked
if(this.codeMirror.lineInfo(n).gutterMarkers?.['widget-gutter']) {
const { widgets } = this.codeMirror.lineInfo(n);
if(!widgets) {
const widget = this.state.widgetUtils.updateLineWidgets(n);
if(widget) {
this.setState({
widgets : { ...this.state.widgets, [n]: widget }
});
}
} else {
for (const widget of widgets) {
this.state.widgetUtils.removeLineWidget(n, widget);
}
this.setState({
hints : [],
hintsField : undefined
});
}
}
});
},
indent : function () {
const cm = this.codeMirror;
if(cm.somethingSelected()) {
cm.execCommand('indentMore');
} else {
cm.execCommand('insertSoftTab');
}
},
dedent : function () {
this.codeMirror.execCommand('indentLess');
},
makeHeader : function (number) {
@@ -387,10 +440,19 @@ const CodeEditor = createClass({
}
};
},
keyDown : function(e) {
if(this.hintsRef.current) {
this.hintsRef.current.keyDown(e);
}
},
//----------------------//
render : function(){
return <div className='codeEditor' ref='editor' style={this.props.style}/>;
const { hints, hintsField } = this.state;
return <React.Fragment>
<div className='codeEditor' ref='editor' style={this.props.style} onKeyDown={this.keyDown}/>
<Hints ref={this.hintsRef} hints={hints} field={hintsField}/>
</React.Fragment>;
}
});

View File

@@ -2,6 +2,8 @@
@import (less) 'codemirror/addon/fold/foldgutter.css';
@import (less) 'codemirror/addon/search/matchesonscrollbar.css';
@import (less) 'codemirror/addon/dialog/dialog.css';
@import (less) 'codemirror/addon/hint/show-hint.css';
@import 'naturalcrit/styles/colors.less';
@keyframes sourceMoveAnimation {
50% {background-color: red; color: white;}
@@ -14,7 +16,7 @@
text-shadow: none;
font-weight: 600;
color: grey;
}
}
.sourceMoveFlash .CodeMirror-line{
animation-name: sourceMoveAnimation;
@@ -30,4 +32,51 @@
// background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQAgMAAABW5NbuAAAACVBMVEVHcEwAAAAAAAAWawmTAAAAA3RSTlMAPBJ6PMxpAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAFUlEQVQI12NgwACcCQysASAEZGAAACMuAX06aCQUAAAAAElFTkSuQmCC) no-repeat right;
// }
//}
.widget-gutter {
width: .7em;
}
.snippet-options-widget {
padding: 2px 0;
>div {
display: flex;
flex-wrap: wrap;
}
* {
margin: 0 2px 2px 2px;
}
input {
max-width: 10vw;
}
}
.widget-field {
border: 2px solid #ddd;
&.default {
background-color: @purple;
border: 2px solid @purple;
color: white;
>input {
background-color: @purple;
color: white;
}
}
&.suggested {
background-color: #ddd;
border: 2px dashed grey;
color: grey;
>input {
background-color: #ddd;
color: black;
}
}
}
}

View File

@@ -0,0 +1,48 @@
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
require('./checkbox.less');
const CodeMirror = require('../../../code-mirror.js');
const Checkbox = createClass({
getDefaultProps : function() {
return {
value : '',
prefix : '',
cm : {},
n : -1,
default : false
};
},
handleChange : function (e) {
const { cm, n, value, prefix } = this.props;
const { text } = cm.lineInfo(n);
const updatedPrefix = `{{${prefix}`;
if(e.target?.checked)
cm.replaceRange(`,${value}`, CodeMirror.Pos(n, updatedPrefix.length), CodeMirror.Pos(n, updatedPrefix.length), '+insert');
else {
const start = text.indexOf(`,${value}`);
if(start > -1)
cm.replaceRange('', CodeMirror.Pos(n, start), CodeMirror.Pos(n, start + value.length + 1), '-delete');
}
},
render : function() {
const { cm, n, value, prefix, def } = this.props;
const { text } = cm.lineInfo(n);
const id = [prefix, value, n].join('-');
let className = 'widget-field widget-checkbox';
if(def) {
className += ' default';
}
return <React.Fragment>
<div className={className}>
<input type='checkbox' id={id} onChange={this.handleChange} checked={_.includes(text, `,${value}`)}/>
<label htmlFor={id}>{_.startCase(value)}</label>
</div>
</React.Fragment>;
}
});
module.exports = Checkbox;

View File

@@ -0,0 +1,7 @@
.widget-checkbox {
display: inline-block;
flex: 0 0 auto;
background-color: #ddd;
border-radius: 10px;
padding: 4px 2px;
}

View File

@@ -0,0 +1,95 @@
require('./color-selector.less');
const React = require('react');
const createClass = require('create-react-class');
const { PATTERNS, STYLE_FN, SNIPPET_TYPE } = require('../constants');
const CodeMirror = require('../../../code-mirror');
const debounce = require('lodash.debounce');
const ColorSelector = createClass({
getDefaultProps : function() {
return {
field : {},
cm : {},
n : undefined,
text : '',
def : false
};
},
getInitialState : function() {
return {
value : ''
};
},
componentDidMount : function() {
const { field, text } = this.props;
const pattern = PATTERNS.field[field.type](field.name);
const [_, __, value] = text.match(pattern) ?? [];
this.setState({
value : value,
});
},
componentDidUpdate({ text }) {
const { field } = this.props;
if(this.props.text !== text) {
const pattern = PATTERNS.field[field.type](field.name);
const [_, __, value] = this.props.text.match(pattern) ?? [];
this.setState({
value,
});
}
},
onChange : function(e) {
const { cm, text, field, n, snippetType } = this.props;
const pattern = PATTERNS.field[field.type](field.name);
const [_, label, current] = text.match(pattern) ?? [null, field.name, ''];
let index = text.indexOf(`${label}:${current}`);
while (index !== -1 && text[index - 1] === '-') {
index = text.indexOf(`${label}:${current}`, index + 1);
}
let value = e.target.value;
if(index === -1) {
if(snippetType === SNIPPET_TYPE.INLINE) {
index = text.indexOf('}');
}
index = index === -1 ? text.length : index;
value = `,${field.name}:${value}`;
} else {
index = index + 1 + field.name.length;
}
cm.replaceRange(value, CodeMirror.Pos(n, index), CodeMirror.Pos(n, index + current.length), '+insert');
this.setState({
value : e.target.value,
});
},
debounce : debounce((self, e)=>self.onChange(e), 300),
onChangeDebounce : function(e) {
this.setState({
value : e.target.value,
});
this.debounce(this, e);
},
render : function() {
const { field, n, text, def } = this.props;
const { value } = this.state;
const style = STYLE_FN(value);
const id = `${field?.name}-${n}`;
const pattern = PATTERNS.field[field.type](field.name);
const [_, label, __] = text.match(pattern) ?? [null, undefined, ''];
let className = 'widget-field color-selector';
if(!label) {
className += ' suggested';
}
if(def) {
className += ' default';
}
return <React.Fragment>
<div className={className}>
<label htmlFor={id}>{field.name}:</label>
<input className='color' type='color' value={value} onChange={this.onChangeDebounce}/>
<input id={id} className='text' type='text' style={style} value={value} onChange={this.onChange}/>
</div>
</React.Fragment>;
}
});
module.exports = ColorSelector;

View File

@@ -0,0 +1,8 @@
.color-selector {
.color {
height: 17px;
width: 13px;
padding: 0;
margin: 0;
}
}

View File

@@ -0,0 +1,50 @@
const _ = require('lodash');
export const UNITS = ['cm', 'mm', 'in', 'px', 'pt', 'pc', 'em', 'ex', 'ch', 'rem', 'vw', 'vh', 'vmin', 'vmax', '%'];
export const HINT_TYPE = {
VALUE : 0,
NUMBER_SUFFIX : 1
};
export const SNIPPET_TYPE = {
BLOCK : 0,
INLINE : 1,
INJECTOR : 2,
};
export const FIELD_TYPE = {
TEXT : 0,
CHECKBOX : 1,
IMAGE_SELECTOR : 2,
COLOR_SELECTOR : 3,
};
const textField = (name)=>new RegExp(`[{,;](${name}):([^};,"\\(]*\\((?!,)[^};"\\)]*\\)|"[^},;"]*"|[^},;]*)`);
export const PATTERNS = {
snippet : {
[SNIPPET_TYPE.BLOCK] : (name)=>new RegExp(`^{{${name}(?:[^a-zA-Z].*)?`),
[SNIPPET_TYPE.INLINE] : (name)=>new RegExp(`{{${name}`),
[SNIPPET_TYPE.INJECTOR] : ()=>new RegExp(`^\\!\\[(?:[a-zA-Z -]+)?\\]\\(.*\\).*{[a-zA-Z0-9:, "'-]+}$`),
},
field : {
[FIELD_TYPE.TEXT] : textField,
[FIELD_TYPE.IMAGE_SELECTOR] : (name)=>new RegExp(`{{(${name})(\\d*)`),
[FIELD_TYPE.COLOR_SELECTOR] : textField
},
collectStyles : new RegExp(`(?:([a-zA-Z-]+):(?!\\/))+`, 'g'),
};
export const NUMBER_PATTERN = new RegExp(`([^-\\d]*)([-\\d]+)(${UNITS.join('|')})?(.*)`);
export const fourDigitNumberFromValue = (value)=>typeof value === 'number' ? (()=>{
const str = String(value);
return _.range(0, 4 - str.length).map(()=>'0').join('') + str;
})() : value;
const DEFAULT_WIDTH = '30px';
export const STYLE_FN = (value, extras = {})=>({
width : `calc(${value?.length ?? 0}ch + ${value?.length ? `${DEFAULT_WIDTH} / 2` : DEFAULT_WIDTH})`,
...extras
});

View File

@@ -0,0 +1,128 @@
const React = require('react');
const createClass = require('create-react-class');
const { NUMBER_PATTERN } = require('../constants');
const Hints = createClass({
hintsRef : React.createRef(),
activeHintRef : React.createRef(),
getDefaultProps : function() {
return {
hints : [],
field : undefined,
};
},
getInitialState : function() {
return {
activeHint : 0
};
},
componentDidUpdate : function({ hints }) {
const hintsLength = this.props.hints.length;
if(hintsLength - 1 < this.state.activeHint && hintsLength !== hints.length) {
this.setState({
activeHint : hintsLength === 0 ? 0 : hintsLength - 1
});
return;
}
if(this.hintsRef.current && this.activeHintRef.current) {
const offset = this.activeHintRef.current.offsetTop;
const scrollTop = this.hintsRef.current.scrollTop;
if(scrollTop + 50 < offset || scrollTop + 50 > offset) {
this.hintsRef.current.scrollTo({
top : offset - 50,
behavior : 'smooth'
});
}
}
},
componentDidMount : function() {},
keyDown : function(e) {
const { code } = e;
const { activeHint } = this.state;
const { hints, field } = this.props;
const match = field?.state?.value?.match(NUMBER_PATTERN);
if(code === 'ArrowDown') {
e.preventDefault();
if(!match || !match?.at(3)) {
this.setState({
activeHint : activeHint === hints.length - 1 ? 0 : activeHint + 1
});
}
} else if(code === 'ArrowUp') {
e.preventDefault();
if(!match || !match?.at(3)) {
this.setState({
activeHint : activeHint === 0 ? hints.length - 1 : activeHint - 1
});
}
} else if(code === 'Enter') {
e.preventDefault();
if(!match || !match?.at(3)) {
field?.hintSelected(hints[activeHint]);
this.setState({
activeHint : 0
});
}
}
},
render : function() {
const { activeHint } = this.state;
const { hints, field } = this.props;
if(!field) return null;
const bounds = field.fieldRef[field.state.id]?.current?.getBoundingClientRect();
if(!bounds) return null;
const hintElements = hints
.filter((h)=>h.hint !== field.state.value)
.map((h, i)=>{
let className = 'CodeMirror-hint';
if(activeHint === i) {
className += ' CodeMirror-hint-active';
return <li key={i}
role={'option'}
className={className}
onMouseDown={(e)=>field.hintSelected(h, e)}
ref={this.activeHintRef}>
{h.hint}
</li>;
}
return <li key={i}
role={'option'}
className={className}
onMouseDown={(e)=>field.hintSelected(h, e)}>
{h.hint}
</li>;
});
let style = {
display : 'none'
};
if(hintElements.length > 0) {
style = {
...style,
display : 'block',
top : `${bounds.top - 5}px`,
left : `${bounds.left}px`
};
}
return <React.Fragment>
<ul role={'listbox'}
id={'hints'}
aria-expanded={true}
className={'CodeMirror-hints default'}
style={style}
ref={this.hintsRef}>
{hintElements}
</ul>
</React.Fragment>;
}
});
module.exports = Hints;

View File

@@ -0,0 +1,92 @@
require('./image-selector.less');
const React = require('react');
const createClass = require('create-react-class');
const { Modal, modalHelpers } = require('../modal/modal.jsx');
const { PATTERNS } = require('../constants.js');
const CodeMirror = require('../../../code-mirror.js');
const _ = require('lodash');
const ImageSelector = createClass({
modalRef : React.createRef(),
getDefaultProps : function () {
return {
field : {},
cm : {},
n : undefined
};
},
getInitialState : function() {
return {
selected : undefined,
};
},
componentDidMount : function() {
modalHelpers.mount(this);
},
componentDidUpdate : function() {
const { name, preview, values } = this.props.field;
const { selected } = this.state;
const images = values.map((v, i)=>{
const className = String(selected) === String(v) ? 'selected' : '';
return <img key={i} className={className} src={preview(v)} alt={`${name} image ${v}`} onClick={()=>this.select(v)}/>;
});
this.state.modalRoot?.render(<Modal ref={this.modalRef} header={_.startCase(name)} save={this.save}>
<div className={'images'}>
{images}
</div>
</Modal>);
},
componentWillUnmount : function() {
modalHelpers.unmount(this);
},
save : function() {
const { cm, field, n } = this.props;
const { text } = cm.lineInfo(n);
const pattern = PATTERNS.field[field.type](field.name);
const [fullmatch, label, current] = text.match(pattern);
if(!fullmatch) {
console.warn('something is wrong... please report this warning with a screenshot');
return;
}
const currentText = `${label}${current ?? ''}`;
const index = 2;
const value = label + this.state.selected;
cm.replaceRange(value, CodeMirror.Pos(n, index), CodeMirror.Pos(n, index + currentText.length), '+insert');
},
select : function(value) {
this.setState({
selected : value
});
},
showModal : function() {
const { cm, field, n } = this.props;
const { text } = cm.lineInfo(n);
const pattern = PATTERNS.field[field.type](field.name);
const [fullmatch, _, current] = text.match(pattern);
if(!fullmatch) {
return;
}
this.setState({
selected : current
});
this.modalRef.current.setVisible(true);
},
render : function () {
return <React.Fragment>
<button onClick={this.showModal}>Select Image</button>
</React.Fragment>;
}
});
module.exports = ImageSelector;

View File

@@ -0,0 +1,23 @@
.images {
display: flex;
flex-direction: row;
flex-wrap: wrap;
max-height: 60vh;
overflow-y: scroll;
img {
flex: 0 0 auto;
max-width: 10vw;
max-height: 20vh;
border-radius: 10px;
&:hover {
background-color: rgba(0, 0, 0, .1);
}
&.selected {
background-color: rgba(0, 0, 0, .175);
}
}
}

View File

@@ -0,0 +1,11 @@
const Text = require('./text/text.jsx');
const Checkbox = require('./checkbox/checkbox.jsx');
const ImageSelector = require('./image-selector/image-selector.jsx');
const ColorSelector = require('./color-selector/color-selector.jsx');
module.exports = {
Text : Text,
Checkbox : Checkbox,
ImageSelector : ImageSelector,
ColorSelector : ColorSelector,
};

View File

@@ -0,0 +1,75 @@
require('./modal.less');
const React = require('react');
const ReactDOMClient = require('react-dom/client');
const createClass = require('create-react-class');
const Modal = createClass({
getDefaultProps : function () {
return {
header : '',
save : ()=>{},
};
},
getInitialState : function() {
return {
visible : false,
};
},
setVisible : function(visible) {
this.setState({
visible
});
},
save : function() {
this.props.save();
this.setVisible(false);
},
render : function () {
const { children, header } = this.props;
const { visible } = this.state;
return <React.Fragment>
{visible ? <div className={'bg-cover'}>
<div className={'modal'}>
<h1>{header}</h1>
<hr/>
{children}
<div className={'action-row'}>
<button id={'save'} onClick={()=>this.save()}>Save</button>
<button id={'cancel'} onClick={()=>this.setVisible(false)}>Cancel</button>
</div>
</div>
</div> : null}
</React.Fragment>;
}
});
module.exports = {
/*
* Requirements:
* - modalRef member variable
* - should be re-rendered via `this.state.modalRoot?.render` in `componentDidUpdate`
*/
Modal,
modalHelpers : {
// should be called in `componentDidMount`
// `self` should be passed as the component instance (`this`)
mount : (self)=>{
const el = document.createElement('div');
const root = ReactDOMClient.createRoot(el);
document.querySelector('body').append(el);
self.setState({
el,
modalRoot : root
});
},
// should be called in `componentWillUnmount`
// `self` should be passed as the component instance (`this`)
unmount : (self)=>{
self.state.el.remove();
}
}
};

View File

@@ -0,0 +1,58 @@
@import 'naturalcrit/styles/colors.less';
.bg-cover {
width: 100vw;
height: 100vh;
position: absolute;
z-index: 10000000;
top: 0;
left: 0;
background-color: rgba(0, 0, 0, .5);
}
.modal {
position: absolute;
top: 10vh;
left: 25vw;
width: 50vw;
min-height: 50vh;
max-height: 80vh;
background-color: #fff;
border-radius: 10px;
box-shadow: 5px 5px 50px black;
display: flex;
flex-direction: column;
justify-content: space-between;
h1 {
margin-top: 5px;
margin-left: 5px;
font-size: 2em;
}
>* {
flex: 0 0 auto;
}
.action-row {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: left;
>* {
flex: 0 0 auto;
margin-left: 5px;
}
}
button {
&#cancel {
background-color: @redLight;
&:hover {
background-color: @red;
}
}
}
}

View File

@@ -0,0 +1,165 @@
require('./text.less');
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const { NUMBER_PATTERN, HINT_TYPE, PATTERNS, STYLE_FN, FIELD_TYPE, SNIPPET_TYPE } = require('../constants');
const CodeMirror = require('../../../code-mirror.js');
const Text = createClass({
fieldRef : {},
getDefaultProps : function() {
return {
field : {},
text : '',
n : 0,
setHints : ()=>{},
onChange : ()=>{},
getStyleHints : ()=>{},
def : false,
snippetType : -1
};
},
getInitialState : function() {
return {
value : '',
id : ''
};
},
componentDidUpdate : function({ text }, { value }) {
if(this.props.text !== text) {
const { field, n } = this.props;
const pattern = PATTERNS.field[field.type](field.name);
const [_, __, value] = this.props.text.match(pattern) ?? [];
this.setState({
value : value,
id : `${field?.name}-${n}`
});
}
if(this.state.value !== value) {
const { field } = this.props;
this.props.setHints(this, field.hints ? this.props.getStyleHints(field, this.state.value) : []);
}
},
componentDidMount : function() {
const { field, text, n } = this.props;
const id = `${field?.name}-${n}`;
const pattern = PATTERNS.field[field.type](field.name);
const [_, __, value] = text.match(pattern) ?? [];
this.setState({
value : value,
id
});
this.fieldRef[id] = React.createRef();
},
componentWillUnmount : function() {
this.fieldRef = undefined;
this.fieldRef = {};
this.fieldRef[this.state.id]?.remove();
},
setFocus : function(e) {
const { type } = e;
const { field } = this.props;
this.props.setHints(this, type === 'focus' && field.hints ? this.props.getStyleHints(field, this.state.value) : []);
},
hintSelected : function(h, e) {
let value;
if(h?.type === HINT_TYPE.VALUE) {
value = h.hint;
} else if(h?.type === HINT_TYPE.NUMBER_SUFFIX) {
const match = this.state.value.match(NUMBER_PATTERN);
let suffix = match?.at(4) ?? '';
for (const char of h.hint) {
if(suffix.at(0) === char) {
suffix = suffix.slice(1);
}
}
value = `${match?.at(1) ?? ''}${match?.at(2) ?? ''}${h.hint}${suffix}`;
}
this.onChange({
target : {
value
}
});
},
keyDown : function(e) {
const { code } = e;
const { field } = this.props;
const { value } = this.state;
const match = value?.match(NUMBER_PATTERN);
if(code === 'ArrowDown') {
if(match && CSS.supports(field.name, value)) {
e.preventDefault();
this.onChange({
target : {
value : `${match.at(1) ?? ''}${Number(match[2]) - field.increment}${match[3] ?? ''}${match.at(4) ?? ''}`
}
});
}
} else if(code === 'ArrowUp') {
if(match && CSS.supports(field.name, value)) {
e.preventDefault();
this.onChange({
target : {
value : `${match.at(1) ?? ''}${Number(match[2]) + field.increment}${match[3] ?? ''}${match.at(4) ?? ''}`
}
});
}
}
},
onChange : function (e){
const { cm, text, field, n, snippetType } = this.props;
const pattern = PATTERNS.field[field.type](field.name);
const [_, label, current] = text.match(pattern) ?? [null, field.name, ''];
let index = text.indexOf(`${label}:${current}`);
let value = e.target.value;
if(index === -1) {
if(snippetType === SNIPPET_TYPE.INLINE) {
index = text.indexOf('}');
}
index = index === -1 ? text.length : index;
value = `,${field.name}:${value}`;
} else {
index = index + 1 + field.name.length;
}
cm.replaceRange(value, CodeMirror.Pos(n, index), CodeMirror.Pos(n, index + current.length), '+insert');
this.setState({
value : e.target.value,
});
},
render : function() {
const { value, id } = this.state;
const { field, text, def } = this.props;
const style = STYLE_FN(value);
const pattern = PATTERNS.field[field.type](field.name);
const [_, label, __] = text.match(pattern) ?? [null, undefined, ''];
let className = 'widget-field';
if(!label) {
className += ' suggested';
}
if(def) {
className += ' default';
}
return <React.Fragment>
<div className={className}>
<label htmlFor={id}>{field.name}:</label>
<input id={id} type='text' value={value}
style={style}
ref={this.fieldRef[id]}
onChange={this.onChange}
onFocus={this.setFocus}
onBlur={this.setFocus}
onKeyDown={this.keyDown}/>
</div>
</React.Fragment>;
}
});
module.exports = Text;

View File

@@ -0,0 +1,37 @@
.widget-field {
display: inline-block;
flex: 0 0 auto;
background-color: #ddd;
border-radius: 10px;
padding: 4px 2px;
>label {
display: inline;
width: 50px;
margin: 0 0;
}
>input {
background-color: #ddd;
border: none;
}
>.hints {
position: relative;
left: 30px;
max-height: 100px;
overflow-y: scroll;
background-color: white;
>.hint {
margin: 0 0;
padding: 2px;
cursor: default;
&:hover,
&.active {
background-color: rgba(0, 0, 0, 0.1);
}
}
}
}

View File

@@ -0,0 +1,188 @@
const React = require('react');
const ReactDOMClient = require('react-dom/client');
const { PATTERNS, FIELD_TYPE, HINT_TYPE, UNITS } = require('./widget-elements/constants');
require('./widget-elements/hints/hints.jsx');
const { Text, Checkbox, ImageSelector, ColorSelector } = require('./widget-elements');
const CodeMirror = require('../code-mirror.js');
// See https://codemirror.net/5/addon/hint/css-hint.js for code reference
const pseudoClasses = { 'active' : 1, 'after' : 1, 'before' : 1, 'checked' : 1, 'default' : 1,
'disabled' : 1, 'empty' : 1, 'enabled' : 1, 'first-child' : 1, 'first-letter' : 1,
'first-line' : 1, 'first-of-type' : 1, 'focus' : 1, 'hover' : 1, 'in-range' : 1,
'indeterminate' : 1, 'invalid' : 1, 'lang' : 1, 'last-child' : 1, 'last-of-type' : 1,
'link' : 1, 'not' : 1, 'nth-child' : 1, 'nth-last-child' : 1, 'nth-last-of-type' : 1,
'nth-of-type' : 1, 'only-of-type' : 1, 'only-child' : 1, 'optional' : 1, 'out-of-range' : 1,
'placeholder' : 1, 'read-only' : 1, 'read-write' : 1, 'required' : 1, 'root' : 1,
'selection' : 1, 'target' : 1, 'valid' : 1, 'visited' : 1
};
const genKey = (...args)=>args.join('-');
module.exports = function(widgets, cm, setHints) {
const roots = {};
const spec = CodeMirror.resolveMode('text/css');
const headless = CodeMirror(()=>{});
const makeTempCSSDoc = (value)=>CodeMirror.Doc(`.selector {\n${value}\n}`, 'text/css');
// See https://codemirror.net/5/addon/hint/css-hint.js for code reference
const getStyleHints = (field, value)=>{
const tempDoc = makeTempCSSDoc(`${field.name}:${value?.replaceAll(`'"`, '') ?? ''}`);
headless.swapDoc(tempDoc);
const pos = CodeMirror.Pos(1, field.name.length + 1 + (value?.length ?? 0), false);
const token = headless.getTokenAt(pos);
const inner = CodeMirror.innerMode(tempDoc.getMode(), token?.state);
if(inner.mode.name !== 'css') return;
if(token.type === 'keyword' && '!important'.indexOf(token.string) === 0)
return { list : ['!important'], from : CodeMirror.Pos(pos.line, token.start),
to : CodeMirror.Pos(pos.line, token.end) };
let start = token.start, end = pos.ch, word = token.string.slice(0, end - start);
if(/[^\w$_-]/.test(word)) {
word = ''; start = end = pos.ch;
}
let result = [];
const add = (keywords)=>{
for (const name in keywords)
if(!word || name.lastIndexOf(word, 0) === 0)
result.push(name);
};
const st = inner.state.state;
if(st === 'pseudo' || token.type === 'variable-3') {
add(pseudoClasses);
} else if(st === 'block' || st === 'maybeprop') {
add(spec.propertyKeywords);
} else if(st === 'prop' || st === 'parens' || st === 'at' || st === 'params') {
add(spec.valueKeywords);
add(spec.colorKeywords);
} else if(st === 'media' || st === 'media_parens') {
add(spec.mediaTypes);
add(spec.mediaFeatures);
}
result = result.map((h)=>({ hint: h, type: HINT_TYPE.VALUE }))
.filter((h)=>CSS.supports(field.name, h.hint) && h.hint.includes(value ?? ''));
const numberSuffix = word.slice(-4).replaceAll(/\d/g, '');
if(token.type === 'number' && !UNITS.includes(numberSuffix)) {
result.push(...UNITS
.filter((u)=>u.includes(numberSuffix) && CSS.supports(field.name, `${value.replaceAll(/\D/g, '') ?? ''}${u}`))
.map((u)=>({ hint: u, type: HINT_TYPE.NUMBER_SUFFIX }))
);
}
return result;
};
const widgetOptions = widgets.map((widget)=>({
name : widget.name,
pattern : PATTERNS.snippet[widget.type](widget.name),
renderWidget : (n, node)=>{
roots[n] = roots[n] ?? {};
const parent = document.createElement('div');
const id = `${widget.name}-${n}`;
parent.id = id;
const textFieldNames = (widget.fields || []).filter((f)=>f.type === FIELD_TYPE.TEXT || f.type === FIELD_TYPE.COLOR_SELECTOR).map((f)=>f.name);
const { text } = cm.lineInfo(n);
const fields = (widget.fields || []).map((field)=>{
const key = genKey(widget.name, n, field.name);
if(field.type === FIELD_TYPE.CHECKBOX) {
return <Checkbox key={key} cm={cm} n={n} prefix={widget.name} value={field.name} def={true}/>;
} else if(field.type === FIELD_TYPE.TEXT) {
return <Text key={key} field={field} cm={cm} n={n} text={text} setHints={(f, h)=>setHints(h, f)} getStyleHints={getStyleHints} def={true} snippetType={widget.type}/>;
} else if(field.type === FIELD_TYPE.IMAGE_SELECTOR) {
return <ImageSelector key={key} field={field} cm={cm} n={n}/>;
} else if(field.type === FIELD_TYPE.COLOR_SELECTOR) {
return <ColorSelector key={key} field={field} cm={cm} n={n} text={text} def={true} snippetType={widget.type}/>;
} else {
return null;
}
}).filter(Boolean);
const styles = [...text.matchAll(PATTERNS.collectStyles)].map(([_, style])=>{
if(textFieldNames.includes(style)) return false;
const field = {
name : style,
type : FIELD_TYPE.TEXT,
increment : 5,
hints : true,
};
const key = genKey(widget.name, n, style);
if(style.includes('color')) {
return <ColorSelector key={key} field={field} cm={cm} n={n} text={text} snippetType={widget.type}/>;
}
return <Text key={key} field={field} cm={cm} n={n} text={text} setHints={(f, h)=>setHints(h, f)} getStyleHints={getStyleHints} snippetType={widget.type}/>;
}).filter(Boolean);
const root = roots[n][id] ?? ReactDOMClient.createRoot(node || parent);
root.render(<React.Fragment>
{fields}
{styles}
</React.Fragment>);
roots[n][id] = root;
return node || parent;
}
}));
const updateLineWidgets = (n)=>{
const { text, widgets } = cm.lineInfo(n);
const widgetOption = widgetOptions.find((option)=>!!text.match(option.pattern));
if(!widgetOption) return;
if(!!widgets) {
for (const widget of widgets) {
widgetOption.renderWidget(n, widget.node);
}
} else {
return cm.addLineWidget(n, widgetOption.renderWidget(n), {
above : false,
coverGutter : false,
noHScroll : true,
className : `snippet-options-widget ${widgetOption.name}-widget ${widgetOption.name}-widget-${n}`
});
}
};
return {
roots,
removeLineWidget : (n, widget)=>{
roots[n][widget.node.id]?.unmount();
delete roots[n][widget.node.id];
widget?.clear();
},
updateLineWidgets,
updateAllLineWidgets : ()=>{
for (let i = 0; i < cm.lineCount(); i++) {
const { widgets } = cm.lineInfo(i);
if(!!widgets) {
updateLineWidgets(i);
}
}
},
updateWidgetGutter : ()=>{
cm.operation(()=>{
for (let i = 0; i < cm.lineCount(); i++) {
const { text, widgets } = cm.lineInfo(i);
if(widgetOptions.some((option)=>text.match(option.pattern))) {
if(widgets) {
continue;
}
const optionsMarker = document.createElement('div');
optionsMarker.style.color = '#822';
optionsMarker.style.cursor = 'pointer';
optionsMarker.innerHTML = '●';
cm.setGutterMarker(i, 'widget-gutter', optionsMarker);
} else {
cm.setGutterMarker(i, 'widget-gutter', null);
}
}
});
}
};
};

View File

@@ -2,6 +2,8 @@
const _ = require('lodash');
const Marked = require('marked');
const MarkedExtendedTables = require('marked-extended-tables');
const { markedSmartypantsLite: MarkedSmartypantsLite } = require('marked-smartypants-lite');
const { gfmHeadingId: MarkedGFMHeadingId } = require('marked-gfm-heading-id');
const renderer = new Marked.Renderer();
//Processes the markdown within an HTML block if it's just a class-wrapper
@@ -237,9 +239,9 @@ const definitionLists = {
};
Marked.use({ extensions: [mustacheSpans, mustacheDivs, mustacheInjectInline, definitionLists] });
Marked.use(MarkedExtendedTables());
Marked.use(mustacheInjectBlock);
Marked.use({ renderer: renderer, smartypants: true });
Marked.use({ renderer: renderer, mangle: false });
Marked.use(MarkedExtendedTables(), MarkedGFMHeadingId(), MarkedSmartypantsLite());
//Fix local links in the Preview iFrame to link inside the frame
renderer.link = function (href, title, text) {
@@ -311,12 +313,6 @@ const escape = function (html, encode) {
return html;
};
const sanatizeScriptTags = (content)=>{
return content
.replace(/<script/ig, '&lt;script')
.replace(/<\/script>/ig, '&lt;/script&gt;');
};
const tagTypes = ['div', 'span', 'a'];
const tagRegex = new RegExp(`(${
_.map(tagTypes, (type)=>{
@@ -347,7 +343,7 @@ module.exports = {
render : (rawBrewText)=>{
rawBrewText = rawBrewText.replace(/^\\column$/gm, `\n<div class='columnSplit'></div>\n`)
.replace(/^(:+)$/gm, (match)=>`${`<div class='blank'></div>`.repeat(match.length)}\n`);
return Marked.parse(sanatizeScriptTags(rawBrewText));
return Marked.parse(rawBrewText);
},
validate : (rawBrewText)=>{

View File

@@ -90,12 +90,6 @@ const escape = function (html, encode) {
return html;
};
const sanatizeScriptTags = (content)=>{
return content
.replace(/<script/ig, '&lt;script')
.replace(/<\/script>/ig, '&lt;/script&gt;');
};
const tagTypes = ['div', 'span', 'a'];
const tagRegex = new RegExp(`(${
_.map(tagTypes, (type)=>{
@@ -113,7 +107,7 @@ module.exports = {
marked : Markdown,
render : (rawBrewText)=>{
return Markdown(
sanatizeScriptTags(rawBrewText),
rawBrewText,
{ renderer: renderer }
);
},

View File

@@ -1,5 +1,6 @@
require('./nav.less');
const React = require('react');
const { useState, useRef, useEffect } = React;
const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
@@ -71,64 +72,49 @@ const Nav = {
}
}),
dropdown : createClass({
displayName : 'Nav.dropdown',
getDefaultProps : function() {
return {
trigger : 'hover'
};
},
getInitialState : function() {
return {
showDropdown : false
};
},
componentDidMount : function() {
if(this.props.trigger == 'click')
document.addEventListener('click', this.handleClickOutside);
},
componentWillUnmount : function() {
if(this.props.trigger == 'click')
document.removeEventListener('click', this.handleClickOutside);
},
handleClickOutside : function(e){
// Close dropdown when clicked outside
if(this.refs.dropdown && !this.refs.dropdown.contains(e.target)) {
this.handleDropdown(false);
}
},
handleDropdown : function(show){
this.setState({
showDropdown : show
});
},
renderDropdown : function(dropdownChildren){
if(!this.state.showDropdown) return null;
dropdown : function dropdown(props) {
props = Object.assign({}, props, {
trigger : 'hover click'
});
return (
<div className='navDropdown'>
{dropdownChildren}
</div>
);
},
render : function () {
const dropdownChildren = React.Children.map(this.props.children, (child, i)=>{
// Ignore the first child
if(i < 1) return;
return child;
});
return (
<div className={`navDropdownContainer ${this.props.className}`}
ref='dropdown'
onMouseEnter={this.props.trigger == 'hover' ? ()=>{this.handleDropdown(true);} : undefined}
onClick= {this.props.trigger == 'click' ? ()=>{this.handleDropdown(true);} : undefined}
onMouseLeave={this.props.trigger == 'hover' ? ()=>{this.handleDropdown(false);} : undefined}>
{this.props.children[0] || this.props.children /*children is not an array when only one child*/}
{this.renderDropdown(dropdownChildren)}
</div>
);
const myRef = useRef(null);
const [showDropdown, setShowDropdown] = useState(false);
useEffect(()=>{
document.addEventListener('click', handleClickOutside);
return ()=>{
document.removeEventListener('click', handleClickOutside);
};
}, []);
function handleClickOutside(e) {
// Close dropdown when clicked outside
if(!myRef.current?.contains(e.target)) {
handleDropdown(false);
}
}
})
function handleDropdown(show) {
setShowDropdown(show ?? !showDropdown);
}
const dropdownChildren = React.Children.map(props.children, (child, i)=>{
if(i < 1) return;
return child;
});
return (
<div className={`navDropdownContainer ${props.className}`}
ref={myRef}
onMouseEnter = { props.trigger.includes('hover') ? ()=>handleDropdown(true) : undefined }
onMouseLeave = { props.trigger.includes('hover') ? ()=>handleDropdown(false) : undefined }
onClick = { props.trigger.includes('click') ? ()=>handleDropdown(true) : undefined }
>
{props.children[0] || props.children /*children is not an array when only one child*/}
{showDropdown && <div className='navDropdown'>{dropdownChildren}</div>}
</div>
);
}
};

View File

@@ -79,6 +79,8 @@ nav{
left : 0px;
z-index : 10000;
width : 100%;
overflow : hidden auto;
max-height : calc(100vh - 28px);
.navItem{
animation-name: glideDropDown;
animation-duration: 0.4s;

View File

@@ -0,0 +1,58 @@
const stylelint = require('stylelint');
const { isNumber } = require('stylelint/lib/utils/validateTypes');
const { report, ruleMessages, validateOptions } = stylelint.utils;
const ruleName = 'naturalcrit/declaration-block-multi-line-min-declarations';
const messages = ruleMessages(ruleName, {
expected : (decls)=>`Rule with ${decls} declaration${decls == 1 ? '' : 's'} should be single line`,
});
module.exports = stylelint.createPlugin(ruleName, function getPlugin(primaryOption, secondaryOptionObject, context) {
return function lint(postcssRoot, postcssResult) {
const validOptions = validateOptions(
postcssResult,
ruleName,
{
actual : primaryOption,
possible : [isNumber],
}
);
if(!validOptions) { //If the options are invalid, don't lint
return;
}
const isAutoFixing = Boolean(context.fix);
postcssRoot.walkRules((rule)=>{ //Iterate CSS rules
//Apply rule only if all children are decls (no further nested rules)
if(rule.nodes.length > primaryOption || !rule.nodes.every((node)=>node.type === 'decl')) {
return;
}
//Ignore if already one line
if(!rule.nodes.some((node)=>node.raws.before.includes('\n')) && !rule.raws.after.includes('\n'))
return;
if(isAutoFixing) { //We are in “fix” mode
rule.each((decl)=>{
decl.raws.before = ' ';
});
rule.raws.after = ' ';
} else {
report({
ruleName,
result : postcssResult,
message : messages.expected(rule.nodes.length), // Build the reported message
node : rule, // Specify the reported node
word : rule.selector, // Which exact word caused the error? This positions the error properly
});
}
});
};
});
module.exports.ruleName = ruleName;
module.exports.messages = messages;

View File

@@ -0,0 +1,68 @@
const stylelint = require('stylelint');
const { report, ruleMessages, validateOptions } = stylelint.utils;
const ruleName = 'naturalcrit/declaration-colon-align';
const messages = ruleMessages(ruleName, {
expected : (rule)=>`Expected colons aligned within rule "${rule}"`,
});
module.exports = stylelint.createPlugin(ruleName, function getPlugin(primaryOption, secondaryOptionObject, context) {
return function lint(postcssRoot, postcssResult) {
const validOptions = validateOptions(
postcssResult,
ruleName,
{
actual : primaryOption,
possible : [
true,
false
]
}
);
if(!validOptions) { //If the options are invalid, don't lint
return;
}
const isAutoFixing = Boolean(context.fix);
postcssRoot.walkRules((rule)=>{ //Iterate CSS rules
let maxColonPos = 0;
let misaligned = false;
rule.each((declaration)=>{
if(declaration.type != 'decl')
return;
const colonPos = declaration.prop.length + declaration.raws.between.indexOf(':');
if(maxColonPos > 0 && colonPos != maxColonPos) {
misaligned = true;
}
maxColonPos = Math.max(maxColonPos, colonPos);
});
if(misaligned) {
if(isAutoFixing) { //We are in “fix” mode
rule.each((declaration)=>{
if(declaration.type != 'decl')
return;
declaration.raws.between = `${' '.repeat(maxColonPos - declaration.prop.length)}:${declaration.raws.between.split(':')[1]}`;
});
} else { //We are in “report only” mode
report({
ruleName,
result : postcssResult,
message : messages.expected(rule.selector), // Build the reported message
node : rule, // Specify the reported node
word : rule.selector, // Which exact word caused the error? This positions the error properly
});
}
}
});
};
});
module.exports.ruleName = ruleName;
module.exports.messages = messages;

View File

@@ -0,0 +1,52 @@
const stylelint = require('stylelint');
const { isNumber } = require('stylelint/lib/utils/validateTypes');
const { report, ruleMessages, validateOptions } = stylelint.utils;
const ruleName = 'naturalcrit/declaration-colon-min-space-before';
const messages = ruleMessages(ruleName, {
expected : (num)=>`Expected at least ${num} space${num == 1 ? '' : 's'} before ":"`
});
module.exports = stylelint.createPlugin(ruleName, function getPlugin(primaryOption, secondaryOptionObject, context) {
return function lint(postcssRoot, postcssResult) {
const validOptions = validateOptions(
postcssResult,
ruleName,
{
actual : primaryOption,
possible : [isNumber],
}
);
if(!validOptions) { //If the options are invalid, don't lint
return;
}
const isAutoFixing = Boolean(context.fix);
postcssRoot.walkDecls((decl)=>{ //Iterate CSS declarations
const between = decl.raws.between;
const colonIndex = between.indexOf(':');
if(between.slice(0, colonIndex).length >= primaryOption) {
return;
}
if(isAutoFixing) { //We are in “fix” mode
decl.raws.between = between.slice(0, colonIndex).replace(/\s*$/, ' '.repeat(primaryOption)) + between.slice(colonIndex);
} else {
report({
ruleName,
result : postcssResult,
message : messages.expected(primaryOption), // Build the reported message
node : decl, // Specify the reported node
word : ':', // Which exact word caused the error? This positions the error properly
});
}
});
};
});
module.exports.ruleName = ruleName;
module.exports.messages = messages;

View File

@@ -2,12 +2,6 @@
const Markdown = require('naturalcrit/markdown.js');
test('Escapes <script> tag', function() {
const source = '<script></script>';
const rendered = Markdown.render(source);
expect(rendered).toMatch('&lt;script&gt;&lt;/script&gt;');
});
test('Processes the markdown within an HTML block if its just a class wrapper', function() {
const source = '<div>*Bold text*</div>';
const rendered = Markdown.render(source);

View File

@@ -47,8 +47,8 @@ const getTOC = (pages)=>{
return res;
};
module.exports = function(brew){
const pages = brew.text.split('\\page');
module.exports = function(props){
const pages = props.brew.text.split('\\page');
const TOC = getTOC(pages);
const markdown = _.reduce(TOC, (r, g1, idx1)=>{
r.push(`- **[${idx1 + 1} ${g1.title}](#p${g1.page})**`);

View File

@@ -1,3 +1,5 @@
@import (less) './themes/assets/assets.less';
:root {
//Colors
--HB_Color_Accent : #EBCEC3; // Salmon
@@ -17,3 +19,10 @@
bottom : 40px;
}
}
.page:has(.partCover) {
.partCover {
background-image: @partCoverHeaderDMG;
}
}

View File

@@ -7,6 +7,7 @@ const scriptGen = require('./snippets/script.gen.js');
const ClassFeatureGen = require('./snippets/classfeature.gen.js');
const CoverPageGen = require('./snippets/coverpage.gen.js');
const TableOfContentsGen = require('./snippets/tableOfContents.gen.js');
const indexGen = require('./snippets/index.gen.js');
const dedent = require('dedent-tabs').default;
@@ -18,20 +19,16 @@ module.exports = [
icon : 'fas fa-pencil-alt',
view : 'text',
snippets : [
{
name : 'Page Number',
icon : 'fas fa-bookmark',
gen : '{{pageNumber 1}}\n{{footnote PART 1 | SECTION NAME}}\n\n'
},
{
name : 'Auto-incrementing Page Number',
icon : 'fas fa-sort-numeric-down',
gen : '{{pageNumber,auto}}\n{{footnote PART 1 | SECTION NAME}}\n\n'
},
{
name : 'Table of Contents',
icon : 'fas fa-book',
gen : TableOfContentsGen
},
{
name : 'Index',
icon : 'fas fa-bars',
gen : indexGen,
experimental : true
}
]
},
@@ -181,6 +178,18 @@ module.exports = [
gen : CoverPageGen.inside,
experimental : true
},
{
name : 'Part Cover Page',
icon : 'fac book-part-cover',
gen : CoverPageGen.part,
experimental : true
},
{
name : 'Back Cover Page',
icon : 'fac book-back-cover',
gen : CoverPageGen.back,
experimental : true
},
{
name : 'Magic Item',
icon : 'fas fa-hat-wizard',
@@ -197,7 +206,7 @@ module.exports = [
}}
\n`;
},
},
}
]
},

View File

@@ -68,13 +68,23 @@ const footnote = [
'In an amazing kingdom, in an age of sorcery and lost souls, eight space pirates quest for freedom.'
];
const coverText = [
'Embark on a thrilling journey across a vast and varied world, where magic and mystery await you at every turn. Encounter strange creatures and ancient secrets, and forge your own destiny with your choices. The world is yours to shape and explore.',
'Join a band of brave adventurers and set out to explore the unknown lands beyond the horizon. Along the way, youll face perilous challenges, make new friends and enemies, and uncover a plot that threatens to destroy everything you hold dear. The fate of the world rests in your hands.',
'Create your own character and enter a realm of endless possibilities, where you can be whoever you want to be. Whether you prefer to fight, sneak, charm, or craft your way through the game, youll find a style that suits you. The only limit is your imagination.',
'Experience a rich and immersive story that adapts to your actions and decisions. Every choice you make has consequences, for good or ill. Will you be a hero or a villain? A leader or a follower? A friend or a foe? The choice is yours.',
'Dive into a world of epic fantasy and adventure, where you can explore ancient civilizations, dark dungeons, and hidden secrets. Along the way, youll meet colorful characters, collect powerful items, and learn new skills. The more you play, the more youll discover.',
'Explore a vast and dynamic world that changes according to your actions. You can shape the environment, influence the politics, and alter the history of the game world. But be careful, as every change has a ripple effect that may have unforeseen consequences.',
'Enter a world of wonder and danger, where you can find allies and enemies among the various races and factions that inhabit it. You can choose to join or oppose any of them, or forge your own path. The game world is alive and responsive to your actions.'
];
module.exports = {
front : function() {
return dedent`
{{frontCover}}
{{logo ![](/assets/naturalCritLogo.svg)}}
{{logo ![](/assets/naturalCritLogoRed.svg)}}
# ${_.sample(titles)}
## ${_.sample(subtitles)}
@@ -100,10 +110,46 @@ module.exports = {
___
{{imageMaskCenter${_.random(1, 16)},--offsetX:0%,--offsetY:0%,--rotation:0
![](https://i.imgur.com/IsfUnFR.jpg){height:100%}
![background image](https://i.imgur.com/IsfUnFR.jpg){position:absolute,bottom:0,left:0,height:100%}
}}
{{logo ![](/assets/naturalCritLogo.svg)}}
{{logo ![](/assets/naturalCritLogoRed.svg)}}
\page`;
},
part : function() {
return dedent`
{{partCover}}
# PART X
## ${_.sample(subtitles)}
{{imageMaskEdge${_.random(1, 8)},--offset:10cm,--rotation:180
![Background image](https://i.imgur.com/9TU96xY.jpg){position:absolute,bottom:0,left:0,height:100%}
}}
\page`;
},
back : function() {
return dedent`
{{backCover}}
# ${_.sample(subtitles)}
${_.sampleSize(coverText, 3).join('\n:\n')}
___
For use with any fantasy roleplaying ruleset. Play the best game of your life!
![background image](https://i.imgur.com/MJ4YHu7.jpg){position:absolute,bottom:0,left:0,height:100%}
{{logo
![](/assets/naturalCritLogoWhite.svg)
Homebrewery.Naturalcrit.com
}}
\page`;
}

View File

@@ -0,0 +1,85 @@
const dedent = require('dedent-tabs').default;
module.exports = ()=>{
return dedent`
{{index,wide,columns:5;
##### Index
- Ankhesh-Bort
- city map, 7
- city watch, 12
- guilds, 19
- Cheese
- types of cheese, 8
- cheese-related magic, 14
- cheese-related quests, 26-27
- Death
- appearance, 10
- personality, 13
- hobbies, 23
- Elves
- types of elves, 15
- elvish magic, 24
- elvish curses, 28
- Footnotes
- types of footnotes, 16-17
- footnote rules, 20-21
- footnote humor, 29-30
- Gods
- types of gods, 12
- godly interventions, 25
- godly conflicts, 31
- Heroes
- class features, 11-12
- heroic deeds, 26-27
- Inns
- types of inns, 9
- inn amenities, 18
- Jokes
- types of jokes, 11-12
- joke delivery, 25
- Knives
- types of knives, 16-17
- knife skills, 22-23
- knife fights, 28-29
- Luggage
- appearance, 10
- personality, 13
- abilities, 23
- Magic
- types of magic, 15
- magic rules, 24
- magic mishaps, 28
- Socks
- types of socks, 9
- sock-related magic (yes, really), 15
- sock-related quests (no, really), 26
- Trolls
- appearance and biology, 11
- culture and language, 18
- troll rights and activism, 31
- Unknown University
- history and architecture, 12
- faculty and staff, 20
- courses and exams, 33
- Vampires
- types and origins, 13
- vampiric powers and weaknesses, 21
- vampiric etiquette and politics, 34
- Witches
- types and traditions, 14
- witchcraft and headology, 22
- witch trials and tribulations, 35
- Xylophones
- musical instruments or weapons?, 15
- xylophone-related magic and lore, 23
- xylophone-related quests and puzzles, 36
- Yetis
- appearance and behavior, 16
- yeti philosophy and religion, 24
- yeti encounters and stories, 37
- Zombies
- types and causes, 17
- zombie rights and duties, 25
- zombie survival and prevention, 38
}}`;
};

View File

@@ -48,8 +48,8 @@ const getTOC = (pages)=>{
return res;
};
module.exports = function(brew){
const pages = brew.text.split('\\page');
module.exports = function(props){
const pages = props.brew.text.split('\\page');
const TOC = getTOC(pages);
const markdown = _.reduce(TOC, (r, g1, idx1)=>{
if(g1.title !== null) {

View File

@@ -820,6 +820,134 @@ h5 + table{
}
}
}
//*****************************
// * BACK COVER
// *****************************/
.page:has(.backCover) {
color: #fff;
columns: 1;
padding: 2.25cm 1.3cm 2cm 1.3cm;
&:after {
all: unset;
}
.columnWrapper {
width: 7.6cm;
}
.backCover {
position: absolute;
inset: 0;
width: 11cm;
background-image: @backCover;
background-repeat: no-repeat;
background-size: contain;
z-index: -1;
}
.blank {
height: 1.4em;
}
h1 {
margin-bottom: .3cm;
font-size: 1.35cm;
line-height: 0.95em;
font-family: NodestoCapsCondensed;
text-align: center;
color: #ED1C24;
}
h1+p::first-line,
h1+p::first-letter {
all: unset;
}
img {
position: absolute;
top: 0px;
height: 100%;
z-index: -2;
}
hr {
margin-left: auto;
margin-right: auto;
margin-top: 1.1cm;
height: .53cm;
width: 4.5cm;
visibility: visible;
background-image: @horizontalRule;
background-size: 100% 100%;
border: none;
}
p {
font-family: Overpass;
line-height: 1.5em;
font-size: 0.332cm;
}
hr+p {
text-align: center;
margin-top: .6cm;
}
.logo {
position: absolute;
z-index: 0;
height: 1.5cm;
left: 1.2cm;
bottom: 2cm;
width: 7.6cm;
img {
position: relative;
height : 1.5cm;
width : 100%;
z-index : 0;
}
p {
position: relative;
color: #fff;
font-family: NodestoCapsWide;
font-size: .4cm;
letter-spacing: 0.08em;
line-height: 1em;
text-align: center;
text-indent: 0;
width: 100%;
}
}
}
//*****************************
// * PART COVER
// *****************************/
.page:has(.partCover) {
columns : 1;
text-align : center;
padding-top: 0;
.partCover {
background-image: @partCoverHeaderPHB;
background-repeat: no-repeat;
position: absolute;
background-size: 100%;
top: 0;
left: 0;
height: 6cm;
width: 100%;
}
h1 {
position: relative;
text-align: center;
text-transform: uppercase;
font-size: 2.3cm;
font-family: NodestoCapsCondensed;
margin-top: .4cm;
}
h2 {
font-family: Overpass;
font-size: 0.45cm;
position: relative;
margin-top: -0.7em;
line-height: 1.1em;
margin-left : auto;
margin-right : auto;
}
}
//*****************************
// * TABLE OF CONTENTS
@@ -978,3 +1106,26 @@ break-inside : avoid;
}
}
}
//*****************************
// * INDEX
// *****************************/
.page {
.index {
font-size : 0.218cm;
ul ul {
margin : 0;
}
ul {
padding-left : 0;
text-indent : 0;
list-style-type : none;
}
& > ul > li {
text-indent : -1.5em;
padding-left : 1.5em;
}
}
}

154
themes/V3/5ePHB/widgets.js Normal file
View File

@@ -0,0 +1,154 @@
const _ = require('lodash');
const { SNIPPET_TYPE, FIELD_TYPE, fourDigitNumberFromValue } = require('../../../shared/naturalcrit/codeEditor/helpers/widget-elements/constants');
module.exports = [{
name : 'monster',
type : SNIPPET_TYPE.BLOCK,
fields : [{
name : 'frame',
type : FIELD_TYPE.CHECKBOX
}, {
name : 'wide',
type : FIELD_TYPE.CHECKBOX
}]
}, {
name : 'classTable',
type : SNIPPET_TYPE.BLOCK,
fields : [{
name : 'frame',
type : FIELD_TYPE.CHECKBOX
}, {
name : 'decoration',
type : FIELD_TYPE.CHECKBOX
}, {
name : 'wide',
type : FIELD_TYPE.CHECKBOX
}]
}, {
name : 'runeTable',
type : SNIPPET_TYPE.BLOCK,
fields : [{
name : 'frame',
type : FIELD_TYPE.CHECKBOX
}, {
name : 'wide',
type : FIELD_TYPE.CHECKBOX
}, {
name : 'font-family',
type : FIELD_TYPE.TEXT
}]
}, {
name : 'index',
type : SNIPPET_TYPE.BLOCK,
fields : [{
name : 'wide',
type : FIELD_TYPE.CHECKBOX
}, {
name : 'columns',
type : FIELD_TYPE.TEXT,
increment : 1
}]
}, {
name : 'image',
type : SNIPPET_TYPE.INJECTOR,
fields : []
}, {
name : 'artist',
type : SNIPPET_TYPE.BLOCK,
fields : [{
name : 'top',
type : FIELD_TYPE.TEXT,
increment : 5,
hints : true
}]
}, {
name : 'watercolor',
type : SNIPPET_TYPE.INLINE,
fields : [{
name : 'watercolor',
type : FIELD_TYPE.IMAGE_SELECTOR,
preview : (value)=>`/assets/watercolor/watercolor${value}.png`,
values : _.range(1, 13)
}, {
name : 'top',
type : FIELD_TYPE.TEXT,
increment : 5,
hints : true
}, {
name : 'left',
type : FIELD_TYPE.TEXT,
increment : 5,
hints : true
}, {
name : 'width',
type : FIELD_TYPE.TEXT,
increment : 5,
hints : true
}, {
name : 'opacity',
type : FIELD_TYPE.TEXT,
increment : 5
}, {
name : 'background-color',
type : FIELD_TYPE.COLOR_SELECTOR,
}]
}, {
name : 'imageMaskCenter',
type : SNIPPET_TYPE.INLINE,
fields : [{
name : 'imageMaskCenter',
type : FIELD_TYPE.IMAGE_SELECTOR,
preview : (value)=>`/assets/waterColorMasks/center/${fourDigitNumberFromValue(value)}.webp`,
values : _.range(1, 17)
}, {
name : '--offsetX',
type : FIELD_TYPE.TEXT,
increment : 5,
}, {
name : '--offsetY',
type : FIELD_TYPE.TEXT,
increment : 5,
}, {
name : '--rotation',
type : FIELD_TYPE.TEXT,
increment : 5,
}]
}, {
name : 'imageMaskEdge',
type : SNIPPET_TYPE.INLINE,
fields : [{
name : 'imageMaskEdge',
type : FIELD_TYPE.IMAGE_SELECTOR,
preview : (value)=>`/assets/waterColorMasks/edge/${fourDigitNumberFromValue(value)}.webp`,
values : _.range(1, 9)
}, {
name : '--offset',
type : FIELD_TYPE.TEXT,
increment : 5,
}, {
name : '--rotation',
type : FIELD_TYPE.TEXT,
increment : 5,
}]
}, {
name : 'imageMaskCorner',
type : SNIPPET_TYPE.INLINE,
fields : [{
name : 'imageMaskCorner',
type : FIELD_TYPE.IMAGE_SELECTOR,
preview : (value)=>`/assets/waterColorMasks/corner/${fourDigitNumberFromValue(value)}.webp`,
values : _.range(1, 38)
}, {
name : '--offsetX',
type : FIELD_TYPE.TEXT,
increment : 5,
}, {
name : '--offsetY',
type : FIELD_TYPE.TEXT,
increment : 5,
}, {
name : '--rotation',
type : FIELD_TYPE.TEXT,
increment : 5,
}]
}];

View File

@@ -2,6 +2,7 @@
const WatercolorGen = require('./snippets/watercolor.gen.js');
const ImageMaskGen = require('./snippets/imageMask.gen.js');
const FooterGen = require('./snippets/footer.gen.js');
const dedent = require('dedent-tabs').default;
module.exports = [
@@ -21,6 +22,53 @@ module.exports = [
icon : 'fas fa-file-alt',
gen : '\n\\page\n'
},
{
name : 'Page Number',
icon : 'fas fa-bookmark',
gen : '{{pageNumber 1}}\n'
},
{
name : 'Auto-incrementing Page Number',
icon : 'fas fa-sort-numeric-down',
gen : '{{pageNumber,auto}}\n'
},
{
name : 'Footer',
icon : 'fas fa-shoe-prints',
gen : FooterGen.createFooterFunc(),
subsnippets : [
{
name : 'Footer from H1',
icon : 'fas fa-dice-one',
gen : FooterGen.createFooterFunc(1)
},
{
name : 'Footer from H2',
icon : 'fas fa-dice-two',
gen : FooterGen.createFooterFunc(2)
},
{
name : 'Footer from H3',
icon : 'fas fa-dice-three',
gen : FooterGen.createFooterFunc(3)
},
{
name : 'Footer from H4',
icon : 'fas fa-dice-four',
gen : FooterGen.createFooterFunc(4)
},
{
name : 'Footer from H5',
icon : 'fas fa-dice-five',
gen : FooterGen.createFooterFunc(5)
},
{
name : 'Footer from H6',
icon : 'fas fa-dice-six',
gen : FooterGen.createFooterFunc(6)
}
]
},
{
name : 'Vertical Spacing',
icon : 'fas fa-arrows-alt-v',

View File

@@ -0,0 +1,17 @@
const Markdown = require('../../../../shared/naturalcrit/markdown.js');
module.exports = {
createFooterFunc : function(headerSize=1){
return (props)=>{
const cursorPos = props.cursorPos;
const markdownText = props.brew.text.split('\n').slice(0, cursorPos.line).join('\n');
const markdownTokens = Markdown.marked.lexer(markdownText);
const headerToken = markdownTokens.findLast((lexerToken)=>{ return lexerToken.type === 'heading' && lexerToken.depth === headerSize; });
const headerText = headerToken?.tokens.map((token)=>{ return token.text; }).join('');
const outputText = headerText || 'PART 1 | SECTION NAME';
return `\n{{footnote ${outputText}}}\n`;
};
}
};

View File

@@ -23,6 +23,9 @@ body {
break-inside : avoid;
display : inline-block;
width : 100%;
img {
z-index : 0;
}
}
.inline-block {
display : inline-block;
@@ -251,7 +254,6 @@ body {
background-size : 20px;
z-index : -1;
transform : translateY(50%) translateX(-50%) rotate(calc(1deg * var(--rotation))) scaleX(var(--scaleX)) scaleY(var(--scaleY));
transition : transform 2s;
& > p:has(img) {
position : absolute;
width : 50%;
@@ -259,7 +261,6 @@ body {
bottom : 50%;
left : 50%;
transform : translateX(-50%) translateY(50%) rotate(calc(-1deg * var(--rotation))) scaleX(calc(1 / var(--scaleX))) scaleY(calc(1 / var(--scaleY)));
transition : transform 2s;
}
& img {
position : absolute;

View File

@@ -13,7 +13,10 @@
@naturalCritLogo : url('/assets/naturalCritLogo.svg');
@coverPageBanner : url('/assets/coverPageBanner.svg');
@horizontalRule : url('/assets/horizontalRule.svg');
@partCoverHeaderPHB : url('/assets/partCoverHeaderPHB.png');
@partCoverHeaderDMG : url('/assets/partCoverHeaderDMG.svg');
@insideCoverMask : url('/assets/insideCoverMask.png');
@backCover : url('/assets/backCover.png');
@scriptBorder : url('/assets/scriptBorder.png');
// Watercolor Images

BIN
themes/assets/backCover.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 94.65 94.6"
version="1.1"
id="svg11"
sodipodi:docname="naturalCritLogoWhite.svg"
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview13"
pagecolor="#ffffff"
bordercolor="#111111"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="8.4989431"
inkscape:cx="38.887188"
inkscape:cy="47.35883"
inkscape:window-width="1920"
inkscape:window-height="991"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg11" />
<defs
id="defs4">
<style
id="style2">.cls-1{fill:#ed1f24;}</style>
</defs>
<title
id="title6">NaturalCritLogo</title>
<g
id="Layer_2"
data-name="Layer 2">
<g
id="base">
<path
id="D20"
class="cls-1"
d="M63.45.09s-45.91,12.4-46,12.45a.71.71,0,0,0-.15.08l-.15.1-.12.11a1.07,1.07,0,0,0-.14.16l-.09.11-.12.23,0,.06L.2,54.9a1.59,1.59,0,0,0,.11,1.69L29.36,94h0l0,0,.08.08.08.08.09.09.08.06.13.07a0,0,0,0,0,0,0,1.59,1.59,0,0,0,.27.12l.13.05.06,0a1.55,1.55,0,0,0,.37,0,1.63,1.63,0,0,0,.31,0l45.67-8.3.16,0,.11,0,.12,0,.06,0s0,0,0,0l.06,0a1.65,1.65,0,0,0,.36-.28l0-.06a1.6,1.6,0,0,0,.26-.38s0,0,0,0v0h0a.14.14,0,0,1,0-.06L94.52,43.74a1.4,1.4,0,0,0,.11-.4.41.41,0,0,0,0-.11,1.13,1.13,0,0,0,0-.26.66.66,0,0,0,0-.14,2,2,0,0,0-.06-.26l0-.11a2.68,2.68,0,0,0-.18-.33v0L65.29.6C64.77-.31,63.45.09,63.45.09ZM74.9,81.7l-28.81-18L78.5,38.49ZM44.1,61l-11-40.17L77,35.39ZM82,37.78l8.92,5.95L79,73.48Zm4.46-1.1-4.6-3.06L75.69,21.36Zm-9.26-4.8-42.07-14,28.05-14ZM30.56,16.34l-6.49-2.16L47.85,7.7Zm-11.35-.21L27.88,19,7.64,45Zm10.73,5.76L40.78,61.64,4.64,54.42Zm10.82,43.2L30.26,89.6,5.75,58.09Zm3.16,1.24L71.74,83.72l-38.26,7Z"
style="fill:#ffffff;fill-opacity:1" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 611.99 154.72"><defs><style>.cls-1{fill:#f4f0f1;}.cls-2{fill:#d0d4d0;stroke:#888;stroke-linecap:round;stroke-miterlimit:35;stroke-width:0.5px;}</style></defs><title>Asset 2</title><g id="Layer_2" data-name="Layer 2"><g id="svg"><polygon id="background" class="cls-1" points="221.58 0 221.58 86.65 305.82 136.18 389.8 86.91 389.8 0 221.58 0"/><path id="right_triangle_compound_path" data-name="right triangle compound path" class="cls-2" d="M526.31.25c0,14.18-.08,26.67-.12,40.85,0,4.47-2.72,11-11.77,11-3.25.16-13.9-1.11-23.74-6.57L410.79.25h-2.53L527.82,69.38V.25Zm-.06,66.27L498.44,50.67c1,.39,14.21,4,19.29,2.81a13.9,13.9,0,0,0,8.52-6Z"/><path id="main_shape" data-name="main shape" class="cls-2" d="M598.88,123.48l-.13-65.27a81.69,81.69,0,0,1-24,20.31,79.73,79.73,0,0,1-26.8,9L544.82,86a78.57,78.57,0,0,0,42.52-18.09c15.33-13,22.12-30.25,24.4-37.06v-7a80.45,80.45,0,0,1-15.39,31.7c.63-1,16.49-26.4-2.42-55.2h-2.37c3.37,5,12.23,19.65,9.21,37.64-4,24-27.74,43.84-58.54,46.25L471.67,43.29a3.24,3.24,0,0,0-1.37-3,3.2,3.2,0,0,0-3.55,0L447.21,29a7,7,0,0,0-2.25-2.7,7,7,0,0,0-4.73-1.19l-16.59-9.57C414.47,10.29,404,4.25,397.06.25h-3.32L436.1,25.46s-36.92.06-40.94.11c-2.79-1.71-2.7,3.24,0,1.62h41.71l-46.4.37L390.3.26h-1.57L388.79,86l-41.1,24.5c-6.35,3.73-24.5,13.91-42.86,14.1s-36.47-11.3-44-15.49C248,101.8,235.15,93.85,222.33,86.52L222.46.25h-2V28l-46.09-.37h41.7c2.71,1.62,2.79-3.33,0-1.62-4-.05-40.93-.11-40.93-.11L218.32.25H215c-7,4-18.25,10.52-27.42,15.8L171,25.62a7,7,0,0,0-4.73,1.19,7,7,0,0,0-2.25,2.7L144.46,40.72a3.19,3.19,0,0,0-3.54.05,3.24,3.24,0,0,0-1.37,3L69,84.62c-30.8-2.41-54.53-22.3-58.54-46.25-3-18,5.84-32.62,9.2-37.64H17.29c-18.91,28.8-3,54.19-2.42,55.2C2.75,41,.27,26.28.27,26.28l0,7.08a78.31,78.31,0,0,0,23.63,35A78.57,78.57,0,0,0,66.4,86.43L63.22,88a79.66,79.66,0,0,1-26.8-9,81.76,81.76,0,0,1-24-20.31L12.34,124C12.46,141,.25,147.51.25,147.51v1.72a27.5,27.5,0,0,0,8.43-8A29,29,0,0,0,13,131.51v10.41L.25,152v2.1L26,133.61v-22l20.48-12c62.61,1.71,93.58-40,99.08-46.72,21.86-20.39,70.66-22.25,74.93-22.37V87.7l85.25,49.11,85.12-49.4-.33-57.36s52.35,1.05,75.23,22.38c5.49,6.67,36.47,48.43,99.08,46.72l20.48,12v22l26.47,21.07v-2.1l-13.55-10.66V131a29,29,0,0,0,4.35,9.72,32.12,32.12,0,0,0,9.2,8.6v-1.72A27.69,27.69,0,0,1,598.88,123.48ZM139.64,46.06c-.25.47-8.48,15.47-26.11,27.94-17.91,12.67-40,10.81-40,10.81ZM24.06,110.34l.1,22.47-7.09,6.1V93.77a99.79,99.79,0,0,0,12.3,3.52,99.74,99.74,0,0,0,13.8,2ZM48.19,97A102.43,102.43,0,0,1,30,95.38a103,103,0,0,1-15-3.87l-.09,48.35L13.76,141q.22-39,.47-77.9A83.48,83.48,0,0,0,36.08,80.34a82.84,82.84,0,0,0,25.15,8.85Zm30.54-3a121.63,121.63,0,0,1-26.57,3l12-7.14a96,96,0,0,0,15.51.29A97,97,0,0,0,102.19,86,122.56,122.56,0,0,1,78.73,94ZM140,55.86C135.3,61.42,126.49,71.79,114.11,79,96,89.52,77.09,89.38,66.63,88.34l2.65-1.62A77.74,77.74,0,0,0,112,77.14c17.82-9.9,26.42-24.69,29.83-30.8.2,0,2.07.45,3.05-.86a3.75,3.75,0,0,0,.64-2.86l6.71-3.76A128.27,128.27,0,0,1,140,55.86ZM164.8,39.57a119.38,119.38,0,0,0-15.51,8.29l7-11.33,11-6.29,36.42-.38C190.52,32.15,179.34,33.15,164.8,39.57Zm140.83,95.27-23.08-13.27c3.87,1.5,15.25,4.45,22.63,4.45s18.72-2.93,23.34-4.45Zm232.1-50.51s-22.14,1.87-40-10.81c-17.63-12.47-25.85-27.47-26.1-27.94ZM446.43,39.1c-14.55-6.43-25.73-7.43-38.88-9.72l36.41.38,11,6.29,7,11.33A118,118,0,0,0,446.43,39.1ZM471.2,55.38a128.27,128.27,0,0,1-12.2-17l6.71,3.76a3.73,3.73,0,0,0,.65,2.86c1,1.31,2.84.85,3.05.86,3.4,6.11,12,20.9,29.83,30.8A77.73,77.73,0,0,0,542,86.24l2.64,1.62c-10.47,1-29.4,1.18-47.48-9.34C484.73,71.32,475.92,60.94,471.2,55.38Zm61.29,38.1A123,123,0,0,1,509,85.54a96.54,96.54,0,0,0,22.51,4.13,96,96,0,0,0,15.51-.29l12,7.14A121.63,121.63,0,0,1,532.49,93.48Zm61.67,45-7.1-6.1.09-22.47-19.1-11a99.66,99.66,0,0,0,13.81-2,100.3,100.3,0,0,0,12.3-3.52Zm2.17.95L596.23,91a102.68,102.68,0,0,1-15,3.87A102.43,102.43,0,0,1,563,96.52l-13-7.81a82.61,82.61,0,0,0,25.16-8.85A83.14,83.14,0,0,0,597,62.62q.22,39,.47,77.9Z"/><path id="left_triangle_compound_path" data-name="left triangle compound path" class="cls-2" d="M83.4.73V69.86L203.77.25h-2.53l-80.7,45.8c-9.84,5.46-20.49,6.73-23.74,6.57-9,0-11.77-6.57-11.77-11C85,27.4,85,14.91,84.91.73ZM85,48a13.87,13.87,0,0,0,8.51,6c5.08,1.18,18.26-2.42,19.29-2.81L85,67Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

Binary file not shown.

View File

@@ -107,6 +107,13 @@
font-style: italic;
}
@font-face {
font-family: NodestoCapsWide;
src: url('../../../fonts/5e/Nodesto Caps Wide.woff2');
font-weight: normal;
font-style: normal
}
@font-face {
font-family: Overpass;
src: url('../../../fonts/5e/Overpass Medium.woff2');