0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2026-01-23 20:53:05 +00:00

Compare commits

..

699 Commits

Author SHA1 Message Date
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
Trevor Buckner
f52321dd4b Update to v3.8.0 2023-04-12 16:12:02 -04:00
Trevor Buckner
3b55cd7d88 Downgrade react-frame-component back to 4.1.3 2023-04-12 11:48:19 -04:00
Trevor Buckner
f33b7b21bb Merge pull request #2733 from G-Ambatte/addMetadataToShare-#1679
Add Metadata Nav Item to SharePage
2023-04-11 22:09:10 -04:00
Trevor Buckner
ed6e64af8d Merge branch 'master' into pr/2733 2023-04-11 22:06:40 -04:00
Trevor Buckner
cadbb422a9 Merge pull request #2783 from naturalcrit/FixJestESLint
Fix missing eslint jest dependency
2023-04-11 22:05:55 -04:00
Trevor Buckner
b756a2f026 Fix missing eslint jest dependency 2023-04-11 22:05:32 -04:00
Trevor Buckner
c8b8d40863 Adjust userpage z-index to fit nav bar tweaks. 2023-04-11 21:35:18 -04:00
Trevor Buckner
d369cad02c Tweak tag bubbles 2023-04-11 21:29:01 -04:00
Trevor Buckner
d92005a3c2 Merge branch 'addMetadataToShare-#1679' of https://github.com/G-Ambatte/homebrewery into pr/2733 2023-04-11 21:26:21 -04:00
Trevor Buckner
a2430c8744 Tweak size and centering strategy 2023-04-11 21:26:16 -04:00
G.Ambatte
8febaee2a9 Merge branch 'master' into addMetadataToShare-#1679 2023-04-11 08:06:28 +12:00
Trevor Buckner
29fd836965 Lift whole navbar z-index up instead of one section. 2023-04-10 11:31:11 -04:00
Trevor Buckner
ebf9cf9364 Undo change to eslintrc 2023-04-10 10:46:42 -04:00
Trevor Buckner
8b8388391c Shorten logic 2023-04-10 10:45:30 -04:00
Trevor Buckner
ba72f1ab22 Merge pull request #2620 from jeddai/content-negotiation-middleware
Fixes #2595: Add content negotiation middleware
2023-04-10 09:54:48 -04:00
Trevor Buckner
9bb1cac547 Merge pull request #2781 from naturalcrit/dependabot/npm_and_yarn/eslint-8.38.0
Bump eslint from 8.37.0 to 8.38.0
2023-04-10 09:25:54 -04:00
dependabot[bot]
5cf6c9b8bd Bump eslint from 8.37.0 to 8.38.0
Bumps [eslint](https://github.com/eslint/eslint) from 8.37.0 to 8.38.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.37.0...v8.38.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-10 03:14:34 +00:00
G.Ambatte
4ddee3c2f1 Remove z-index to fix UserPage bug 2023-04-10 10:17:15 +12:00
G.Ambatte
0aac08f276 Move from let to const 2023-04-10 10:16:28 +12:00
G.Ambatte
9690c6dac3 Center metadata window 2023-04-10 09:35:56 +12:00
Victor Losada Hernandez
78ca5f5107 undo isolation, raising image z-index 2023-04-09 15:32:03 +02:00
G.Ambatte
eb7d558c8d Change author names to UserPage links 2023-04-09 23:24:54 +12:00
G.Ambatte
0e226ca8db Add min and max widths 2023-04-09 22:26:15 +12:00
G.Ambatte
14ac098882 Fix no systems/tags/authors mesasges 2023-04-09 21:40:41 +12:00
G.Ambatte
d5dbf46fc4 Fix "No tags" message 2023-04-09 21:33:57 +12:00
G.Ambatte
bc83e1f84d Tweak animation, add alternating bg colors 2023-04-09 21:33:33 +12:00
G.Ambatte
b8e68f9a93 Add animations 2023-04-09 21:01:28 +12:00
G.Ambatte
ebc90c998a Position window correctly when nav bar is thick 2023-04-09 20:31:12 +12:00
G.Ambatte
aa0cc1ebf6 Move Metadata window to title 2023-04-09 13:33:53 +12:00
G.Ambatte
c5bd41acbf Adjust tag styling 2023-04-09 11:00:41 +12:00
G.Ambatte
22b6b6a473 Comment out valid-expect linter rule 2023-04-09 11:00:07 +12:00
G.Ambatte
89ba709789 Merge branch 'master' into addMetadataToShare-#1679 2023-04-08 17:14:39 +12:00
Trevor Buckner
0720677824 Merge branch 'master' into pr/2620 2023-04-07 15:15:08 -04:00
Trevor Buckner
fab4bfae27 Merge pull request #2774 from Gazook89/mustache-syntax-unit-tests
Mustache syntax unit tests
2023-04-07 14:10:53 -04:00
Trevor Buckner
f880c961bd Revert "Update package-lock.json"
This reverts commit ec7c083f90.
2023-04-07 13:29:46 -04:00
Trevor Buckner
ec7c083f90 Update package-lock.json 2023-04-07 13:28:58 -04:00
Trevor Buckner
99984e207f Merge branch 'master' into pr/2774 2023-04-07 13:15:41 -04:00
Trevor Buckner
b5bd28ddd1 Merge pull request #2778 from naturalcrit/dependabot/npm_and_yarn/npm-9.6.4
Bump npm from 9.6.3 to 9.6.4
2023-04-07 11:32:54 -04:00
dependabot[bot]
e9bd80aa0d Bump npm from 9.6.3 to 9.6.4
Bumps [npm](https://github.com/npm/cli) from 9.6.3 to 9.6.4.
- [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.3...v9.6.4)

---
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-06 04:06:58 +00:00
Trevor Buckner
89f0c7e127 Small refactor to fix error popup that lost its styling 2023-04-04 23:46:11 -04:00
Trevor Buckner
70295fb227 Revert "Small refactor to fix broken error popup"
This reverts commit 2cb6acc090.
2023-04-04 23:44:23 -04:00
Trevor Buckner
2cb6acc090 Small refactor to fix broken error popup 2023-04-04 23:41:44 -04:00
Gazook89
83fac6a10f Mark failing tests with comments. 2023-04-04 21:13:41 -05:00
Trevor Buckner
121da67b7a Merge pull request #2776 from naturalcrit/FixTests
Change tests from .remove() to deleteOne()
2023-04-04 18:00:47 -04:00
Trevor Buckner
eaf7b9c4ef Change tests from .remove() to deleteOne() 2023-04-04 17:47:25 -04:00
Gazook89
9e9bf8c6fa Add injection tests 2023-04-04 16:32:59 -05:00
Gazook89
4cfe26b4a9 Add Block tests, structure with Describe() 2023-04-04 16:15:10 -05:00
Gazook89
0e35b99289 remove quotes from rule option object 2023-04-04 16:14:34 -05:00
Gazook89
b32c724c89 remove stack traces from test output 2023-04-04 15:51:29 -05:00
Gazook89
e5377c1939 add and setup jest-expect-message library 2023-04-04 15:01:23 -05:00
Trevor Buckner
a5e84694c1 Merge pull request #2752 from Gazook89/Injection-Blocks-Take-3
Prevent Injection if preceded by another Injection token
2023-04-04 12:19:13 -04:00
Trevor Buckner
48227eaf71 Remove Console.log and lint 2023-04-04 12:18:57 -04:00
Trevor Buckner
f06d30e4a6 Merge pull request #2770 from G-Ambatte/fixMongooseRemove-#2769
Change Model.remove to Model.deleteOne
2023-04-04 11:51:09 -04:00
Gazook89
333525d9ab Update CI config and package.json scripts 2023-04-03 21:23:39 -05:00
Gazook89
69c283f00f Set Inline unit tests grouped inside a describe 2023-04-03 21:00:59 -05:00
Gazook89
9f17f36a87 add trimReturns() method to strings to trim render output 2023-04-03 20:53:07 -05:00
Gazook89
b948106500 add dedent for Block tests 2023-04-03 20:51:05 -05:00
Gazook89
7000b911e7 change mustache test file name. 2023-04-03 20:46:21 -05:00
Gazook89
7353e6c7ac Add unit tests for double injection into block and inline 2023-04-03 16:57:29 -05:00
Trevor Buckner
773a9b5c82 Merge pull request #2765 from naturalcrit/dependabot/npm_and_yarn/npm-9.6.3
Bump npm from 9.6.2 to 9.6.3
2023-04-03 11:47:53 -04:00
Trevor Buckner
e2b0b9e5d2 Merge pull request #2773 from naturalcrit/dependabot/npm_and_yarn/babel/plugin-transform-runtime-7.21.4
Bump @babel/plugin-transform-runtime from 7.21.0 to 7.21.4
2023-04-03 11:47:41 -04:00
dependabot[bot]
1c7540edcd Bump npm from 9.6.2 to 9.6.3
Bumps [npm](https://github.com/npm/cli) from 9.6.2 to 9.6.3.
- [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.2...v9.6.3)

---
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-03 15:47:29 +00:00
dependabot[bot]
4dc14101bc Bump @babel/plugin-transform-runtime from 7.21.0 to 7.21.4
Bumps [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-runtime) from 7.21.0 to 7.21.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.21.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-04-03 15:47:17 +00:00
Trevor Buckner
6016a60a3a Merge pull request #2772 from naturalcrit/dependabot/npm_and_yarn/babel/preset-env-7.21.4
Bump @babel/preset-env from 7.20.2 to 7.21.4
2023-04-03 11:46:12 -04:00
Trevor Buckner
ab51a93fb2 Merge pull request #2771 from naturalcrit/dependabot/npm_and_yarn/babel/core-7.21.4
Bump @babel/core from 7.21.3 to 7.21.4
2023-04-03 11:45:59 -04:00
dependabot[bot]
097d9aaacd Bump @babel/preset-env from 7.20.2 to 7.21.4
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.20.2 to 7.21.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.21.4/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-04-03 03:57:06 +00:00
dependabot[bot]
d74acd2bdc Bump @babel/core from 7.21.3 to 7.21.4
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.21.3 to 7.21.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.21.4/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-04-03 03:56:49 +00:00
G.Ambatte
dce880610d Change Model.remove to Model.deleteOne 2023-04-02 20:57:03 +12:00
G.Ambatte
8958238342 Merge branch 'master' into addMetadataToShare-#1679 2023-03-31 15:55:54 +13:00
Trevor Buckner
d1dd5e34bd Merge pull request #2661 from 5e-Cleric/char-fix
U+00D1 and U+00F1 fix
2023-03-30 22:19:44 -04:00
Trevor Buckner
7529a4380b Fix LSB & RSB 2023-03-30 22:17:51 -04:00
Trevor Buckner
1b5b4154ed Merge pull request #2764 from naturalcrit/Tweak-CoverPage-Snippet
Change .coverPage to .frontCover, clean CSS
2023-03-30 17:22:54 -04:00
Trevor Buckner
a1476582b0 Change .coverPage to .frontCover, clean CSS 2023-03-30 17:22:35 -04:00
Trevor Buckner
0fbda91169 Merge pull request #2714 from 5e-Cleric/Inside-Cover-snippet
Inside Cover Snippet
2023-03-30 17:10:29 -04:00
Trevor Buckner
4b6f81ba34 Merge branch 'master' into Inside-Cover-snippet 2023-03-30 17:09:56 -04:00
Trevor Buckner
5cdc1dda64 Small style tweaks 2023-03-30 16:46:09 -04:00
Trevor Buckner
4bf61a063c Remove accidental racism :P 2023-03-30 15:13:29 -04:00
Trevor Buckner
6e99636296 Merge pull request #2760 from naturalcrit/dependabot/npm_and_yarn/react-router-dom-6.10.0
Bump react-router-dom from 6.9.0 to 6.10.0
2023-03-30 14:41:26 -04:00
dependabot[bot]
8902b237ce Bump react-router-dom from 6.9.0 to 6.10.0
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.9.0 to 6.10.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.10.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-03-30 18:40:34 +00:00
Trevor Buckner
1ef18fc53c Merge pull request #2759 from naturalcrit/dependabot/npm_and_yarn/eslint-8.37.0
Bump eslint from 8.36.0 to 8.37.0
2023-03-30 14:40:04 -04:00
dependabot[bot]
ea00c1a5d6 Bump eslint from 8.36.0 to 8.37.0
Bumps [eslint](https://github.com/eslint/eslint) from 8.36.0 to 8.37.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.36.0...v8.37.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-03-30 18:39:22 +00:00
Trevor Buckner
d49a94498a Merge pull request #2761 from G-Ambatte/bumpNodeVersion-#2756
Update engines to Node 16.13.0
2023-03-30 14:38:04 -04:00
G.Ambatte
591c45f59f Fix Recent Items drop down 2023-03-30 20:19:30 +13:00
G.Ambatte
435eec6e74 Merge branch 'master' into addMetadataToShare-#1679 2023-03-30 20:14:59 +13:00
G.Ambatte
aed29952d6 Fix nav item background transparency & z position 2023-03-30 20:13:01 +13:00
G.Ambatte
527b704ccd Update engines to Node 16.13.0 2023-03-30 19:27:32 +13:00
Trevor Buckner
02bcc9bfb9 Handle multi-line titles. Add Subtitles. 2023-03-28 17:31:26 -04:00
Trevor Buckner
d4b624186f Fix imageMask snippet typo 2023-03-28 17:30:40 -04:00
Trevor Buckner
a58a750b94 Change background image 2023-03-28 17:30:16 -04:00
Trevor Buckner
d793b6f690 Change Icon 2023-03-28 17:29:55 -04: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
38a5ebf779 interpoint fix 2023-03-25 22:46:49 +01:00
Victor Losada Hernandez
7926a318d8 special character width fix 2023-03-25 22:40:58 +01:00
Victor Losada Hernandez
370c6ccf73 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into char-fix 2023-03-25 22:23:56 +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
Trevor Buckner
a92f5d0694 Combine .gen files together, add Center mask 2023-03-24 19:06:06 -04:00
Trevor Buckner
5b2aa452c0 Merge branch 'master' into pr/2714 2023-03-24 18:52:50 -04:00
Trevor Buckner
46bc34d527 Merge pull request #2609 from naturalcrit/dependabot/npm_and_yarn/react-frame-component-5.2.6
Bump react-frame-component from 4.1.3 to 5.2.6
2023-03-24 17:41:50 -04:00
Gazook89
6a95ed57ca escape tokenization of injection if preceded by another injection. 2023-03-24 15:15:08 -05:00
Trevor Buckner
97f5a17d10 Merge pull request #2741 from 5e-Cleric/WatercolorImageMaskCenter
Water color image masks part 2 - Center Masks
2023-03-24 14:05:36 -04:00
Trevor Buckner
a106f6f814 Merge pull request #2751 from naturalcrit/dependabot/npm_and_yarn/mongoose-7.0.3
Bump mongoose from 7.0.2 to 7.0.3
2023-03-24 13:56:58 -04:00
Trevor Buckner
1c90b3c4d6 Merge pull request #2749 from naturalcrit/dependabot/npm_and_yarn/googleapis/drive-5.0.2
Bump @googleapis/drive from 5.0.1 to 5.0.2
2023-03-24 13:56:45 -04:00
Trevor Buckner
db81d347bd Merge pull request #2750 from naturalcrit/dependabot/npm_and_yarn/dedent-tabs-0.10.3
Bump dedent-tabs from 0.10.2 to 0.10.3
2023-03-24 13:56:34 -04:00
dependabot[bot]
d9423b9d50 Bump mongoose from 7.0.2 to 7.0.3
Bumps [mongoose](https://github.com/Automattic/mongoose) from 7.0.2 to 7.0.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.0.2...7.0.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-03-24 03:58:18 +00:00
dependabot[bot]
220b5df559 Bump dedent-tabs from 0.10.2 to 0.10.3
Bumps [dedent-tabs](https://github.com/adrianjost/dedent-tabs) from 0.10.2 to 0.10.3.
- [Release notes](https://github.com/adrianjost/dedent-tabs/releases)
- [Commits](https://github.com/adrianjost/dedent-tabs/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-24 03:57:47 +00:00
dependabot[bot]
67068221bd Bump @googleapis/drive from 5.0.1 to 5.0.2
Bumps [@googleapis/drive](https://github.com/googleapis/google-api-nodejs-client) from 5.0.1 to 5.0.2.
- [Release notes](https://github.com/googleapis/google-api-nodejs-client/releases)
- [Changelog](https://github.com/googleapis/google-api-nodejs-client/blob/main/CHANGELOG.md)
- [Commits](https://github.com/googleapis/google-api-nodejs-client/compare/admin-v5.0.1...drive-v5.0.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-24 03:57:22 +00:00
Victor Losada Hernandez
e28605338b centering + 5 new masks 2023-03-23 23:51:27 +01:00
Victor Losada Hernandez
9870ff369e title variation included 2023-03-23 23:26:15 +01:00
Trevor Buckner
c39a95f1e1 Fix to work with rotation and % offsets 2023-03-23 16:47:42 -04:00
Trevor Buckner
3b5aef7d71 Further snippet tweaks 2023-03-23 16:47:23 -04:00
Trevor Buckner
dc1ef3dd3e Fix snippet 2023-03-23 16:39:32 -04:00
Trevor Buckner
262e79c4df Tweak icon 2023-03-23 16:37:44 -04:00
Trevor Buckner
43b9877fa4 Merge branch 'master' into pr/2741 2023-03-23 15:42:18 -04:00
Trevor Buckner
d25cef0c49 Merge pull request #2625 from G-Ambatte/experimentalWinChocolateyInstall
Windows install script using Chocolatey
2023-03-23 14:24:39 -04:00
Trevor Buckner
bd9dfeb46c Merge branch 'master' into pr/2661 2023-03-23 13:41:55 -04:00
dependabot[bot]
348ec5fd20 Bump react-frame-component from 4.1.3 to 5.2.6
Bumps [react-frame-component](https://github.com/ryanseddon/react-frame-component) from 4.1.3 to 5.2.6.
- [Release notes](https://github.com/ryanseddon/react-frame-component/releases)
- [Commits](https://github.com/ryanseddon/react-frame-component/compare/v4.1.3...v5.2.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-23 16:51:07 +00:00
Trevor Buckner
038088328e Merge pull request #2748 from naturalcrit/dependabot/npm_and_yarn/marked-4.3.0
Bump marked from 4.2.12 to 4.3.0
2023-03-23 12:49:45 -04:00
Trevor Buckner
5d77dea652 Merge pull request #2658 from G-Ambatte/fixAdminPages-#2657
Fix admin pages #2657
2023-03-23 12:49:15 -04:00
Trevor Buckner
0436235ec3 Merge branch 'master' into pr/2658 2023-03-23 12:28:02 -04:00
Trevor Buckner
6431964807 Merge branch 'master' into pr/2658 2023-03-23 12:24:33 -04:00
Trevor Buckner
bda9b455d9 Merge pull request #2681 from G-Ambatte/fixDivLinks-#2680
[EDITOR] Fix div links #2680
2023-03-23 12:16:27 -04:00
Trevor Buckner
c41b06eee1 Remove duplicate renderer on Marked.parse call 2023-03-23 12:03:30 -04:00
Trevor Buckner
402811fbec Merge branch 'master' into pr/2681 2023-03-23 11:48:22 -04:00
dependabot[bot]
c7758e02a8 Bump marked from 4.2.12 to 4.3.0
Bumps [marked](https://github.com/markedjs/marked) from 4.2.12 to 4.3.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/v4.2.12...v4.3.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-03-23 03:57:23 +00:00
Trevor Buckner
92f3fc9ff8 Merge pull request #2745 from 5e-Cleric/script-snippet
Script snippet
2023-03-22 17:44:16 -04:00
Trevor Buckner
f7bd861d9f Move snippet under Tables category 2023-03-22 17:43:41 -04:00
Trevor Buckner
be39a6c7cc lint 2023-03-22 16:59:14 -04:00
Trevor Buckner
c6210280eb Use font-family vs classes. Rename to runeTable 2023-03-22 16:58:32 -04:00
Trevor Buckner
801f66c483 Remove mention of 5e 2023-03-22 16:10:08 -04:00
Trevor Buckner
bdd898f5b6 Fix typo in Iokharic font name 2023-03-22 15:57:38 -04:00
Trevor Buckner
1a87a5543f Merge branch 'master' into pr/2745 2023-03-22 14:11:19 -04:00
G.Ambatte
b24c604597 Merge branch 'master' into addMetadataToShare-#1679 2023-03-22 18:51:49 +13:00
Trevor Buckner
ded29dc390 Merge pull request #2737 from naturalcrit/dependabot/npm_and_yarn/mongoose-7.0.2
Bump mongoose from 6.9.2 to 7.0.2
2023-03-21 16:14:03 -04:00
Trevor Buckner
ab5755e94e Update package-lock.json 2023-03-21 16:13:43 -04:00
Trevor Buckner
eaad46b6bc lint 2023-03-21 16:10:48 -04:00
Trevor Buckner
1ec08bb1fa Update Mongoose calls to not use callbacks. 2023-03-21 16:06:43 -04:00
Trevor Buckner
9dda58991f Merge branch 'dependabot/npm_and_yarn/mongoose-7.0.2' of https://github.com/naturalcrit/homebrewery into dependabot/npm_and_yarn/mongoose-7.0.2 2023-03-21 16:06:01 -04:00
dependabot[bot]
844d2b7a06 Bump mongoose from 6.9.2 to 7.0.2
Bumps [mongoose](https://github.com/Automattic/mongoose) from 6.9.2 to 7.0.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/6.9.2...7.0.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-21 18:38:37 +00:00
Trevor Buckner
9e2824e0be Merge pull request #2736 from naturalcrit/dependabot/npm_and_yarn/npm-9.6.2
Bump npm from 8.19.3 to 9.6.2
2023-03-21 14:37:03 -04:00
Trevor Buckner
4f5f34c888 Merge pull request #2747 from naturalcrit/RemoveBundledFilesFromCoverageTest
Remove bundled JS from coverage tests
2023-03-21 14:32:10 -04:00
Trevor Buckner
1b3ed2ad70 Remove bundled JS from coverage tests 2023-03-21 14:31:49 -04:00
dependabot[bot]
098de2afd3 Bump npm from 8.19.3 to 9.6.2
Bumps [npm](https://github.com/npm/cli) from 8.19.3 to 9.6.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/v8.19.3...v9.6.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-21 18:24:58 +00:00
Trevor Buckner
fa762cf32f Merge pull request #2734 from naturalcrit/dependabot/npm_and_yarn/googleapis/drive-5.0.1
Bump @googleapis/drive from 4.0.2 to 5.0.1
2023-03-21 14:20:30 -04:00
dependabot[bot]
a4677956f6 Bump @googleapis/drive from 4.0.2 to 5.0.1
Bumps [@googleapis/drive](https://github.com/googleapis/google-api-nodejs-client) from 4.0.2 to 5.0.1.
- [Release notes](https://github.com/googleapis/google-api-nodejs-client/releases)
- [Changelog](https://github.com/googleapis/google-api-nodejs-client/blob/main/CHANGELOG.md)
- [Commits](https://github.com/googleapis/google-api-nodejs-client/compare/run-v4.0.2...admin-v5.0.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-21 18:06:03 +00:00
Trevor Buckner
efdc0b072e Merge pull request #2728 from naturalcrit/dependabot/npm_and_yarn/react-router-dom-6.9.0
Bump react-router-dom from 6.8.2 to 6.9.0
2023-03-21 14:04:43 -04:00
Trevor Buckner
56e7355a0e Merge pull request #2727 from naturalcrit/dependabot/npm_and_yarn/eslint-8.36.0
Bump eslint from 8.35.0 to 8.36.0
2023-03-21 14:03:51 -04:00
Trevor Buckner
ae8e2c9889 Merge pull request #2744 from naturalcrit/dependabot/npm_and_yarn/fs-extra-11.1.1
Bump fs-extra from 11.1.0 to 11.1.1
2023-03-21 14:03:23 -04:00
Trevor Buckner
32543f5aa3 Merge pull request #2746 from MichielDeMey/feature/no-transform-username-navbar
Remove text transform from username
2023-03-21 14:03:04 -04:00
Trevor Buckner
3587511e44 Merge pull request #2735 from naturalcrit/dependabot/npm_and_yarn/babel/core-7.21.3
Bump @babel/core from 7.21.0 to 7.21.3
2023-03-21 13:36:34 -04:00
Trevor Buckner
a8926503b7 Merge pull request #2457 from Gazook89/Language-Attribute
Set Language Attribute of the `.pages` Element
2023-03-21 11:10:18 -04:00
Michiel De Mey
a52ec1c330 Remove text transform from username
Fixes #2731
2023-03-21 16:08:58 +01:00
Trevor Buckner
c2349fb464 Add note to Lang selector 2023-03-21 11:05:26 -04:00
Trevor Buckner
10263cbf7c Add note to Lang selector 2023-03-21 10:38:48 -04:00
Victor Losada Hernandez
6281ed044e font-size corrections 2023-03-21 14:37:04 +01:00
Victor Losada Hernandez
25b5badf90 dropdown icons 2023-03-21 14:17:12 +01:00
dependabot[bot]
d743b72f9c Bump fs-extra from 11.1.0 to 11.1.1
Bumps [fs-extra](https://github.com/jprichardson/node-fs-extra) from 11.1.0 to 11.1.1.
- [Release notes](https://github.com/jprichardson/node-fs-extra/releases)
- [Changelog](https://github.com/jprichardson/node-fs-extra/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jprichardson/node-fs-extra/compare/11.1.0...11.1.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-21 03:56:45 +00:00
Trevor Buckner
33d8d51956 Tweak combobox style 2023-03-20 14:04:20 -04:00
Trevor Buckner
285b4c3b92 Lift up box to not be covered by Themes selector. 2023-03-20 13:18:20 -04:00
Trevor Buckner
0a7ccfb89e Debounce validation on Lang field 2023-03-20 13:17:51 -04:00
G.Ambatte
db5469699e Move metadata window to be independent of title 2023-03-19 18:42:31 +13:00
G.Ambatte
807ab2a538 Standardize to className 2023-03-19 18:40:38 +13:00
Victor Losada Hernandez
d46736b7e6 update - DMG svg 2023-03-17 00:12:48 +01:00
Victor Losada Hernandez
b041ef921e initial draft 2023-03-16 17:54:19 +01:00
dependabot[bot]
064a92f0da Bump mongoose from 6.9.2 to 7.0.2
Bumps [mongoose](https://github.com/Automattic/mongoose) from 6.9.2 to 7.0.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/6.9.2...7.0.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-16 03:57:18 +00:00
dependabot[bot]
3e73ae0327 Bump @babel/core from 7.21.0 to 7.21.3
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.21.0 to 7.21.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.21.3/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-03-15 03:57:46 +00:00
G.Ambatte
bd4c24df46 Adjust styling for unusual browser widths 2023-03-15 13:46:30 +13:00
G.Ambatte
1126481d53 Add Last Updated field and nudge styling 2023-03-15 11:46:27 +13:00
G.Ambatte
a3f93c2602 Styling updates 2023-03-15 11:06:48 +13:00
G.Ambatte
24564a2750 Shift to title wrapper 2023-03-15 09:17:05 +13:00
G.Ambatte
4505308b81 Merge branch 'master' into addMetadataToShare-#1679 2023-03-15 07:38:17 +13:00
Trevor Buckner
cf99bd9004 Fix unit tests 2023-03-14 12:12:21 -04:00
Trevor Buckner
75d97379f8 Merge branch 'master' into pr/2457 2023-03-14 11:22:00 -04:00
dependabot[bot]
6588863d2d Bump eslint from 8.35.0 to 8.36.0
Bumps [eslint](https://github.com/eslint/eslint) from 8.35.0 to 8.36.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.35.0...v8.36.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-03-14 15:19:51 +00:00
Trevor Buckner
98ae938b3d Merge pull request #2730 from naturalcrit/RunJestTestsSequentially
Run Tests sequentially
2023-03-14 11:18:10 -04:00
G.Ambatte
ccf44cbe91 Initial functionality pass 2023-03-14 23:01:29 +13:00
Victor Losada Hernandez
54ed9a7d33 initial draft 2023-03-14 08:06:26 +01:00
Trevor Buckner
4ec0107348 Merge pull request #2732 from naturalcrit/Fix_Column-Fill-Auto_on_Legacy_MonsterBlocks
Change monster block to column-fill : balance
2023-03-13 23:27:58 -04:00
Trevor Buckner
8106b2b694 Up version to v3.7.2 2023-03-13 23:25:42 -04:00
Trevor Buckner
c4d26e7ffe Change monster block to column-fill : balance 2023-03-13 23:16:34 -04:00
Trevor Buckner
f148014a93 Make coverage command run in sequence too 2023-03-13 14:48:10 -04:00
Trevor Buckner
0a09cd9c67 Don't test in parallel, raise timeout 2023-03-13 14:34:48 -04:00
Trevor Buckner
3105ee1eac Run Tests sequentially
One possible solution to tests timing out on CI

https://jestjs.io/docs/troubleshooting#tests-are-extremely-slow-on-docker-and-or-continuous-integration-ci-server
2023-03-13 14:16:28 -04:00
dependabot[bot]
2fc1600865 Bump react-router-dom from 6.8.2 to 6.9.0
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.8.2 to 6.9.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.9.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-03-13 03:58:01 +00:00
G.Ambatte
d075b09496 Merge branch 'master' into fixDivLinks-#2680 2023-03-12 22:29:44 +13:00
G.Ambatte
22e275acd8 Merge branch 'master' into fixAdminPages-#2657 2023-03-12 22:28:02 +13:00
G.Ambatte
a5513b359e Merge branch 'master' into experimentalWinChocolateyInstall 2023-03-12 22:26:29 +13:00
Trevor Buckner
30e7c73805 Merge pull request #2717 from naturalcrit/dependabot/npm_and_yarn/jest-29.5.0
Bump jest from 29.4.3 to 29.5.0
2023-03-11 23:56:35 -05:00
Trevor Buckner
e080bf1bde Update changelog.md 2023-03-09 16:17:09 -05:00
dependabot[bot]
37c60feda1 Bump jest from 29.4.3 to 29.5.0
Bumps [jest](https://github.com/facebook/jest/tree/HEAD/packages/jest) from 29.4.3 to 29.5.0.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v29.5.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-03-09 20:47:53 +00:00
Trevor Buckner
aa76252a55 Merge pull request #2722 from naturalcrit/v3.7.1
Up version to v3.7.1
2023-03-09 15:45:41 -05:00
Trevor Buckner
6f3292e994 Merge pull request #2721 from naturalcrit/FixBlurryCoverpageOutlines
Change coverpage text-shadow to filter:drop-shadow
2023-03-09 15:45:13 -05:00
Trevor Buckner
eaa672c4c7 Change coverpage text-shadow to filter:drop-shadow 2023-03-09 15:35:35 -05:00
Trevor Buckner
93ff59f670 Up version to v3.7.1 2023-03-09 15:20:28 -05:00
Gazook89
461487534d add onBlur to lang input to reset to valid 2023-03-08 14:24:15 -06:00
Gazook89
7bef807c41 Remove unnecessary commented code. 2023-03-07 22:08:42 -06:00
Gazook89
2a8eaa654d updated package-lock 2023-03-07 21:55:49 -06:00
Gazook89
29f8f3546c Merge branch 'master' into Language-Attribute 2023-03-07 21:23:23 -06:00
Trevor Buckner
c47fae6061 Merge pull request #2696 from MichielDeMey/feature/trim-google-apis
[Draft] Trimming Google APIs
2023-03-07 14:53:20 -05:00
Trevor Buckner
6ff0999d88 Merge branch 'master' into pr/2696 2023-03-07 14:49:37 -05:00
Trevor Buckner
bfccf833b6 Fix variable name conflict bugs 2023-03-07 14:27:33 -05:00
Michiel De Mey
2a9ac9fa47 Defining default auth at the top 2023-03-07 11:05:11 +01:00
Trevor Buckner
b990af3fc3 Merge pull request #2710 from MichielDeMey/feature/new-google-drive-icon
Updated Google Drive icon
2023-03-06 16:06:04 -05:00
Trevor Buckner
91a31757e5 Merge branch 'master' into feature/new-google-drive-icon 2023-03-06 16:03:19 -05:00
Trevor Buckner
c341bc5db6 Make icon slightly smaller 2023-03-06 16:02:54 -05:00
Trevor Buckner
c88253901a Merge pull request #2127 from lucastucious/v3-fix-note-render
[V3] Fix note render to pdf
2023-03-06 14:12:06 -05:00
Trevor Buckner
164e0a4433 adjust values based on old original box-shadow sizes
Some shadows need to be made bigger to interact with the border-image hanging over the top of the shadow. This just restores those sizes we had before first changing to filter:drop-shadow. See https://github.com/naturalcrit/homebrewery/pull/1577/files
2023-03-06 14:09:59 -05:00
Trevor Buckner
97852c3c03 Merge branch 'master' into pr/2127 2023-03-06 12:54:13 -05:00
Trevor Buckner
4057d7bf84 Merge branch 'master' into pr/2696 2023-03-02 16:48:05 -05:00
Victor Losada Hernandez
33ae652222 format and editable logo 2023-03-02 18:25:23 +01:00
Victor Losada Hernandez
690e797fe5 initial draft 2023-03-02 18:01:44 +01:00
Trevor Buckner
ce2298ddd0 Properly comment line so // doesn't appear in page 2023-03-02 10:54:14 -05:00
Michiel De Mey
bbcf415a30 Fixed vertical alignment 2023-03-02 12:56:47 +01:00
Michiel De Mey
e67fc2f775 Moved inline styling to separate stylesheet 2023-03-02 12:40:48 +01:00
G.Ambatte
cf9dbffe49 Fix title in README 2023-03-02 10:30:13 +13:00
G.Ambatte
c006ab0901 Merge branch 'master' into experimentalWinChocolateyInstall 2023-03-02 10:28:17 +13:00
G.Ambatte
572b92f893 Merge branch 'master' into fixDivLinks-#2680 2023-03-02 10:24:27 +13: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
Trevor Buckner
cc89ad1c7d Merge pull request #2709 from naturalcrit/Re-remove-layers-from-Blank-Theme
Remove last bits of @Layers. Sigh...
2023-03-01 07:42:23 -05:00
Trevor Buckner
ba11aef038 Remove last bits of @Layers. Sigh... 2023-03-01 07:42:06 -05:00
Michiel De Mey
33f3fb18fa Updated Google Drive icon 2023-03-01 13:38:37 +01:00
Trevor Buckner
240d283536 Merge pull request #2707 from naturalcrit/v3.7.0
Update changelog.md
2023-02-28 22:50:35 -05:00
Trevor Buckner
9a60fe4129 Update changelog.md 2023-02-28 22:50:02 -05:00
Trevor Buckner
6af98cd842 Merge pull request #2706 from naturalcrit/v3.7.0
V3.7.0
2023-02-28 22:36:10 -05:00
Trevor Buckner
b2f64d1094 Update changelog.md 2023-02-28 22:35:46 -05:00
Trevor Buckner
820582067e Merge branch 'master' into v3.7.0 2023-02-28 22:33:35 -05:00
Trevor Buckner
dae1106e50 Tweak icons 2023-02-28 22:33:15 -05:00
Trevor Buckner
239cc4d99e up version to 3.7.0 2023-02-28 22:25:20 -05:00
Trevor Buckner
48cd8bb6f7 Merge pull request #2694 from MichielDeMey/patch-1
Use secure protocol for Homebrewery mug image
2023-02-28 21:53:22 -05:00
Trevor Buckner
480d7d2b5e Merge pull request #2700 from naturalcrit/dependabot/npm_and_yarn/react-router-dom-6.8.2
Bump react-router-dom from 6.8.1 to 6.8.2
2023-02-28 16:56:32 -05:00
Trevor Buckner
9ea80c0d31 Merge pull request #2698 from naturalcrit/dependabot/npm_and_yarn/eslint-8.35.0
Bump eslint from 8.34.0 to 8.35.0
2023-02-28 16:56:18 -05:00
Trevor Buckner
bd151efd51 Merge pull request #2705 from naturalcrit/DisableLayersFromCoreCSS
Disable @layers on core CSS due to crashing ios
2023-02-28 16:56:08 -05:00
Trevor Buckner
0ac1d1e87a Disable @layers on core CSS due to crashing ios 2023-02-28 16:54:59 -05:00
Trevor Buckner
a626f394df Merge pull request #2695 from MichielDeMey/patch-2
Fixed typo in Jest's modulePaths
2023-02-28 16:33:46 -05:00
Victor Losada Hernandez
7df2d39a6d second markdown fix(sorry) 2023-02-28 22:32:07 +01:00
Trevor Buckner
afa3fb434e Merge pull request #2703 from naturalcrit/Mark-snippets-as-experimental
Add "beta" badge on snippets marked "experimetal"
2023-02-28 16:31:39 -05: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
Trevor Buckner
7117d3caed Add "beta" badge on snippets marked "experimetal" 2023-02-28 16:26:23 -05:00
Trevor Buckner
3461c47a63 Merge pull request #2649 from 5e-Cleric/cover-snippet
Cover snippet
2023-02-28 14:08:22 -05:00
Trevor Buckner
4f715a316b Tweak CSS and snippet 2023-02-28 13:17:25 -05:00
Trevor Buckner
7a316060dd Change footnote font 2023-02-28 13:15:30 -05:00
Trevor Buckner
a96f9e2b76 Update Nodesto Font to be slightly more narrow 2023-02-28 13:14:34 -05:00
dependabot[bot]
cc3c429b58 Bump react-router-dom from 6.8.1 to 6.8.2
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.8.1 to 6.8.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.8.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-02-28 03:56:52 +00:00
dependabot[bot]
35c257ed50 Bump eslint from 8.34.0 to 8.35.0
Bumps [eslint](https://github.com/eslint/eslint) from 8.34.0 to 8.35.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.34.0...v8.35.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-02-27 03:57:15 +00:00
Michiel De Mey
a6ed05214a Updated auth 2023-02-26 14:53:26 +01:00
Michiel De Mey
27ea00e9ce Trimming Google APIs 2023-02-26 14:34:23 +01:00
Michiel De Mey
8a6cc3c0aa Fixed typo in Jest's modulePaths 2023-02-26 14:24:21 +01:00
G.Ambatte
23668f15f0 Merge branch 'master' into fixDivLinks-#2680 2023-02-26 14:50:23 +13:00
Victor Losada Hernandez
ac8c79ee63 unit change and has update 2023-02-25 22:39:25 +01:00
Michiel De Mey
9bb628da5a Use secure protocol for Homebrewery mug image
Fixes https://github.com/naturalcrit/homebrewery/issues/2687
2023-02-25 16:30:04 +01:00
Victor Losada Hernandez
5ae61e2c26 reviews plus naturalcrit logo 2023-02-23 23:28:32 +01:00
Trevor Buckner
2e7c8c0cab Remove @layer 2023-02-22 15:34:05 -05:00
Trevor Buckner
ed85e4eb0a Merge branch 'master' into cover-snippet 2023-02-22 15:06:49 -05:00
Trevor Buckner
91a2ce211d Merge branch 'cover-snippet' of https://github.com/5e-Cleric/homebrewery into pr/2649 2023-02-22 15:05:25 -05:00
Trevor Buckner
6e859aec1c Merge branch 'master' into pr/2649 2023-02-22 14:57:34 -05:00
Trevor Buckner
4d7e273f7d Merge pull request #2373 from naturalcrit/WatercolorImageMask
Watercolor image mask
2023-02-22 14:51:48 -05:00
Trevor Buckner
c3d53cfc10 Remove old comments 2023-02-22 14:51:16 -05:00
Trevor Buckner
90d5ac4603 Implement scaling, but not added to snippet 2023-02-22 14:49:11 -05:00
Trevor Buckner
096b3d00fc Fix corner snippet reversed Y position 2023-02-22 14:48:24 -05:00
Trevor Buckner
2a75c702b9 Merge branch 'master' into WatercolorImageMask 2023-02-22 13:06:20 -05:00
Trevor Buckner
c4719f0e0f Merge pull request #2682 from naturalcrit/dependabot/npm_and_yarn/babel/core-7.21.0
Bump @babel/core from 7.20.12 to 7.21.0
2023-02-22 10:04:54 -05:00
Trevor Buckner
fe6223c892 Merge pull request #2685 from naturalcrit/dependabot/npm_and_yarn/body-parser-1.20.2
Bump body-parser from 1.20.1 to 1.20.2
2023-02-22 10:03:27 -05:00
dependabot[bot]
5f01fa1add Bump body-parser from 1.20.1 to 1.20.2
Bumps [body-parser](https://github.com/expressjs/body-parser) from 1.20.1 to 1.20.2.
- [Release notes](https://github.com/expressjs/body-parser/releases)
- [Changelog](https://github.com/expressjs/body-parser/blob/master/HISTORY.md)
- [Commits](https://github.com/expressjs/body-parser/compare/1.20.1...1.20.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-22 03:16:53 +00:00
Trevor Buckner
66c80c3891 Merge pull request #2684 from naturalcrit/undoLayers
Disable @layers for now
2023-02-21 15:36:39 -05:00
Trevor Buckner
767f03fba0 Disable @layers for now
@Layers have too many conflicts with custom CSS styling. Delay until V4 renderer.
2023-02-21 15:36:01 -05:00
dependabot[bot]
62692552b1 Bump @babel/core from 7.20.12 to 7.21.0
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.20.12 to 7.21.0.
- [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.0/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-02-21 14:40:42 +00:00
Trevor Buckner
8b3bef02e8 Merge pull request #2676 from naturalcrit/dependabot/npm_and_yarn/mongoose-6.9.2
Bump mongoose from 6.9.1 to 6.9.2
2023-02-21 09:39:54 -05:00
Trevor Buckner
3a6e4ec385 Merge pull request #2683 from naturalcrit/dependabot/npm_and_yarn/babel/plugin-transform-runtime-7.21.0
Bump @babel/plugin-transform-runtime from 7.19.6 to 7.21.0
2023-02-21 09:39:20 -05:00
dependabot[bot]
d39148116b Bump @babel/plugin-transform-runtime from 7.19.6 to 7.21.0
Bumps [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-runtime) from 7.19.6 to 7.21.0.
- [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.0/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-02-21 03:58:12 +00:00
G.Ambatte
81f0670be0 Fix minor version number 2023-02-21 08:15:33 +13:00
G.Ambatte
4484035d75 Add Markdown test 2023-02-21 07:51:18 +13:00
G.Ambatte
f528b55226 Move renderer assignment to options 2023-02-21 07:42:38 +13:00
G.Ambatte
9eb8653dfb Add info to the change log 2023-02-20 21:35:53 +13:00
G.Ambatte
a65c26e806 Increase Jest timeout 2023-02-20 21:35:12 +13:00
G.Ambatte
17525a4f41 Add renderer option to HTML blocks in Markdown 2023-02-20 21:35:00 +13:00
Trevor Buckner
fe5e91c377 Merge pull request #2678 from naturalcrit/v3.6.1
Up version to 3.6.1
2023-02-18 13:57:00 -05:00
Trevor Buckner
512ef78e9e Up version to 3.6.1 2023-02-18 13:56:41 -05:00
Trevor Buckner
4fca81fd3f Merge pull request #2675 from G-Ambatte/fixAuthorDeletion-#2674
Fix author deletion #2674
2023-02-18 13:48:49 -05:00
Trevor Buckner
6a8a2f080c Lint 2023-02-18 13:48:32 -05:00
Trevor Buckner
298a10bc42 Clean up tests 2023-02-18 13:48:02 -05:00
Trevor Buckner
b6a95a2c01 Merge pull request #2677 from naturalcrit/FixDividerBarDots
Override FontAwesome conflict due to @layers
2023-02-18 13:30:32 -05:00
Trevor Buckner
b09a4ea5fa Override FontAwesome conflict due to @layers 2023-02-18 13:30:06 -05:00
G.Ambatte
1fb7fe2487 Add markModified mock function to test spec 2023-02-17 17:43:21 +13:00
G.Ambatte
e751f9a25c Remove mocking function from homebrew.api.js 2023-02-17 17:42:56 +13:00
Trevor Buckner
9e2aec18ad Get Corners fully working with x/y offset and rotate 2023-02-16 23:00:17 -05:00
dependabot[bot]
e8cf3bee34 Bump mongoose from 6.9.1 to 6.9.2
Bumps [mongoose](https://github.com/Automattic/mongoose) from 6.9.1 to 6.9.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/6.9.1...6.9.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-02-17 03:56:57 +00:00
G.Ambatte
41db670e63 Add mock markModified when it does not exist 2023-02-17 16:14:33 +13:00
G.Ambatte
74e14ca72a Restore coverage to .gitignore 2023-02-17 16:05:32 +13:00
G.Ambatte
860070b0c2 Remove coverage folder from .gitignore 2023-02-17 15:48:55 +13:00
G.Ambatte
43d1cb12db Add change log entry for v3.6.1 2023-02-17 11:30:16 +13:00
G.Ambatte
2bab0b50d2 Add coverage folder to gitignore 2023-02-17 11:26:29 +13:00
G.Ambatte
4b98c1ac89 Add markModified to fix authors array in DB 2023-02-17 11:26:11 +13:00
Trevor Buckner
d9f5e9d635 Merge pull request #2673 from naturalcrit/dependabot/npm_and_yarn/jest-29.4.3
Bump jest from 29.4.1 to 29.4.3
2023-02-16 15:19:49 -05:00
Trevor Buckner
1ce3e399a8 Merge pull request #2670 from naturalcrit/dependabot/npm_and_yarn/eslint-8.34.0
Bump eslint from 8.33.0 to 8.34.0
2023-02-16 15:19:26 -05:00
Trevor Buckner
4a12ccf2b6 Merge pull request #2669 from naturalcrit/dependabot/npm_and_yarn/googleapis-111.0.0
Bump googleapis from 110.0.0 to 111.0.0
2023-02-16 15:19:14 -05:00
Trevor Buckner
da83e1a252 Merge pull request #2666 from naturalcrit/dependabot/npm_and_yarn/react-router-dom-6.8.1
Bump react-router-dom from 6.8.0 to 6.8.1
2023-02-16 15:18:31 -05:00
Trevor Buckner
a971dd4713 Merge pull request #2665 from naturalcrit/dependabot/npm_and_yarn/mongoose-6.9.1
Bump mongoose from 6.9.0 to 6.9.1
2023-02-16 15:18:19 -05:00
dependabot[bot]
0a7e25a749 Bump jest from 29.4.1 to 29.4.3
Bumps [jest](https://github.com/facebook/jest/tree/HEAD/packages/jest) from 29.4.1 to 29.4.3.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v29.4.3/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-02-16 03:57:59 +00:00
dependabot[bot]
c9ee1bc4b0 Bump eslint from 8.33.0 to 8.34.0
Bumps [eslint](https://github.com/eslint/eslint) from 8.33.0 to 8.34.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.33.0...v8.34.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-02-13 03:58:32 +00:00
dependabot[bot]
d5c21c5881 Bump googleapis from 110.0.0 to 111.0.0
Bumps [googleapis](https://github.com/googleapis/google-api-nodejs-client) from 110.0.0 to 111.0.0.
- [Release notes](https://github.com/googleapis/google-api-nodejs-client/releases)
- [Changelog](https://github.com/googleapis/google-api-nodejs-client/blob/main/CHANGELOG.md)
- [Commits](https://github.com/googleapis/google-api-nodejs-client/compare/googleapis-v110.0.0...googleapis-v111.0.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-13 03:57:01 +00:00
Victor Losada Hernandez
3d6842bf86 i forgot to change file extensions 2023-02-11 00:48:52 +01:00
Victor Losada Hernandez
e610194ace custom icon and vectorization of assets 2023-02-11 00:38:27 +01:00
Victor Losada Hernandez
3393e72481 Merge upstream into cover-snippet 2023-02-10 23:11:12 +01:00
G.Ambatte
f644740f60 Merge branch 'master' into experimentalWinChocolateyInstall 2023-02-08 22:43:36 +13:00
Trevor Buckner
0355b52021 Custom icons for image masks in general 2023-02-07 15:36:52 -05:00
Trevor Buckner
c430e5a92b lint 2023-02-07 10:37:33 -05:00
Trevor Buckner
2ac09130a6 Remove switch statement 2023-02-07 10:36:51 -05:00
Trevor Buckner
63346cfd7a Add subsnippets for edge masks 2023-02-07 10:31:29 -05:00
Trevor Buckner
2ea639000b Update Corner snippets to use correct corner 2023-02-07 10:21:29 -05:00
Trevor Buckner
051fdbbc60 Fix snippet hover highlight not full button width 2023-02-07 10:20:43 -05:00
Trevor Buckner
d02fcc9252 Update custom position icons 2023-02-07 09:56:03 -05:00
dependabot[bot]
f157b57928 Bump react-router-dom from 6.8.0 to 6.8.1
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.8.0 to 6.8.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.8.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-02-07 03:01:39 +00:00
dependabot[bot]
e6318fefb6 Bump mongoose from 6.9.0 to 6.9.1
Bumps [mongoose](https://github.com/Automattic/mongoose) from 6.9.0 to 6.9.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/6.9.0...6.9.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-02-07 03:00:46 +00:00
G.Ambatte
dae97946dc Merge branch 'master' into fixAdminPages-#2657 2023-02-07 11:02:28 +13:00
Sean Robertson
a921452c22 Reinstate Jest timeout increase 2023-02-07 10:59:48 +13:00
Sean Robertson
b0954bcd2c Revert CircleCI config changes 2023-02-07 10:56:30 +13:00
Sean Robertson
01f90ea085 Revert Jest test timeout change 2023-02-07 10:55:34 +13:00
Trevor Buckner
33c8291a55 Merge branch 'master' into WatercolorImageMask 2023-02-06 16:25:13 -05:00
Trevor Buckner
270b20aaaf Add position options to corner snippets 2023-02-06 16:25:02 -05:00
Victor Losada Hernandez
0689d3d0b2 fix metadata font 2023-02-04 23:14:51 +01:00
Victor Losada Hernandez
877ee1cc4f Merge branch 'master' of https://github.com/naturalcrit/homebrewery into char-fix 2023-02-04 23:04:51 +01:00
Victor Losada Hernandez
5f26f857d4 Manually adding special characters 2023-02-04 23:01:08 +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
Trevor Buckner
7ea3ef8474 Merge pull request #2662 from naturalcrit/CustomSnippetIcons
Custom icons for snippets
2023-02-04 11:10:29 -05:00
Trevor Buckner
a0af588d75 Custom icons 2023-02-04 11:07:04 -05:00
Victor Losada Hernandez
f7dd03c628 U+00D1 and U+00F1 fix 2023-02-04 17:02:36 +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
G.Ambatte
d4d2356708 Remove npm audit fix 2023-02-04 10:53:19 +13:00
G.Ambatte
6d9a0938ab Add audit fix to CircleCI 2023-02-04 10:50:59 +13:00
G.Ambatte
747bb3c489 Reinstate PostInstall script for testing 2023-02-04 10:47:03 +13:00
G.Ambatte
4a695eda87 Fix outdated method in Admin API 2023-02-03 19:28:20 +13:00
G.Ambatte
208a341f27 Add test coverage report directory to gitignore 2023-02-03 19:09:01 +13:00
G.Ambatte
75a4cff319 Tweak Jest timeout value 2023-02-03 13:58:09 +13:00
G.Ambatte
72e5515830 Tweak CircleCI config 2023-02-03 13:46:52 +13:00
G.Ambatte
e5996db4f7 Merge branch 'master' into fixAdminPages-#2657 2023-02-03 09:52:02 +13:00
Trevor Buckner
6f70994a77 Merge branch 'master' into WatercolorImageMask 2023-02-02 15:49:32 -05:00
Trevor Buckner
9b06380b9c Merge pull request #2656 from naturalcrit/SubSnippets
Add a side menu for sub-snippets
2023-02-02 15:49:10 -05:00
Sean Robertson
d84fe3e5b4 Update changelog.md
Add changes to change log
2023-02-03 09:47:23 +13:00
Sean Robertson
83a62e7133 Update package.json
Update build script
Remove obsolete scripts
2023-02-03 09:44:18 +13:00
Trevor Buckner
5e38ff66da Add a side menu for sub-snippets
Subsnippets can be added to snippets as an additional property "subsnippets" which is an array of more snippets.
2023-02-02 15:29:12 -05:00
Trevor Buckner
5eb1d58059 Add rotation to corners snippet 2023-02-02 11:49:25 -05:00
Trevor Buckner
096e281a6c Rework Corner snippet and CSS to allow free rotation 2023-02-02 11:48:30 -05:00
Trevor Buckner
73f141613e Change classname from imageMask to imageMaskEdge 2023-01-31 17:03:12 -05:00
Trevor Buckner
aee240cf9b remove original text background 2023-01-31 16:00:43 -05:00
Trevor Buckner
7af2e8810a Fix snippet more, add link to imgur image 2023-01-31 16:00:31 -05:00
Trevor Buckner
24031fbfa0 Clarify snippet instructions 2023-01-31 13:33:19 -05:00
Trevor Buckner
b93e9ec95e Comment out Corners snippet for later PR 2023-01-31 13:32:10 -05:00
Trevor Buckner
347d132cde Keep fixing merge 2023-01-31 13:24:29 -05:00
Trevor Buckner
98c7ef9d12 Merge branch 'master' into WatercolorImageMask 2023-01-31 13:18:20 -05:00
Victor Losada Hernandez
5cc654a908 Part cover first draft 2023-01-31 17:11:46 +01:00
Trevor Buckner
85b3741df8 Merge pull request #2651 from 5e-Cleric/cloning-fix-2
Thanks @5e-Cleric for this fix!
2023-01-30 17:19:19 -05:00
Trevor Buckner
4260f5197c Update specs to expect a views prop from default brew 2023-01-30 17:15:33 -05:00
Trevor Buckner
f628e1a5ae Use DEFAULT_BREW values instead of setting them here 2023-01-30 17:08:19 -05:00
Trevor Buckner
14bc7e45ab Merge pull request #2619 from 5e-Cleric/readme
Readme update
2023-01-30 14:44:19 -05:00
Trevor Buckner
4668d36a52 typo 2023-01-30 14:40:13 -05:00
Victor Losada Hernandez
91fc8a1a5e Suggested changes 2023-01-30 20:30:43 +01:00
Victor Losada Hernandez
341b53c603 veracruz to Alkalami 2023-01-30 20:27:15 +01:00
Trevor Buckner
6226f3376a Merge pull request #2604 from naturalcrit/CSS-Layers
Try @Layers to not need `.page` in user style
2023-01-30 12:41:36 -05:00
Trevor Buckner
ed8b0c51af Merge pull request #2653 from naturalcrit/dependabot/npm_and_yarn/eslint-plugin-react-7.32.2
Bump eslint-plugin-react from 7.32.1 to 7.32.2
2023-01-30 12:32:41 -05:00
dependabot[bot]
a19b961b0f Bump eslint-plugin-react from 7.32.1 to 7.32.2
Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.32.1 to 7.32.2.
- [Release notes](https://github.com/jsx-eslint/eslint-plugin-react/releases)
- [Changelog](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.32.1...v7.32.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-30 16:45:54 +00:00
Trevor Buckner
f4326616b4 Merge pull request #2652 from naturalcrit/dependabot/npm_and_yarn/eslint-8.33.0
Bump eslint from 8.32.0 to 8.33.0
2023-01-30 11:44:28 -05:00
dependabot[bot]
e8509dbbed Bump eslint from 8.32.0 to 8.33.0
Bumps [eslint](https://github.com/eslint/eslint) from 8.32.0 to 8.33.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.32.0...v8.33.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-01-30 03:00:51 +00:00
Victor Losada Hernandez
541109e7b1 fix created, updated published last viewed 2023-01-28 11:47:26 +01:00
Trevor Buckner
625d3f7034 Add note about why we use !important on user page 2023-01-28 01:13:10 -05:00
Victor Losada Hernandez
78554603e8 coverPage initial draft 2023-01-28 00:43:43 +01:00
Víctor Losada Hernández
1ebbd9c8ce Merge pull request #2 from naturalcrit/master
pull from upstream
2023-01-28 00:38:48 +01:00
Trevor Buckner
5bb61a7c3c Fix userpage 2023-01-27 17:09:52 -05:00
Trevor Buckner
3c551daf16 Fix print page 2023-01-27 15:16:16 -05:00
Trevor Buckner
0bf96cb9e2 Add layers to all current themes 2023-01-27 14:57:20 -05:00
Trevor Buckner
bef4d9f41f Merge branch 'master' into CSS-Layers 2023-01-27 14:48:13 -05:00
Trevor Buckner
9ff0789387 Merge pull request #2622 from 5e-Cleric/previews
Theme previews updated
2023-01-27 14:45:47 -05:00
Trevor Buckner
a457058041 Resize dropdown button 2023-01-27 14:45:31 -05:00
Trevor Buckner
6d40e63e96 Merge branch 'master' into pr/2622 2023-01-27 14:26:05 -05:00
Trevor Buckner
964342a13d Merge pull request #2646 from naturalcrit/dependabot/npm_and_yarn/react-router-dom-6.8.0
Bump react-router-dom from 6.7.0 to 6.8.0
2023-01-27 14:04:35 -05:00
Trevor Buckner
9067cbdced Merge pull request #2644 from naturalcrit/dependabot/npm_and_yarn/mongoose-6.9.0
Bump mongoose from 6.8.4 to 6.9.0
2023-01-27 14:04:25 -05:00
Trevor Buckner
c9fd2c63af Merge pull request #2647 from naturalcrit/dependabot/npm_and_yarn/jest-29.4.1
Bump jest from 29.4.0 to 29.4.1
2023-01-27 14:04:16 -05:00
Trevor Buckner
ec8126eb8a Merge pull request #2648 from naturalcrit/FixNodestoFont
Update fonts.less path for Nodesto fonts
2023-01-27 14:04:03 -05:00
Trevor Buckner
6aa1920061 Update fonts.less 2023-01-27 14:02:11 -05:00
dependabot[bot]
07325a7550 Bump jest from 29.4.0 to 29.4.1
Bumps [jest](https://github.com/facebook/jest/tree/HEAD/packages/jest) from 29.4.0 to 29.4.1.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v29.4.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-01-27 03:01:43 +00:00
dependabot[bot]
7fa50099a6 Bump react-router-dom from 6.7.0 to 6.8.0
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.7.0 to 6.8.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.8.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-01-27 03:00:56 +00:00
Charlie Humphreys
4c42a9e2fc add changelog 2023-01-25 23:27:01 -06:00
Charlie Humphreys
4ae751bf70 Merge branch 'master' into content-negotiation-middleware 2023-01-25 23:01:31 -06:00
Charlie Humphreys
b77c70054a adjust content-negotiation middleware to elvis on the accept header 2023-01-25 23:00:05 -06:00
dependabot[bot]
12b1c41716 Bump mongoose from 6.8.4 to 6.9.0
Bumps [mongoose](https://github.com/Automattic/mongoose) from 6.8.4 to 6.9.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/6.8.4...6.9.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-01-26 03:02:15 +00:00
Trevor Buckner
62d193ddd1 Merge pull request #2639 from naturalcrit/dependabot/npm_and_yarn/jest-29.4.0
Bump jest from 29.3.1 to 29.4.0
2023-01-25 11:38:09 -05:00
dependabot[bot]
750c650b69 Bump jest from 29.3.1 to 29.4.0
Bumps [jest](https://github.com/facebook/jest/tree/HEAD/packages/jest) from 29.3.1 to 29.4.0.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v29.4.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-01-25 03:01:12 +00:00
Trevor Buckner
70219f1bd4 Merge pull request #2628 from naturalcrit/v3.6.0
Update Version to v3.6.0
2023-01-23 16:02:07 -05:00
Trevor Buckner
c8f9e5bcf2 Update Version to v3.6.0 2023-01-23 16:01:32 -05:00
Trevor Buckner
0a9a5909d1 Merge pull request #2589 from jeddai/client-server-version-mismatch-middleware
adjust frontend error handling, add client/server mismatch middleware
2023-01-23 15:40:48 -05:00
Charlie Humphreys
8f75ea4728 fix error issue 2023-01-23 14:22:18 -06:00
Trevor Buckner
91ad46b202 Merge pull request #2627 from naturalcrit/dependabot/npm_and_yarn/cookiejar-2.1.4
Bump cookiejar from 2.1.3 to 2.1.4
2023-01-23 14:59:58 -05:00
Trevor Buckner
752806c0ef Merge pull request #2616 from naturalcrit/dependabot/npm_and_yarn/react-router-dom-6.7.0
Bump react-router-dom from 6.6.1 to 6.7.0
2023-01-23 14:59:41 -05:00
dependabot[bot]
c39bb67bf3 Bump cookiejar from 2.1.3 to 2.1.4
Bumps [cookiejar](https://github.com/bmeck/node-cookiejar) from 2.1.3 to 2.1.4.
- [Release notes](https://github.com/bmeck/node-cookiejar/releases)
- [Commits](https://github.com/bmeck/node-cookiejar/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-23 19:58:54 +00:00
Trevor Buckner
fe6097e0d9 Merge pull request #2607 from naturalcrit/dependabot/npm_and_yarn/eslint-8.32.0
Bump eslint from 8.31.0 to 8.32.0
2023-01-23 14:58:12 -05:00
Charlie Humphreys
6ddf0bb889 update metadata editor to include error handling 2023-01-23 09:35:19 -06:00
Trevor Buckner
8dcbad97df Merge pull request #2623 from 5e-Cleric/Cloning-views-fix
Cloning views fix
2023-01-23 10:14:23 -05:00
Trevor Buckner
64b3955bc9 Update Dependencies 2023-01-23 10:13:59 -05:00
G.Ambatte
055773b1c3 Merge branch 'master' into experimentalWinChocolateyInstall 2023-01-23 22:50:30 +13:00
G.Ambatte
c3936d28d9 Add README.WINDOWS.md 2023-01-23 22:50:01 +13:00
G.Ambatte
607a66a8f0 Fix typo 2023-01-23 22:35:35 +13:00
G.Ambatte
658aee8806 Fix titles 2023-01-23 22:31:04 +13:00
G.Ambatte
c60be5d24b Add colors to Script titles 2023-01-23 22:14:03 +13:00
G.Ambatte
3d5a8b5627 Reduced to a single install file 2023-01-23 21:46:08 +13:00
G.Ambatte
d11508886b Add final notes to each install part 2023-01-23 21:13:40 +13:00
G.Ambatte
4bb64a535f Split install script into two parts 2023-01-23 21:00:00 +13:00
G.Ambatte
c956100416 Improve commenting in script 2023-01-23 18:16:06 +13:00
G.Ambatte
458d104866 Fix typo 2023-01-23 18:13:55 +13:00
G.Ambatte
029230e075 Initial commit 2023-01-23 15:33:00 +13:00
Victor Losada Hernandez
0f88a13635 Merge branch 'master' of hb into Cloning-views-fix 2023-01-22 22:11:23 +01:00
Victor Losada Hernandez
e8c7d38608 setting view count to 0 2023-01-22 21:57:14 +01:00
Trevor Buckner
6020657529 Ensure getBrew returns an object if undefined 2023-01-22 21:57:14 +01:00
Trevor Buckner
a8c35f3967 Remove extra console log for getGoogleBrew
App.js already logs the thrown error, so we were getting double logs (and Google errors are long....). This should make the logs a bit easier to sift through.
2023-01-22 21:57:13 +01:00
Trevor Buckner
62fa8f511a Only fix stub if we actually found one. 2023-01-22 21:57:13 +01:00
Trevor Buckner
18cf202ac0 If no stub exists, start stub as {}, not undefined
Recent changes to handle bad brew properties (tags as strings, no renderer, etc.) didn't account for the case where an old Google brew is first being stubbed; since no stub exists, there is no object to perform the corrections on, and we crash.
2023-01-22 21:57:13 +01:00
Trevor Buckner
98d9018e13 Fix saving issue when tags do not exist
Rare case where tags don't exist at all; gets confused in the step of converting tag strings to arrays
2023-01-22 21:57:13 +01:00
Trevor Buckner
a9e14f6165 Enable brew version mismatch checking on server
Was commented out previously to allow users time to update client code so the proper error displays
2023-01-22 21:57:13 +01:00
dependabot[bot]
7005e9f760 Bump mongoose from 6.8.2 to 6.8.3
Bumps [mongoose](https://github.com/Automattic/mongoose) from 6.8.2 to 6.8.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/6.8.2...6.8.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-01-22 21:57:13 +01:00
dependabot[bot]
163bc4e0b3 Bump @babel/core from 7.20.7 to 7.20.12
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.20.7 to 7.20.12.
- [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.20.12/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-01-22 21:57:13 +01:00
dependabot[bot]
3420886192 Bump eslint from 8.31.0 to 8.32.0
Bumps [eslint](https://github.com/eslint/eslint) from 8.31.0 to 8.32.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.31.0...v8.32.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-01-22 17:31:41 +00:00
Trevor Buckner
1704ef6557 Merge pull request #2610 from naturalcrit/dependabot/npm_and_yarn/eslint-plugin-react-7.32.1
Bump eslint-plugin-react from 7.31.11 to 7.32.1
2023-01-22 12:30:28 -05:00
Trevor Buckner
637b3311d6 Merge pull request #2612 from naturalcrit/dependabot/npm_and_yarn/mongoose-6.8.4
Bump mongoose from 6.8.3 to 6.8.4
2023-01-22 12:30:09 -05:00
Trevor Buckner
4b8c34bcbd Merge pull request #2608 from naturalcrit/dependabot/npm_and_yarn/marked-4.2.12
Bump marked from 4.2.5 to 4.2.12
2023-01-22 12:29:50 -05:00
Victor Losada Hernandez
0c68e5870b admin privileges detail readme 2023-01-22 15:52:28 +01:00
Charlie Humphreys
82622744a1 Merge branch 'client-server-version-mismatch-middleware' into content-negotiation-middleware 2023-01-21 15:01:22 -06:00
Charlie Humphreys
d5a34eedb9 Merge branch 'master' into client-server-version-mismatch-middleware 2023-01-21 15:00:54 -06:00
Victor Losada Hernandez
d0dc83cf10 preview images updated 2023-01-21 17:15:50 +01:00
Trevor Buckner
c997908a49 Merge pull request #2621 from jeddai/adjust-coverage-thresholds
lower coverage thresholds for api
2023-01-21 11:11:31 -05:00
Victor Losada Hernandez
45c7ac4b85 Themes dropdown previews 2023-01-21 17:11:28 +01:00
Trevor Buckner
128b299f25 Ensure getBrew returns an object if undefined 2023-01-21 17:11:28 +01:00
Trevor Buckner
692daa88fc Remove extra console log for getGoogleBrew
App.js already logs the thrown error, so we were getting double logs (and Google errors are long....). This should make the logs a bit easier to sift through.
2023-01-21 17:11:28 +01:00
Trevor Buckner
bd6eb816f2 Only fix stub if we actually found one. 2023-01-21 17:11:28 +01:00
Trevor Buckner
2050028484 If no stub exists, start stub as {}, not undefined
Recent changes to handle bad brew properties (tags as strings, no renderer, etc.) didn't account for the case where an old Google brew is first being stubbed; since no stub exists, there is no object to perform the corrections on, and we crash.
2023-01-21 17:11:28 +01:00
Trevor Buckner
7e4018351d Fix saving issue when tags do not exist
Rare case where tags don't exist at all; gets confused in the step of converting tag strings to arrays
2023-01-21 17:11:28 +01:00
Trevor Buckner
01b03e8683 Enable brew version mismatch checking on server
Was commented out previously to allow users time to update client code so the proper error displays
2023-01-21 17:11:28 +01:00
dependabot[bot]
3538aa6da0 Bump mongoose from 6.8.2 to 6.8.3
Bumps [mongoose](https://github.com/Automattic/mongoose) from 6.8.2 to 6.8.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/6.8.2...6.8.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-01-21 17:11:28 +01:00
dependabot[bot]
13eb6cac17 Bump @babel/core from 7.20.7 to 7.20.12
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.20.7 to 7.20.12.
- [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.20.12/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-01-21 17:11:28 +01:00
Charlie Humphreys
bd594fa214 lower coverage thresholds for api 2023-01-21 09:22:58 -06:00
Charlie Humphreys
8b0203dd7c add content negotiation middleware and tests 2023-01-21 00:48:41 -06:00
Charlie Humphreys
6bae21a578 Merge branch 'master' into client-server-version-mismatch-middleware 2023-01-21 00:26:18 -06:00
Charlie Humphreys
79db97efdf create error navitem and use it in all necessary use cases 2023-01-21 00:25:35 -06:00
Charlie Humphreys
7755affa1e update based on feedback 2023-01-20 23:07:24 -06:00
Victor Losada Hernandez
6b6e05ca11 Readme update, installation text improved 2023-01-21 00:05:54 +01:00
Trevor Buckner
ea04069fe5 Merge pull request #2618 from naturalcrit/FixGoogleBrewsDuplicatingOnStub
Fix Google Drive brews duplicating
2023-01-20 17:25:47 -05:00
Trevor Buckner
2c3a302c85 Merge branch 'master' into FixGoogleBrewsDuplicatingOnStub 2023-01-20 17:25:07 -05:00
Trevor Buckner
89d9bfe1f1 Merge pull request #2606 from G-Ambatte/addThemesToWatchList-#2605
[LOCAL] Add Themes directory to watch list
2023-01-20 17:21:15 -05:00
Trevor Buckner
c9241e2162 Fix Google Drive brews duplicating 2023-01-20 17:19:02 -05:00
dependabot[bot]
99f7668901 Bump react-router-dom from 6.6.1 to 6.7.0
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.6.1 to 6.7.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.7.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-01-19 03:01:37 +00:00
dependabot[bot]
187738ee11 Bump mongoose from 6.8.3 to 6.8.4
Bumps [mongoose](https://github.com/Automattic/mongoose) from 6.8.3 to 6.8.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/6.8.3...6.8.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-01-18 03:01:47 +00:00
dependabot[bot]
68d3724e50 Bump eslint-plugin-react from 7.31.11 to 7.32.1
Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.31.11 to 7.32.1.
- [Release notes](https://github.com/jsx-eslint/eslint-plugin-react/releases)
- [Changelog](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.31.11...v7.32.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-17 03:00:45 +00:00
dependabot[bot]
8526faa041 Bump marked from 4.2.5 to 4.2.12
Bumps [marked](https://github.com/markedjs/marked) from 4.2.5 to 4.2.12.
- [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.2.5...v4.2.12)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-16 03:01:52 +00:00
G.Ambatte
ac9fbb1f08 Move changes from 3.6.1 to 3.6.0 2023-01-15 18:24:23 +13:00
G.Ambatte
e82da3a6c1 Add buildDev to NPM scripts 2023-01-15 18:19:23 +13:00
G.Ambatte
40e36fd875 Fix minor version number 2023-01-15 17:26:56 +13:00
G.Ambatte
3c86984cf1 Add change to changelog 2023-01-15 14:13:25 +13:00
G.Ambatte
50d172bbd5 Add Themes directory to watch list 2023-01-15 14:11:33 +13:00
Trevor Buckner
a22d59475e Try @Layers to not need .page in user style 2023-01-13 17:08:12 -05:00
Trevor Buckner
da676c6ec1 Ensure getBrew returns an object if undefined 2023-01-12 13:33:55 -05:00
Trevor Buckner
901615d99e Remove extra console log for getGoogleBrew
App.js already logs the thrown error, so we were getting double logs (and Google errors are long....). This should make the logs a bit easier to sift through.
2023-01-10 21:08:21 -05:00
Trevor Buckner
6ed52f37cc Only fix stub if we actually found one. 2023-01-09 17:30:49 -05:00
Trevor Buckner
15e5a31767 If no stub exists, start stub as {}, not undefined
Recent changes to handle bad brew properties (tags as strings, no renderer, etc.) didn't account for the case where an old Google brew is first being stubbed; since no stub exists, there is no object to perform the corrections on, and we crash.
2023-01-09 14:53:35 -05:00
Trevor Buckner
8cbab4d4ce Fix saving issue when tags do not exist
Rare case where tags don't exist at all; gets confused in the step of converting tag strings to arrays
2023-01-09 14:12:57 -05:00
Trevor Buckner
a9c28e84d0 Enable brew version mismatch checking on server
Was commented out previously to allow users time to update client code so the proper error displays
2023-01-09 10:30:07 -05:00
Trevor Buckner
bafabb84b4 Merge pull request #2591 from naturalcrit/dependabot/npm_and_yarn/mongoose-6.8.3
Bump mongoose from 6.8.2 to 6.8.3
2023-01-09 10:26:36 -05:00
dependabot[bot]
f5d592a291 Bump mongoose from 6.8.2 to 6.8.3
Bumps [mongoose](https://github.com/Automattic/mongoose) from 6.8.2 to 6.8.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/6.8.2...6.8.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-01-09 03:00:50 +00:00
Trevor Buckner
aa23da6ce4 Move curly CSS up so they don't overwrite styles 2023-01-07 00:25:46 -05:00
Charlie Humphreys
385bee964d adjust frontend error handling, add client/server mismatch middleware 2023-01-06 21:29:21 -06:00
Trevor Buckner
18f277182a Merge pull request #2588 from naturalcrit/dependabot/npm_and_yarn/babel/core-7.20.12
Bump @babel/core from 7.20.7 to 7.20.12
2023-01-06 13:08:12 -05:00
Trevor Buckner
344a9d8334 Merge pull request #2548 from jeddai/api-tests
Add api tests
2023-01-06 13:07:54 -05:00
Charlie Humphreys
67a76f9d86 adjust circleci command for API unit tests 2023-01-06 11:53:38 -06:00
Charlie Humphreys
93d6d1ac6a add unit test command 2023-01-06 11:48:00 -06:00
Charlie Humphreys
4b3edf053f add coverage thresholds and coverage command 2023-01-05 23:30:20 -06:00
Charlie Humphreys
0720ac6a15 update changelog 2023-01-05 23:29:58 -06:00
Charlie Humphreys
c0b9cd951e update circleci test config to run test coverage 2023-01-05 23:29:43 -06:00
Charlie Humphreys
a54ebabf53 fix tests after merge from master 2023-01-05 23:10:25 -06:00
Charlie Humphreys
676acb9e5a Merge branch 'master' into api-tests 2023-01-05 23:02:43 -06:00
Charlie Humphreys
387c468d84 add tests for deletion and address PR feedback 2023-01-05 22:56:54 -06:00
dependabot[bot]
64e7fe3422 Bump @babel/core from 7.20.7 to 7.20.12
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.20.7 to 7.20.12.
- [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.20.12/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-01-05 03:01:25 +00:00
Trevor Buckner
2b1466c51b Merge pull request #2587 from naturalcrit/FixThemesOnPrint
Fix Themes on /print
2023-01-04 21:41:15 -05:00
Trevor Buckner
332bcde4b2 Themes weren't being picked up for rendering 2023-01-04 21:39:51 -05:00
Trevor Buckner
db783179ce Merge pull request #2429 from G-Ambatte/fixThemesDefault
Add default brew on load and before save
2023-01-04 21:36:37 -05:00
Trevor Buckner
c78d687387 Fix all brews being forced to V3 on load 2023-01-04 21:32:16 -05:00
Trevor Buckner
b717059a39 Fix /new storing string "undefined" in Style tab 2023-01-04 20:58:29 -05:00
Trevor Buckner
e02bde5eed Cleanup; added more fields to DEFAULT_BREW 2023-01-04 17:33:23 -05:00
Trevor Buckner
e1765cad41 Merge branch 'fixThemesDefault' of https://github.com/G-Ambatte/homebrewery into pr/2429 2023-01-03 15:13:41 -05:00
Trevor Buckner
6dab5f836e Merge branch 'master' into pr/2429 2023-01-03 15:13:19 -05:00
Charlie Humphreys
e47f81698c Merge branch 'master' into api-tests 2023-01-03 13:47:09 -06:00
Trevor Buckner
2b824839c3 Merge pull request #2581 from naturalcrit/dependabot/npm_and_yarn/eslint-8.31.0
Bump eslint from 8.30.0 to 8.31.0
2023-01-03 14:05:28 -05:00
Trevor Buckner
26f009a295 Merge pull request #2577 from naturalcrit/dependabot/npm_and_yarn/react-router-dom-6.6.1
Bump react-router-dom from 6.6.0 to 6.6.1
2023-01-03 14:05:18 -05:00
Trevor Buckner
9b4c997b57 Merge pull request #2578 from naturalcrit/dependabot/npm_and_yarn/mongoose-6.8.2
Bump mongoose from 6.8.1 to 6.8.2
2023-01-03 14:05:10 -05:00
Trevor Buckner
39143295b1 Merge pull request #2576 from naturalcrit/dependabot/npm_and_yarn/marked-4.2.5
Bump marked from 4.2.4 to 4.2.5
2023-01-03 14:05:01 -05:00
Trevor Buckner
6eaf2feb40 Log version mismatch errors
To gauge how frequently they are occurring for future update.
2023-01-03 12:47:17 -05:00
Trevor Buckner
4fe0f1a7af Comment out server-side brew version checking
Requires client-side update to apply brew version correctly; temporarily disabling server-side checking for a few days until more users have updated their clients.
2023-01-03 12:38:00 -05:00
Trevor Buckner
7aac377ce8 Merge pull request #2575 from jeddai/google-brew-version-comparison-fix
add check for truthy version, and make sure the version exists when incrementing it
2023-01-03 11:22:37 -05:00
dependabot[bot]
77542c5f06 Bump eslint from 8.30.0 to 8.31.0
Bumps [eslint](https://github.com/eslint/eslint) from 8.30.0 to 8.31.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.30.0...v8.31.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-01-02 03:01:18 +00:00
dependabot[bot]
3d365339e4 Bump mongoose from 6.8.1 to 6.8.2
Bumps [mongoose](https://github.com/Automattic/mongoose) from 6.8.1 to 6.8.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/6.8.1...6.8.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-29 03:01:18 +00:00
dependabot[bot]
66be400f5f Bump react-router-dom from 6.6.0 to 6.6.1
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.6.0 to 6.6.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.6.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>
2022-12-26 03:01:12 +00:00
dependabot[bot]
9880792c4d Bump marked from 4.2.4 to 4.2.5
Bumps [marked](https://github.com/markedjs/marked) from 4.2.4 to 4.2.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/v4.2.4...v4.2.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-26 03:00:50 +00:00
Charlie Humphreys
ca03a473ec add check for truthy version, and make sure the version exists when incrementing it 2022-12-23 14:31:58 -06:00
Trevor Buckner
c364856942 Merge branch 'master' into fixThemesDefault 2022-12-23 13:40:12 -05:00
Trevor Buckner
4e7a96b67c Merge pull request #2571 from naturalcrit/v3.5.0
v3.5.0
2022-12-23 13:25:00 -05:00
Trevor Buckner
39bfc818a6 Merge pull request #2572 from jeddai/new-props-authors-fix
add elvis to fix invited authors editor
2022-12-23 13:24:48 -05:00
Charlie Humphreys
6d9982f735 add elvis to fix invited authors editor 2022-12-23 12:21:15 -06:00
Charlie Humphreys
da9e20e96f add more tests and merge from main 2022-12-23 00:11:46 -06:00
Charlie Humphreys
925db96b08 Merge branch 'fixThemesDefault' into api-tests 2022-12-22 20:09:49 -06:00
G.Ambatte
efdb8e07b0 Merge branch 'master' into fixThemesDefault 2022-12-23 13:03:31 +13:00
G.Ambatte
32506860dd Add additional fields to default 2022-12-14 21:26:57 +13:00
G.Ambatte
a89b20584f Apply default to EditPage 2022-12-14 21:26:40 +13:00
G.Ambatte
8e42c09721 Apply default to HomePage 2022-12-14 21:26:31 +13:00
G.Ambatte
bb5978dfea Apply default to SharePage 2022-12-14 21:26:20 +13:00
G.Ambatte
0dc491adfc Apply default to NewPage 2022-12-14 21:26:11 +13:00
G.Ambatte
f470a6185a Move default brew to app.js 2022-12-14 19:23:16 +13:00
G.Ambatte
0a885c8581 Merge branch 'master' into fixThemesDefault 2022-12-14 12:30:28 +13:00
G.Ambatte
ec9c704e71 Merge branch 'master' into fixThemesDefault 2022-12-14 11:57:37 +13:00
Charlie Humphreys
a451e562fb add initial set of tests for api 2022-12-06 00:01:38 -06:00
Gazook89
76d73e0e02 prevent crash if desired attr is not available. 2022-11-29 12:25:58 -06:00
Gazook89
9e289ad6d1 remove unused require 2022-11-29 12:12:10 -06:00
Gazook89
914a4586b9 set dropdown list scroll to auto 2022-11-29 12:08:52 -06:00
Gazook89
12fe787ab4 allow strings for filterOn 2022-11-29 12:06:38 -06:00
Gazook89
fc7c46cfec add ability to filter options on any number of attributes 2022-11-28 21:39:41 -06:00
Gazook89
8d80f699b6 add 'title' attr to lang options 2022-11-24 23:50:19 -06:00
Gazook89
e1ff34ebaa add placeholder to input 2022-11-24 23:33:04 -06:00
Gazook89
ce732778bb add .value div for consistency and styling 2022-11-24 23:21:47 -06:00
Gazook89
b54d225f11 add autoSuggest option to filter on chosen attribute 2022-11-24 23:08:41 -06:00
Gazook89
fb95039368 edit/add autoSuggest options 2022-11-24 22:51:16 -06:00
Gazook89
60ca9530a3 change height to max-height 2022-11-24 20:03:35 -06:00
Gazook89
70d8491e7c remove comment 2022-11-24 19:56:40 -06:00
Gazook89
a9ff1cded7 add autoSuggest option based on option 'value' 2022-11-24 19:55:18 -06:00
Gazook89
417f9d7291 adjust styling to make individual items more apparent 2022-11-24 11:22:25 -06:00
Gazook89
adb261f8f1 revert change to Themes dropdown 2022-11-23 22:44:17 -06:00
Gazook89
678c1fb3d8 create combobox 2022-11-23 22:34:32 -06:00
Trevor Buckner
e4a9c73f56 Merge branch 'master' into WatercolorImageMask 2022-11-23 15:51:49 -05:00
Gazook89
1818ea1e3b dropdown changes 2022-11-22 12:02:27 -06:00
Gazook89
d4b803205e add a few language tags with subtags 2022-11-20 22:20:22 -06:00
Gazook89
a16f12546a set name attr's on inputs to remove autocomplete 2022-11-20 22:11:46 -06:00
Gazook89
b3343e5981 adjust console log of valid errors. 2022-11-20 12:00:35 -06:00
Gazook89
0061040cb6 add a few more language codes to datalist. 2022-11-20 11:56:35 -06:00
Gazook89
c2d79bedb5 add more robust lang code regexp. 2022-11-20 11:42:01 -06:00
Gazook89
9ce79fbe3f update validation on lang field 2022-11-19 19:41:17 -06:00
Gazook89
806dcb04eb change default to 'en', including if input is left empty 2022-11-19 19:27:27 -06:00
Gazook89
d5ea4c4e77 Merge branch 'master' into Language-Attribute 2022-11-19 11:30:54 -06:00
Gazook89
8ca44653e9 use 'en' as default if no entry in input 2022-10-23 22:33:22 -05:00
Gazook89
0b5d9714c0 remove complicated languageCode regexp 2022-10-23 22:27:12 -05:00
Gazook89
b0110f20d2 add alphabetic sort, add keys, minor changes 2022-10-23 22:05:21 -05:00
Gazook89
9e227dadd2 add placeholder text 2022-10-23 21:42:22 -05:00
Gazook89
a214f27e9c set autocomplete to off 2022-10-23 21:22:57 -05:00
Gazook89
2d3b03a9c3 basically the whole thing 2022-10-23 13:11:12 -05:00
Gazook89
af094474b8 flailing around. 2022-10-21 12:01:19 -05:00
Gazook89
d92d00581a Merge branch 'master' into Language-Attribute 2022-10-20 12:40:49 -05:00
G.Ambatte
52a79b4f75 Add default loading properties using custom assign 2022-10-20 19:11:31 +13:00
G.Ambatte
9ccf9d0a83 Merge branch 'master' into fixThemesDefault 2022-10-20 08:03:43 +13:00
G.Ambatte
9ad915c14a Remove unnecessary & incorrect default setting 2022-10-09 21:50:31 +13:00
G.Ambatte
9fd5fea50c Remove obsolete code in app.js 2022-10-09 21:50:11 +13:00
G.Ambatte
41fa0f2c77 Apply defaults on load and before saving 2022-10-09 21:49:25 +13:00
Trevor Buckner
89c091c630 Add 8 corner images.
Doesn't work well with --rotation but you can just set top,left or whatever. --offset works.
2022-09-27 23:55:24 -04:00
Trevor Buckner
b8d7d1a8e4 Allow rotation and positioning up and down 2022-09-25 21:43:40 -04:00
Gazook89
4dc1a60934 add lang property to brewRender and metadataEditor 2022-09-21 13:25:40 -05:00
Gazook89
bce7cf41af add 'lang' as a brew metadata property 2022-09-21 12:21:32 -05:00
Gazook89
8c6fd3086c add language field in metadata editor 2022-09-21 12:07:07 -05:00
Trevor Buckner
d079985e6c Add checkerboard behind image to show position 2022-09-16 00:30:39 -04:00
Trevor Buckner
aba2746f89 Initial commit 2022-09-15 00:35:35 -04:00
LUCASTUCIOUS
2019d91711 [V3] Fix note render to pdf 2022-04-11 22:12:01 +02:00
187 changed files with 23122 additions and 30510 deletions

View File

@@ -48,22 +48,28 @@ jobs:
- image: cimg/node:16.11.0
working_directory: ~/homebrewery
parallelism: 4
parallelism: 1
steps:
- attach_workspace:
at: .
# run tests!
- run:
name: Test - API Unit Tests
command: npm run test:api-unit
- run:
name: Test - Basic
command: npm run test:basic
- run:
name: Test - Mustache Spans
command: npm run test:mustache-span
command: npm run test:mustache-syntax
- run:
name: Test - Routes
command: npm run test:route
- run:
name: Test - Coverage
command: npm run test:coverage
workflows:
build_and_test:

View File

@@ -11,7 +11,7 @@ module.exports = {
browser : true,
node : true
},
plugins : ['react'],
plugins : ['react', 'jest'],
rules : {
/** Errors **/
'camelcase' : ['error', { properties: 'never' }],
@@ -24,6 +24,7 @@ module.exports = {
'react/jsx-no-bind' : ['error', { allowArrowFunctions: true }],
'react/jsx-uses-react' : 'error',
'react/prefer-es6-class' : ['error', 'never'],
'jest/valid-expect' : ['error', { maxArgs: 3 }],
/** Warnings **/
'max-lines' : ['warn', {

2
.gitignore vendored
View File

@@ -12,3 +12,5 @@ todo.md
startDB.bat
startMViewer.bat
.vscode
coverage

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

View File

@@ -21,24 +21,29 @@ below.
First, install three programs that The Homebrewery requires to run and retrieve
updates:
1. install [node](https://nodejs.org/en/)
1. install [node](https://nodejs.org/en/), version v16 or higher.
1. install [mongodb](https://www.mongodb.com/try/download/community) (Community version)
For the easiest installation, follow these steps:
1. In the installer, uncheck the option to run as a service.
1. You can install MongoDB Compass if you want a GUI to view your database documents.
1. If you install any version over 6.0, you will have to install [MongoDB Shell](https://www.mongodb.com/try/download/shell).
1. Go to the C:\ drive and create a folder called "data".
1. Inside the "data" folder, create a new folder called "db".
1. Open a command prompt or other terminal and navigate to your MongoDB install folder (C:\Program Files\Mongo\Server\4.4\bin).
1. Open a command prompt or other terminal and navigate to your MongoDB install folder (C:\Program Files\Mongo\Server\6.0\bin).
1. In the command prompt, run "mongod", which will start up your local database server.
1. While MongoD is running, open a second command prompt and navigate to the MongoDB install folder.
1. In the second command prompt, run "mongo", which allows you to edit the database.
1. Type `use homebrewery` to create The Homebrewery database. You should see `switched to db homebrewery`.
1. Type `db.brews.insert({"title":"test"})` to create a blank document. You should see `WriteResult({ "nInserted" : 1 })`.
1. Search in Windows for "Advanced system settings" and open it.
1. Click "Environment variables", find the "path" variable, and double-click to open it.
1. Click "New" and paste in the path to the MongoDB "bin" folder.
1. Click "OK" three times to close all the windows.
1. In the second command prompt, run "mongo", which allows you to edit the database.
1. Type `use homebrewery` to create The Homebrewery database. You should see `switched to db homebrewery`.
1. Type `db.brews.insertOne({"title":"test"})` to create a blank document. You should see `{
acknowledged: true,
insertedId: ObjectId("63c2fce9e5ac5a94fe2410cf")
}`
1. install [git](https://git-scm.com/downloads) (select the option that allows Git to run from the command prompt).
Checkout the repo ([documentation][github-clone-repo-docs-url]):
@@ -51,11 +56,19 @@ git clone https://github.com/naturalcrit/homebrewery.git
Second, you will need to add the environment variable `NODE_ENV=local` to allow
the project to run locally.
You can set this temporarily in your shell of choice:
You can set this **temporarily** (until you close the terminal) in your shell of choice with admin privileges:
* Windows Powershell: `$env:NODE_ENV="local"`
* Windows CMD: `set NODE_ENV=local`
* Linux / macOS: `export NODE_ENV=local`
If you want to add this variable **permanently** the steps are as follows:
1. Search in Windows for "Advanced system settings" and open it.
1. Click "Environment variables".
1. In System Variables, click "New"
1. Click "New" and write `NODE_ENV` as a name and `local` as the value.
1. Click "OK" three times to close all the windows.
This can be undone at any time if needed.
Third, you will need to install the Node dependencies, compile the app, and run
it using the two commands:
@@ -65,6 +78,13 @@ it using the two commands:
You should now be able to go to [http://localhost:8000](http://localhost:8000)
in your browser and use The Homebrewery offline.
If you had any issue at all, here are some links that may be useful:
- [Course](https://learn.mongodb.com/courses/m103-basic-cluster-administration) on cluster administration, useful for beginners
- [Mongo community forums](https://www.mongodb.com/community/forums/)
- Useful Stack Overflow links for your most probable errors: [1](https://stackoverflow.com/questions/44962540/mongod-and-mongo-commands-not-working-on-windows-10), [2](https://stackoverflow.com/questions/15053893/mongo-command-not-recognized-when-trying-to-connect-to-a-mongodb-server/41507803#41507803), [3](https://stackoverflow.com/questions/51224959/mongo-is-not-recognized-as-an-internal-or-external-command-operable-program-o)
If you still have problems, post in [Our Subreddit](https://www.reddit.com/r/homebrewery/) and we will help you.
### Running the application via Docker
Please see the docs here: [README.DOCKER.md](./README.DOCKER.md)

View File

@@ -1,4 +1,23 @@
```css
.beta {
color : white;
padding : 4px 6px;
line-height : 1em;
background : grey;
border-radius : 12px;
font-family : monospace;
font-size : 10px;
font-weight : 800;
margin-top : -5px;
margin-bottom : -5px;
}
.fac {
height: 1em;
line-height: 2em;
margin-bottom: -0.05cm
}
h5 {
font-size: .35cm !important;
}
@@ -52,11 +71,204 @@ pre {
font-family: 'Open Sans';
font-size: 0.9em;
}
.page {
padding-bottom: 1.5cm;
}
```
## changelog
For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery).
### 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-Clerc
* [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
##### calculuschild
* [x] Rename `{{coverPage}}` to `{{frontCover}}`. Those using this {{beta BETA}} feature will need to update that text to make the cover page appear again.
* [x] Several background fixes to test scripts
##### Jeddai
* [X] Add content negotiation to exclude image requests from our API calls
Fixes issue [#2595](https://github.com/naturalcrit/homebrewery/issues/2595)
##### G-Ambatte
* [x] Update server build scripts to fix Admin page
Fixes issues [#2657](https://github.com/naturalcrit/homebrewery/issues/2657)
* [x] Fix internal links inside `<\div>` blocks not receiving the `target=_self` attribute
Fixes issues [#2680](https://github.com/naturalcrit/homebrewery/issues/2680)
* [x] See brew details on `/share` pages by clicking the brew title (author, last update, tags, etc.)
Fixes issues [#1679](https://github.com/naturalcrit/homebrewery/issues/1679)
* [x] Add local Windows install script via Chocolatey
##### 5e-Clerc
* [x] New {{openSans **TABLES → {{fas,fa-language}} RUNE TABLE**}} snippets for V3. Adds an alphabetic script translation table.
* [x] New {{openSans **IMAGES → {{fac,mask-center}} WATERCOLOR CENTER** }} snippets for V3, which adds a stylish watercolor texture to the center of your images!
* [x] New {{openSans **PHB → {{fac,book-inside-cover}} INSIDE COVER PAGE** }} snippet for V3! (Thanks to /u/Kaiburr_Kath-Hound on Reddit for providing some of these resources!)
* [x] Add some missing characters {{font-family:scalySansRemake Ñ ñ ç Ç Ý ý # ^ ¿ ' " ¡ ·}} to the "scalySansRemake" font in V3.
Fixes issues [#2280](https://github.com/naturalcrit/homebrewery/issues/2280)
##### Gazook89
* [x] Add "Language" selector in {{fa,fa-info-circle}} **Properties** menu. Sets the HTML Lang attribute for your brew to better handle hyphenation or spellcheck.
Fixes issues [#1343](https://github.com/naturalcrit/homebrewery/issues/1343)
* [x] Fix a crash when multiple `{injection}` tags appear in sequence
Fixes issues [#2712](https://github.com/naturalcrit/homebrewery/issues/2712)
##### MichielDeMey
* [x] Remove all-caps display on Account button since usernames are case-sensitive.
Fixes issues [#2731](https://github.com/naturalcrit/homebrewery/issues/2731)
}}
\page
### Monday 13/03/2023 - v3.7.2
{{taskList
##### Calculuschild
* [x] Fix wide Monster Stat Blocks not spanning columns on Legacy
}}
### Thursday 09/03/2023 - v3.7.1
{{taskList
##### Lucastucious (new contributor!)
* [x] Changed `filter: drop-shadow` to `box-shadow` on text boxes, making PDF text selectable
Fixes issues [#1569](https://github.com/naturalcrit/homebrewery/issues/1569)
{{note
**NOTE:** If you create your PDF on a computer with an old version of Mac Preview (v10 or older) you may see shadows appear as solid gray.
}}
##### MichielDeMey
* [x] Updated the Google Drive icon
* [x] Backend fix to unit tests failing intermittently
##### Calculuschild
* [x] Fix PDF pixelation on CoverPage text outlines
}}
### Tuesday 28/02/2023 - v3.7.0
{{taskList
{{note
**NOTE:** Some new snippets will now show a {{beta BETA}} tag. Feel free to use them, but be aware we may change how they work depending on your feedback.
}}
##### Calculuschild
* [x] New {{openSans **IMAGES → WATERCOLOR EDGE** {{fac,mask-edge}} }} and {{openSans **WATERCOLOR CORNER** {{fac,mask-corner}} }} snippets for V3, which adds a stylish watercolor texture to the edge of your images! (Thanks to /u/flamableconcrete on Reddit for providing these image masks!)
* [x] Fix site not displaying on iOS devices
##### 5e-Cleric
* [x] New {{openSans **PHB → COVER PAGE** {{fac,book-front-cover}} }} snippet for V3, which adds a stylish coverpage to your brew! (Thanks to /u/Kaiburr_Kath-Hound on Reddit for providing some of these resources!)
##### MichielDeMey (new contribuor!)
* [x] Fix typo in testing scripts
* [x] Fix "mug" image not using HTTPS
Fixes issues [#2687](https://github.com/naturalcrit/homebrewery/issues/2687)
}}
### Saturday 18/02/2023 - v3.6.1
{{taskList
##### G-Ambatte
* [x] Fix users not being removed from Authors list
Fixes issues [#2674](https://github.com/naturalcrit/homebrewery/issues/2674)
}}
### Monday 23/01/2023 - v3.6.0
{{taskList
##### calculuschild
* [x] Fix Google Drive brews sometimes duplicating
Fixes issues [#2603](https://github.com/naturalcrit/homebrewery/issues/2603)
##### Jeddai
* [x] Add unit tests with full coverage for the Homebrewery API
* [x] Add message to refresh the browser if the user is missing an update to the Homebrewery
Fixes issues [#2583](https://github.com/naturalcrit/homebrewery/issues/2583)
##### G-Ambatte
* [x] Auto-compile Themes CSS on development server
##### 5e-Cleric
* [x] Fix cloned brews inheriting the parent view count
}}
\page
### Friday 23/12/2022 - v3.5.0
{{taskList
@@ -70,24 +282,6 @@ For a full record of development, visit our [Github Page](https://github.com/nat
Fixes issues [#1987](https://github.com/naturalcrit/homebrewery/issues/1987)
}}
\page
### Monday 05/12/2022 - v3.4.1
{{taskList
##### G-Ambatte
* [x] Fix Account page incorrect last login time
Fixes issues [#2521](https://github.com/naturalcrit/homebrewery/issues/2521)
##### Gazook
* [x] Fix crashing on iOS and Safari browsers
Fixes issues [#2531](https://github.com/naturalcrit/homebrewery/issues/2531)
}}
### Saturday 10/12/2022 - v3.4.2
{{taskList

View File

@@ -0,0 +1,129 @@
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
require('./combobox.less');
const Combobox = createClass({
displayName : 'Combobox',
getDefaultProps : function() {
return {
className : '',
trigger : 'hover',
default : '',
placeholder : '',
autoSuggest : {
clearAutoSuggestOnClick : true,
suggestMethod : 'includes',
filterOn : [] // should allow as array to filter on multiple attributes, or even custom filter
},
};
},
getInitialState : function() {
return {
showDropdown : false,
value : '',
options : [...this.props.options],
inputFocused : false
};
},
componentDidMount : function() {
if(this.props.trigger == 'click')
document.addEventListener('click', this.handleClickOutside);
this.setState({
value : this.props.default
});
},
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,
inputFocused : this.props.autoSuggest.clearAutoSuggestOnClick ? show : false
});
},
handleInput : function(e){
e.persist();
this.setState({
value : e.target.value,
inputFocused : false
}, ()=>{
this.props.onEntry(e);
});
},
handleSelect : function(e){
this.setState({
value : e.currentTarget.getAttribute('data-value')
}, ()=>{this.props.onSelect(this.state.value);});
;
},
renderTextInput : function(){
return (
<div className='dropdown-input item'
onMouseEnter={this.props.trigger == 'hover' ? ()=>{this.handleDropdown(true);} : undefined}
onClick= {this.props.trigger == 'click' ? ()=>{this.handleDropdown(true);} : undefined}>
<input
type='text'
onChange={(e)=>this.handleInput(e)}
value={this.state.value || ''}
placeholder={this.props.placeholder}
onBlur={(e)=>{
if(!e.target.checkValidity()){
this.setState({
value : this.props.default
}, ()=>this.props.onEntry(e));
}
}}
/>
</div>
);
},
renderDropdown : function(dropdownChildren){
if(!this.state.showDropdown) return null;
if(this.props.autoSuggest && !this.state.inputFocused){
const suggestMethod = this.props.autoSuggest.suggestMethod;
const filterOn = _.isString(this.props.autoSuggest.filterOn) ? [this.props.autoSuggest.filterOn] : this.props.autoSuggest.filterOn;
const filteredArrays = filterOn.map((attr)=>{
const children = dropdownChildren.filter((item)=>{
if(suggestMethod === 'includes'){
return item.props[attr]?.toLowerCase().includes(this.state.value.toLowerCase());
} else if(suggestMethod === 'startsWith'){
return item.props[attr]?.toLowerCase().startsWith(this.state.value.toLowerCase());
}
});
return children;
});
dropdownChildren = _.uniq(filteredArrays.flat(1));
}
return (
<div className='dropdown-options'>
{dropdownChildren}
</div>
);
},
render : function () {
const dropdownChildren = this.state.options.map((child, i)=>{
const clone = React.cloneElement(child, { onClick: (e)=>this.handleSelect(e) });
return clone;
});
return (
<div className={`dropdown-container ${this.props.className}`}
ref='dropdown'
onMouseLeave={this.props.trigger == 'hover' ? ()=>{this.handleDropdown(false);} : undefined}>
{this.renderTextInput()}
{this.renderDropdown(dropdownChildren)}
</div>
);
}
});
module.exports = Combobox;

View File

@@ -0,0 +1,50 @@
.dropdown-container {
position:relative;
input {
width: 100%;
}
.dropdown-options {
position:absolute;
background-color: white;
z-index: 100;
width: 100%;
border: 1px solid gray;
overflow-y: auto;
max-height: 200px;
&::-webkit-scrollbar {
width: 14px;
}
&::-webkit-scrollbar-track {
background: #ffffff;
}
&::-webkit-scrollbar-thumb {
background-color: #949494;
border-radius: 10px;
border: 3px solid #ffffff;
}
.item {
position:relative;
font-size: 11px;
font-family: Open Sans;
padding: 5px;
cursor: default;
margin: 0 3px;
//border-bottom: 1px solid darkgray;
&:hover {
filter: brightness(120%);
background-color: rgb(163, 163, 163);
}
.detail {
width:100%;
text-align: left;
color: rgb(124, 124, 124);
font-style:italic;
font-size: 9px;
}
}
}
}

View File

@@ -27,6 +27,7 @@ const BrewRenderer = createClass({
style : '',
renderer : 'legacy',
theme : '5ePHB',
lang : '',
errors : []
};
},
@@ -134,7 +135,8 @@ const BrewRenderer = createClass({
renderStyle : function() {
if(!this.props.style) return;
return <div style={{ display: 'none' }} dangerouslySetInnerHTML={{ __html: `<style> ${this.props.style} </style>` }} />;
//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>` }} />;
},
renderPage : function(pageText, index){
@@ -189,7 +191,6 @@ const BrewRenderer = createClass({
const rendererPath = this.props.renderer == 'V3' ? 'V3' : 'Legacy';
const themePath = this.props.theme ?? '5ePHB';
const baseThemePath = Themes[rendererPath][themePath].baseTheme;
return (
<React.Fragment>
{!this.state.isMounted
@@ -222,7 +223,7 @@ const BrewRenderer = createClass({
&&
<>
{this.renderStyle()}
<div className='pages' ref='pages'>
<div className='pages' ref='pages' lang={`${this.props.lang || 'en'}`}>
{this.renderPages()}
</div>
</>

View File

@@ -4,7 +4,7 @@ const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames'); //Unused variable
const DISMISS_KEY = 'dismiss_notification08-27-22';
const DISMISS_KEY = 'dismiss_notification12-04-23';
const NotificationPopup = createClass({
displayName : 'NotificationPopup',
@@ -25,21 +25,13 @@ const NotificationPopup = createClass({
return (
<>
<li key='psa'>
<em>V3.2.0 Released!</em> <br />
We are happy to announce that after nearly a year of use by our many users,
we are making the V3 render mode the default setting for all new brews.
This mode has become quite popular, and has proven to be stable and powerful.
Of course, we will always keep the option to use the Legacy renderer for any
brew, which can still be accessed from the Properties menu.
</li>
<li key='stubs'>
<em>Change to Google Drive Storage!</em> <br />
We have made a change to the process of tranferring brews between Google
Drive and the Homebrewery storage. Starting now, any time a brew is
transferred, it will keep the same links instead of generating new ones!
We hope this change will help reduce issues where people "lost" their work
by trying to visit old links.
<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

@@ -32,6 +32,7 @@ const Editor = createClass({
onTextChange : ()=>{},
onStyleChange : ()=>{},
onMetaChange : ()=>{},
reportError : ()=>{},
renderer : 'legacy'
};
@@ -291,7 +292,8 @@ const Editor = createClass({
rerenderParent={this.rerenderParent} />
<MetadataEditor
metadata={this.props.brew}
onChange={this.props.onMetaChange} />
onChange={this.props.onMetaChange}
reportError={this.props.reportError}/>
</>;
}
},

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

@@ -4,8 +4,9 @@ const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
const request = require('superagent');
const request = require('../../utils/request-middleware.js');
const Nav = require('naturalcrit/nav/nav.jsx');
const Combobox = require('client/components/combobox.jsx');
const StringArrayEditor = require('../stringArrayEditor/stringArrayEditor.jsx');
const Themes = require('themes/themes.json');
@@ -35,9 +36,11 @@ const MetadataEditor = createClass({
authors : [],
systems : [],
renderer : 'legacy',
theme : '5ePHB'
theme : '5ePHB',
lang : 'en'
},
onChange : ()=>{}
onChange : ()=>{},
reportError : ()=>{}
};
},
@@ -75,6 +78,7 @@ const MetadataEditor = createClass({
const errMessage = validationErr.map((err)=>{
return `- ${err}`;
}).join('\n');
callIfExists(e.target, 'setCustomValidity', errMessage);
callIfExists(e.target, 'reportValidity');
}
@@ -110,6 +114,11 @@ const MetadataEditor = createClass({
this.props.onChange(this.props.metadata);
},
handleLanguage : function(languageCode){
this.props.metadata.lang = languageCode;
this.props.onChange(this.props.metadata);
},
handleDelete : function(){
if(this.props.metadata.authors && this.props.metadata.authors.length <= 1){
if(!confirm('Are you sure you want to delete this brew? Because you are the only owner of this brew, the document will be deleted permanently.')) return;
@@ -121,8 +130,12 @@ const MetadataEditor = createClass({
request.delete(`/api/${this.props.metadata.googleId ?? ''}${this.props.metadata.editId}`)
.send()
.end(function(err, res){
window.location.href = '/';
.end((err, res)=>{
if(err) {
this.props.reportError(err);
} else {
window.location.href = '/';
}
});
},
@@ -184,6 +197,10 @@ const MetadataEditor = createClass({
return <div className='item' key={''} onClick={()=>this.handleTheme(theme)} title={''}>
{`${theme.renderer} : ${theme.name}`}
<img src={`/themes/${theme.renderer}/${theme.path}/dropdownTexture.png`}/>
<div className='preview'>
<h6>{`${theme.name}`} preview</h6>
<img src={`/themes/${theme.renderer}/${theme.path}/dropdownPreview.png`}/>
</div>
</div>;
});
};
@@ -193,14 +210,14 @@ const MetadataEditor = createClass({
if(this.props.metadata.renderer == 'legacy') {
dropdown =
<Nav.dropdown className='disabled' trigger='disabled'>
<Nav.dropdown className='disabled value' trigger='disabled'>
<div>
{`Themes are not supported in the Legacy Renderer`} <i className='fas fa-caret-down'></i>
</div>
</Nav.dropdown>;
} else {
dropdown =
<Nav.dropdown trigger='click'>
<Nav.dropdown className='value' trigger='click'>
<div>
{`${_.upperFirst(currentTheme.renderer)} : ${currentTheme.name}`} <i className='fas fa-caret-down'></i>
</div>
@@ -215,6 +232,47 @@ const MetadataEditor = createClass({
</div>;
},
renderLanguageDropdown : function(){
const langCodes = ['en', 'de', 'de-ch', 'fr', 'ja', 'es', 'it', 'sv', 'ru', 'zh-Hans', 'zh-Hant'];
const listLanguages = ()=>{
return _.map(langCodes.sort(), (code, index)=>{
const localName = new Intl.DisplayNames([code], { type: 'language' });
const englishName = new Intl.DisplayNames('en', { type: 'language' });
return <div className='item' title={`${englishName.of(code)}`} key={`${index}`} data-value={`${code}`} data-detail={`${localName.of(code)}`}>
{`${code}`}
<div className='detail'>{`${localName.of(code)}`}</div>
</div>;
});
};
const debouncedHandleFieldChange = _.debounce(this.handleFieldChange, 500);
return <div className='field language'>
<label>language</label>
<div className='value'>
<Combobox trigger='click'
className='language-dropdown'
default={this.props.metadata.lang || ''}
placeholder='en'
onSelect={(value)=>this.handleLanguage(value)}
onEntry={(e)=>{
e.target.setCustomValidity(''); //Clear the validation popup while typing
debouncedHandleFieldChange('lang', e);
}}
options={listLanguages()}
autoSuggest={{
suggestMethod : 'startsWith',
clearAutoSuggestOnClick : true,
filterOn : ['data-value', 'data-detail', 'title']
}}
>
</Combobox>
<small>Sets the HTML Lang property for your brew. May affect hyphenation or spellcheck.</small>
</div>
</div>;
},
renderRenderOptions : function(){
if(!global.enable_v3) return;
@@ -292,6 +350,8 @@ const MetadataEditor = createClass({
</div>
</div>
{this.renderLanguageDropdown()}
{this.renderThemeDropdown()}
{this.renderRenderOptions()}
@@ -303,10 +363,10 @@ const MetadataEditor = createClass({
{this.renderAuthors()}
<StringArrayEditor label='invited authors' valuePatterns={[/.+/]}
validators={[(v)=>!this.props.metadata.authors.includes(v)]}
validators={[(v)=>!this.props.metadata.authors?.includes(v)]}
placeholder='invite author' unique={true}
values={this.props.metadata.invitedAuthors}
notes={['Invited authors are case sensitive.', 'After adding an invited author, send them the edit link. There, they can choose to accept or decline the invitation.']}
notes={['Invited author usernames are case sensitive.', 'After adding an invited author, send them the edit link. There, they can choose to accept or decline the invitation.']}
onChange={(e)=>this.handleFieldChange('invitedAuthors', e)}/>
<hr/>

View File

@@ -35,13 +35,16 @@
flex-direction: column;
flex: 5 0 200px;
gap: 10px;
}
.field{
display : flex;
flex-wrap : wrap;
width : 100%;
min-width : 200px;
position : relative;
&>label{
width : 80px;
font-size : 11px;
@@ -58,6 +61,9 @@
}
input[type='text'], textarea {
border : 1px solid gray;
&:focus {
outline: 1px solid #444;
}
}
&.thumbnail{
height : 1.4em;
@@ -89,9 +95,15 @@
}
}
&.language .language-dropdown {
max-width : 150px;
z-index : 200;
}
small {
font-size : 0.6em;
font-style : italic;
font-size : 0.6em;
font-style : italic;
line-height : 1.4em;
display : inline-block;
}
}
@@ -159,9 +171,8 @@
font-size : 13.33px;
.navDropdownContainer {
background-color : white;
width : 100%;
position : relative;
z-index : 500;
z-index : 100;
&.disabled {
font-style :italic;
font-style : italic;
@@ -182,24 +193,51 @@
}
.navDropdown {
box-shadow : 0px 5px 10px rgba(0, 0, 0, 0.3);
position : absolute;
width : 100%;
position : absolute;
width : 100%;
.item {
padding : 3px 3px;
border-top : 1px solid rgb(118, 118, 118);
position : relative;
overflow : hidden;
padding : 3px 3px;
border-top : 1px solid rgb(118, 118, 118);
position : relative;
overflow : visible;
background-color : white;
.preview {
display : flex;
flex-direction: column;
background : #ccc;
border-radius : 5px;
box-shadow : 0 0 5px black;
width : 200px;
color :black;
position : absolute;
top : 0;
right : 0;
opacity : 0;
transition : opacity 250ms ease;
z-index : 1;
overflow :hidden;
h6 {
font-weight : 900;
padding-inline:1em;
padding-block :.5em;
border-bottom :2px solid hsl(0,0%,40%);
}
}
&:hover {
background-color : @blue;
color : white;
color : white;
}
img {
mask-image : linear-gradient(90deg, transparent, black 20%);
&:hover > .preview {
opacity: 1;
}
>img {
mask-image : linear-gradient(90deg, transparent, black 20%);
-webkit-mask-image : linear-gradient(90deg, transparent, black 20%);
position : absolute;
left : ~"max(100px, 100% - 300px)";
top : 0px;
position : absolute;
right : 0;
top : 0px;
width : 50%;
height : 100%;
}
}
}

View File

@@ -23,9 +23,9 @@ module.exports = {
}
}
],
language : [
lang : [
(value)=>{
return new RegExp(/[a-z]{2,3}(-.*)?/).test(value || '') === false ? 'Invalid language code.' : null;
return new RegExp(/^([a-zA-Z]{2,3})(-[a-zA-Z]{4})?(-(?:[0-9]{3}|[a-zA-Z]{2}))?$/).test(value) === false && (value.length > 0) ? 'Invalid language code.' : null;
}
]
};

View File

@@ -163,15 +163,23 @@ const SnippetGroup = createClass({
onSnippetClick : function(){},
};
},
handleSnippetClick : function(snippet){
handleSnippetClick : function(e, snippet){
e.stopPropagation();
this.props.onSnippetClick(execute(snippet.gen, this.props.brew));
},
renderSnippets : function(){
return _.map(this.props.snippets, (snippet)=>{
return <div className='snippet' key={snippet.name} onClick={()=>this.handleSnippetClick(snippet)}>
renderSnippets : function(snippets){
return _.map(snippets, (snippet)=>{
return <div className='snippet' key={snippet.name} onClick={(e)=>this.handleSnippetClick(e, snippet)}>
<i className={snippet.icon} />
{snippet.name}
<span className='name'>{snippet.name}</span>
{snippet.experimental && <span className='beta'>beta</span>}
{snippet.subsnippets && <>
<i className='fas fa-caret-right'></i>
<div className='dropdown side'>
{this.renderSnippets(snippet.subsnippets)}
</div></>}
</div>;
});
},
@@ -182,7 +190,7 @@ const SnippetGroup = createClass({
<span className='groupName'>{this.props.groupName}</span>
</div>
<div className='dropdown'>
{this.renderSnippets()}
{this.renderSnippets(this.props.snippets)}
</div>
</div>;
},

View File

@@ -1,4 +1,4 @@
@import (less) './client/icons/customIcons.less';
.snippetBar{
@menuHeight : 25px;
position : relative;
@@ -83,7 +83,7 @@
.snippetGroup{
border-right : 1px solid black;
&:hover{
.dropdown{
&>.dropdown{
visibility : visible;
}
}
@@ -96,16 +96,47 @@
padding : 0px;
background-color : #ddd;
.snippet{
position: relative;
.animate(background-color);
padding : 5px;
cursor : pointer;
font-size : 10px;
display : flex;
align-items : center;
min-width : max-content;
padding : 5px;
cursor : pointer;
font-size : 10px;
i{
margin-right : 8px;
font-size : 1.2em;
height : 1.2em;
&~i{
margin-right: 0;
margin-left: 5px;
}
}
.name {
margin-right : auto;
}
.beta {
color : white;
padding : 4px 6px;
line-height : 1em;
margin-left : 5px;
align-self : center;
background : grey;
border-radius : 12px;
font-family : monospace;
}
&:hover{
background-color : #999;
&>.dropdown{
visibility : visible;
&.side {
left: 100%;
top: 0%;
margin-left:0;
box-shadow: -1px 1px 2px 0px #999;
}
}
}
}
}

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>;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 305 KiB

View File

@@ -0,0 +1,8 @@
<svg viewBox="0 0 87.3 78" xmlns="http://www.w3.org/2000/svg">
<path d="m6.6 66.85 3.85 6.65c.8 1.4 1.95 2.5 3.3 3.3l13.75-23.8h-27.5c0 1.55.4 3.1 1.2 4.5z" fill="#0066da"/>
<path d="m43.65 25-13.75-23.8c-1.35.8-2.5 1.9-3.3 3.3l-25.4 44a9.06 9.06 0 0 0 -1.2 4.5h27.5z" fill="#00ac47"/>
<path d="m73.55 76.8c1.35-.8 2.5-1.9 3.3-3.3l1.6-2.75 7.65-13.25c.8-1.4 1.2-2.95 1.2-4.5h-27.502l5.852 11.5z" fill="#ea4335"/>
<path d="m43.65 25 13.75-23.8c-1.35-.8-2.9-1.2-4.5-1.2h-18.5c-1.6 0-3.15.45-4.5 1.2z" fill="#00832d"/>
<path d="m59.8 53h-32.3l-13.75 23.8c1.35.8 2.9 1.2 4.5 1.2h50.8c1.6 0 3.15-.45 4.5-1.2z" fill="#2684fc"/>
<path d="m73.4 26.5-12.7-22c-.8-1.4-1.95-2.5-3.3-3.3l-13.75 23.8 16.15 28h27.45c0-1.55-.4-3.1-1.2-4.5z" fill="#ffba00"/>
</svg>

After

Width:  |  Height:  |  Size: 755 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -47,6 +47,7 @@ const Homebrew = createClass({
editId : null,
createdAt : null,
updatedAt : null,
lang : ''
}
};
},

View File

@@ -63,7 +63,7 @@ const Account = createClass({
if(global.account){
return <Nav.dropdown>
<Nav.item
className='account'
className='account username'
color='orange'
icon='fas fa-user'
>

View File

@@ -0,0 +1,85 @@
require('./error-navitem.less');
const React = require('react');
const Nav = require('naturalcrit/nav/nav.jsx');
const createClass = require('create-react-class');
const ErrorNavItem = createClass({
getDefaultProps : function() {
return {
error : '',
parent : null
};
},
render : function() {
const clearError = ()=>{
const state = {
error : null
};
if(this.props.parent.state.isSaving) {
state.isSaving = false;
}
this.props.parent.setState(state);
};
const error = this.props.error;
const response = error.response;
const status = response.status;
const message = response.body?.message;
let errMsg = '';
try {
errMsg += `${error.toString()}\n\n`;
errMsg += `\`\`\`\n${error.stack}\n`;
errMsg += `${JSON.stringify(response.error, null, ' ')}\n\`\`\``;
console.log(errMsg);
} catch (e){}
if(status === 409) {
return <Nav.item className='save error' icon='fas fa-exclamation-triangle'>
Oops!
<div className='errorContainer' onClick={clearError}>
{message ?? 'Conflict: please refresh to get latest changes'}
</div>
</Nav.item>;
} else if(status === 412) {
return <Nav.item className='save error' icon='fas fa-exclamation-triangle'>
Oops!
<div className='errorContainer' onClick={clearError}>
{message ?? 'Your client is out of date. Please save your changes elsewhere and refresh.'}
</div>
</Nav.item>;
}
if(response.req.url.match(/^\/api.*Google.*$/m)){
return <Nav.item className='save error' icon='fas fa-exclamation-triangle'>
Oops!
<div className='errorContainer' onClick={clearError}>
Looks like your Google credentials have
expired! Visit our log in page to sign out
and sign back in with Google,
then try saving again!
<a target='_blank' rel='noopener noreferrer'
href={`https://www.naturalcrit.com/login?redirect=${window.location.href}`}>
<div className='confirm'>
Sign In
</div>
</a>
<div className='deny'>
Not Now
</div>
</div>
</Nav.item>;
}
return <Nav.item className='save error' icon='fas fa-exclamation-triangle'>
Oops!
<div className='errorContainer'>
Looks like there was a problem saving. <br />
Report the issue <a target='_blank' rel='noopener noreferrer' href={`https://github.com/naturalcrit/homebrewery/issues/new?template=save_issue.yml&error-code=${encodeURIComponent(errMsg)}`}>
here
</a>.
</div>
</Nav.item>;
}
});
module.exports = ErrorNavItem;

View File

@@ -0,0 +1,75 @@
.navItem.error {
position : relative;
background-color : @red;
}
.errorContainer{
animation-name: glideDown;
animation-duration: 0.4s;
position : absolute;
top : 100%;
left : 50%;
z-index : 1000;
width : 140px;
padding : 3px;
color : white;
background-color : #333;
border : 3px solid #444;
border-radius : 5px;
transform : translate(-50% + 3px, 10px);
text-align : center;
font-size : 10px;
font-weight : 800;
text-transform : uppercase;
a{
color : @teal;
}
&:before {
content: "";
width: 0px;
height: 0px;
position: absolute;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 10px solid transparent;
border-bottom: 10px solid #444;
left: 53px;
top: -23px;
}
&:after {
content: "";
width: 0px;
height: 0px;
position: absolute;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 10px solid transparent;
border-bottom: 10px solid #333;
left: 53px;
top: -19px;
}
.deny {
width : 48%;
margin : 1px;
padding : 5px;
background-color : #333;
display : inline-block;
border-left : 1px solid #666;
.animate(background-color);
&:hover{
background-color : red;
}
}
.confirm {
width : 48%;
margin : 1px;
padding : 5px;
background-color : #333;
display : inline-block;
color : white;
.animate(background-color);
&:hover{
background-color : teal;
}
}
}

View File

@@ -0,0 +1,90 @@
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const Moment = require('moment');
const Nav = require('naturalcrit/nav/nav.jsx');
const MetadataNav = createClass({
displayName : 'MetadataNav',
getDefaultProps : function() {
return {
};
},
getInitialState : function() {
return {
showMetaWindow : false
};
},
componentDidMount : function() {
},
toggleMetaWindow : function(){
this.setState((prevProps)=>({
showMetaWindow : !prevProps.showMetaWindow
}));
},
getAuthors : function(){
if(!this.props.brew.authors || this.props.brew.authors.length == 0) return 'No authors';
return <>
{this.props.brew.authors.map((author, idx, arr)=>{
const spacer = arr.length - 1 == idx ? <></> : <span>, </span>;
return <span key={idx}><a className='userPageLink' href={`/user/${author}`}>{author}</a>{spacer}</span>;
})}
</>;
},
getTags : function(){
if(!this.props.brew.tags || this.props.brew.tags.length == 0) return 'No tags';
return <>
{this.props.brew.tags.map((tag, idx)=>{
return <span className='tag' key={idx}>{tag}</span>;
})}
</>;
},
getSystems : function(){
if(!this.props.brew.systems || this.props.brew.systems.length == 0) return 'No systems';
return this.props.brew.systems.join(', ');
},
renderMetaWindow : function(){
return <div className={`window ${this.state.showMetaWindow ? 'active' : 'inactive'}`}>
<div className='row'>
<h4>Description</h4>
<p>{this.props.brew.description || 'No description.'}</p>
</div>
<div className='row'>
<h4>Authors</h4>
<p>{this.getAuthors()}</p>
</div>
<div className='row'>
<h4>Tags</h4>
<p>{this.getTags()}</p>
</div>
<div className='row'>
<h4>Systems</h4>
<p>{this.getSystems()}</p>
</div>
<div className='row'>
<h4>Updated</h4>
<p>{Moment(this.props.brew.updatedAt).fromNow()}</p>
</div>
</div>;
},
render : function(){
return <Nav.item icon='fas fa-info-circle' color='grey' className='metadata'
onClick={()=>this.toggleMetaWindow()}>
{this.props.children}
{this.renderMetaWindow()}
</Nav.item>;
}
});
module.exports = MetadataNav;

View File

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

View File

@@ -4,9 +4,9 @@ const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
const moment = require('moment');
const request = require('superagent');
const request = require('../../../../utils/request-middleware.js');
const googleDriveIcon = require('../../../../googleDrive.png');
const googleDriveIcon = require('../../../../googleDrive.svg');
const dedent = require('dedent-tabs').default;
const BrewItem = createClass({
@@ -18,7 +18,8 @@ const BrewItem = createClass({
description : '',
authors : [],
stubbed : true
}
},
reportError : ()=>{}
};
},
@@ -33,8 +34,12 @@ const BrewItem = createClass({
request.delete(`/api/${this.props.brew.googleId ?? ''}${this.props.brew.editId}`)
.send()
.end(function(err, res){
location.reload();
.end((err, res)=>{
if(err) {
this.props.reportError(err);
} else {
location.reload();
}
});
},

View File

@@ -94,7 +94,7 @@
}
}
.googleDriveIcon {
height : 20px;
height : 18px;
padding : 0px;
margin : -5px;
}

View File

@@ -23,7 +23,8 @@ const ListPage = createClass({
brews : []
}
],
navItems : <></>
navItems : <></>,
reportError : null
};
},
getInitialState : function() {
@@ -81,7 +82,7 @@ const ListPage = createClass({
if(!brews || !brews.length) return <div className='noBrews'>No Brews.</div>;
return _.map(brews, (brew, idx)=>{
return <BrewItem brew={brew} key={idx}/>;
return <BrewItem brew={brew} key={idx} reportError={this.props.reportError}/>;
});
},
@@ -218,12 +219,13 @@ const ListPage = createClass({
render : function(){
return <div className='listPage sitePage'>
{/*<style>@layer V3_5ePHB, bundle;</style>*/}
<link href='/themes/V3/5ePHB/style.css' rel='stylesheet'/>
{this.props.navItems}
{this.renderSortOptions()}
<div className='content V3'>
<div className='phb page'>
<div className='page'>
{this.renderBrewCollection(this.state.brewCollection)}
</div>
</div>

View File

@@ -10,14 +10,15 @@
-moz-column-width : auto;
-webkit-column-gap : auto;
-moz-column-gap : auto;
height : auto;
min-height : 279.4mm;
margin : 20px auto;
}
.listPage{
.content{
.phb{
.noColumns();
height : auto;
min-height : 279.4mm;
margin : 20px auto;
z-index : 1;
.page{
.noColumns() !important; //Needed to override PHB Theme since this is on a lower @layer
&::after{
display : none;
}
@@ -63,7 +64,7 @@
border-bottom : 1px solid #666;
color : white;
text-align : center;
z-index : 500;
z-index : 1;
display : flex;
justify-content : center;
align-items : baseline;

View File

@@ -3,7 +3,7 @@ require('./editPage.less');
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const request = require('superagent');
const request = require('../../utils/request-middleware.js');
const { Meta } = require('vitreum/headtags');
const Nav = require('naturalcrit/nav/nav.jsx');
@@ -12,6 +12,7 @@ const Navbar = require('../../navbar/navbar.jsx');
const NewBrew = require('../../navbar/newbrew.navitem.jsx');
const HelpNavItem = require('../../navbar/help.navitem.jsx');
const PrintLink = require('../../navbar/print.navitem.jsx');
const ErrorNavItem = require('../../navbar/error-navitem.jsx');
const Account = require('../../navbar/account.navitem.jsx');
const RecentNavItem = require('../../navbar/recent.navitem.jsx').both;
@@ -21,8 +22,9 @@ const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
const Markdown = require('naturalcrit/markdown.js');
const googleDriveActive = require('../../googleDrive.png');
const googleDriveInactive = require('../../googleDriveMono.png');
const { DEFAULT_BREW_LOAD } = require('../../../../server/brewDefaults.js');
const googleDriveIcon = require('../../googleDrive.svg');
const SAVE_TIMEOUT = 3000;
@@ -30,24 +32,7 @@ const EditPage = createClass({
displayName : 'EditPage',
getDefaultProps : function() {
return {
brew : {
text : '',
style : '',
shareId : null,
editId : null,
createdAt : null,
updatedAt : null,
gDrive : false,
trashed : false,
title : '',
description : '',
tags : '',
published : false,
authors : [],
systems : [],
renderer : 'legacy'
}
brew : DEFAULT_BREW_LOAD
};
},
@@ -60,7 +45,7 @@ const EditPage = createClass({
alertLoginToTransfer : false,
saveGoogle : this.props.brew.googleId ? true : false,
confirmGoogleTransfer : false,
errors : null,
error : null,
htmlErrors : Markdown.validate(this.props.brew.text),
url : '',
autoSave : true,
@@ -75,7 +60,6 @@ const EditPage = createClass({
url : window.location.href
});
this.savedBrew = JSON.parse(JSON.stringify(this.props.brew)); //Deep copy
this.setState({ autoSave: JSON.parse(localStorage.getItem('AUTOSAVE_ON')) ?? true }, ()=>{
@@ -172,7 +156,10 @@ const EditPage = createClass({
this.setState((prevState)=>({
confirmGoogleTransfer : !prevState.confirmGoogleTransfer
}));
this.clearErrors();
this.setState({
error : null,
isSaving : false
});
},
closeAlerts : function(event){
@@ -188,24 +175,16 @@ const EditPage = createClass({
this.setState((prevState)=>({
saveGoogle : !prevState.saveGoogle,
isSaving : false,
errors : null
error : null
}), ()=>this.save());
},
clearErrors : function(){
this.setState({
errors : null,
isSaving : false
});
},
save : async function(){
if(this.debounceSave && this.debounceSave.cancel) this.debounceSave.cancel();
this.setState((prevState)=>({
isSaving : true,
errors : null,
error : null,
htmlErrors : Markdown.validate(prevState.brew.text)
}));
@@ -220,8 +199,9 @@ const EditPage = createClass({
.send(brew)
.catch((err)=>{
console.log('Error Updating Local Brew');
this.setState({ errors: err });
this.setState({ error: err });
});
if(!res) return;
this.savedBrew = res.body;
history.replaceState(null, null, `/edit/${this.savedBrew.editId}`);
@@ -241,10 +221,7 @@ const EditPage = createClass({
renderGoogleDriveIcon : function(){
return <Nav.item className='googleDriveStorage' onClick={this.handleGoogleClick}>
{this.state.saveGoogle
? <img src={googleDriveActive} alt='googleDriveActive'/>
: <img src={googleDriveInactive} alt='googleDriveInactive'/>
}
<img src={googleDriveIcon} className={this.state.saveGoogle ? '' : 'inactive'} alt='Google Drive icon'/>
{this.state.confirmGoogleTransfer &&
<div className='errorContainer' onClick={this.closeAlerts}>
@@ -277,81 +254,19 @@ const EditPage = createClass({
</div>
</div>
}
{this.state.alertTrashedGoogleBrew &&
<div className='errorContainer' onClick={this.closeAlerts}>
This brew is currently in your Trash folder on Google Drive!<br />If you want to keep it, make sure to move it before it is deleted permanently!<br />
<div className='confirm'>
OK
</div>
</div>
}
</Nav.item>;
},
renderSaveButton : function(){
if(this.state.errors){
let errMsg = '';
try {
errMsg += `${this.state.errors.toString()}\n\n`;
errMsg += `\`\`\`\n${this.state.errors.stack}\n`;
errMsg += `${JSON.stringify(this.state.errors.response.error, null, ' ')}\n\`\`\``;
console.log(errMsg);
} catch (e){}
// if(this.state.errors.status == '401'){
// return <Nav.item className='save error' icon='fas fa-exclamation-triangle'>
// Oops!
// <div className='errorContainer' onClick={this.clearErrors}>
// You must be signed in to a Google account
// to save this to<br />Google Drive!<br />
// <a target='_blank' rel='noopener noreferrer'
// href={`https://www.naturalcrit.com/login?redirect=${this.state.url}`}>
// <div className='confirm'>
// Sign In
// </div>
// </a>
// <div className='deny'>
// Not Now
// </div>
// </div>
// </Nav.item>;
// }
if(this.state.errors.response.req.url.match(/^\/api.*Google.*$/m)){
return <Nav.item className='save error' icon='fas fa-exclamation-triangle'>
Oops!
<div className='errorContainer' onClick={this.clearErrors}>
Looks like your Google credentials have
expired! Visit our log in page to sign out
and sign back in with Google,
then try saving again!
<a target='_blank' rel='noopener noreferrer'
href={`https://www.naturalcrit.com/login?redirect=${this.state.url}`}>
<div className='confirm'>
Sign In
</div>
</a>
<div className='deny'>
Not Now
</div>
</div>
</Nav.item>;
}
if(this.state.errors.response.error.status === 409) {
const message = this.state.errors.response.body?.message;
return <Nav.item className='save error' icon='fas fa-exclamation-triangle'>
Oops!
<div className='errorContainer'>
{message ? message : 'Conflict: please refresh to get latest changes'}
</div>
</Nav.item>;
}
return <Nav.item className='save error' icon='fas fa-exclamation-triangle'>
Oops!
<div className='errorContainer'>
Looks like there was a problem saving. <br />
Report the issue <a target='_blank' rel='noopener noreferrer'
href={`https://github.com/naturalcrit/homebrewery/issues/new?template=save_issue.yml&error-code=${encodeURIComponent(errMsg)}`}>
here
</a>.
</div>
</Nav.item>;
}
if(this.state.autoSaveWarning && this.hasChanges()){
this.setAutosaveWarning();
const elapsedTime = Math.round((new Date() - this.state.unsavedTime) / 1000 / 60);
@@ -395,6 +310,12 @@ const EditPage = createClass({
this.warningTimer;
},
errorReported : function(error) {
this.setState({
error
});
},
renderAutoSaveButton : function(){
return <Nav.item onClick={this.handleAutoSave}>
Autosave <i className={this.state.autoSave ? 'fas fa-power-off active' : 'fas fa-power-off'}></i>
@@ -423,26 +344,19 @@ const EditPage = createClass({
const shareLink = this.processShareId();
return <Navbar>
{this.state.alertTrashedGoogleBrew &&
<div className='errorContainer' onClick={this.closeAlerts}>
This brew is currently in your Trash folder on Google Drive!<br />If you want to keep it, make sure to move it before it is deleted permanently!<br />
<div className='confirm'>
OK
</div>
</div>
}
<Nav.section>
<Nav.item className='brewTitle'>{this.state.brew.title}</Nav.item>
</Nav.section>
<Nav.section>
{this.renderGoogleDriveIcon()}
<Nav.dropdown className='save-menu'>
{this.renderSaveButton()}
{this.renderAutoSaveButton()}
</Nav.dropdown>
{this.state.error ?
<ErrorNavItem error={this.state.error} parent={this}></ErrorNavItem> :
<Nav.dropdown className='save-menu'>
{this.renderSaveButton()}
{this.renderAutoSaveButton()}
</Nav.dropdown>
}
<NewBrew />
<HelpNavItem/>
<Nav.dropdown>
@@ -480,9 +394,17 @@ const EditPage = createClass({
onTextChange={this.handleTextChange}
onStyleChange={this.handleStyleChange}
onMetaChange={this.handleMetaChange}
reportError={this.errorReported}
renderer={this.state.brew.renderer}
/>
<BrewRenderer text={this.state.brew.text} style={this.state.brew.style} renderer={this.state.brew.renderer} theme={this.state.brew.theme} errors={this.state.htmlErrors} />
<BrewRenderer
text={this.state.brew.text}
style={this.state.brew.style}
renderer={this.state.brew.renderer}
theme={this.state.brew.theme}
errors={this.state.htmlErrors}
lang={this.state.brew.lang}
/>
</SplitPane>
</div>
</div>;

View File

@@ -13,87 +13,17 @@
cursor : initial;
color : #666;
}
&.error{
position : relative;
background-color : @red;
}
}
.googleDriveStorage {
position : relative;
}
.googleDriveStorage img{
height : 20px;
height : 18px;
padding : 0px;
margin : -5px;
}
.errorContainer{
animation-name: glideDown;
animation-duration: 0.4s;
position : absolute;
top : 100%;
left : 50%;
z-index : 500;
width : 140px;
padding : 3px;
color : white;
background-color : #333;
border : 3px solid #444;
border-radius : 5px;
transform : translate(-50% + 3px, 10px);
text-align : center;
font-size : 10px;
font-weight : 800;
text-transform : uppercase;
a{
color : @teal;
}
&:before {
content: "";
width: 0px;
height: 0px;
position: absolute;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 10px solid transparent;
border-bottom: 10px solid #444;
left: 53px;
top: -23px;
}
&:after {
content: "";
width: 0px;
height: 0px;
position: absolute;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 10px solid transparent;
border-bottom: 10px solid #333;
left: 53px;
top: -19px;
}
.deny {
width : 48%;
margin : 1px;
padding : 5px;
background-color : #333;
display : inline-block;
border-left : 1px solid #666;
.animate(background-color);
&:hover{
background-color : red;
}
}
.confirm {
width : 48%;
margin : 1px;
padding : 5px;
background-color : #333;
display : inline-block;
color : white;
.animate(background-color);
&:hover{
background-color : teal;
}
&.inactive {
filter: grayscale(1);
}
}
}

View File

@@ -3,7 +3,7 @@ const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
const request = require('superagent');
const request = require('../../utils/request-middleware.js');
const { Meta } = require('vitreum/headtags');
const Nav = require('naturalcrit/nav/nav.jsx');
@@ -12,35 +12,38 @@ const NewBrewItem = require('../../navbar/newbrew.navitem.jsx');
const HelpNavItem = require('../../navbar/help.navitem.jsx');
const RecentNavItem = require('../../navbar/recent.navitem.jsx').both;
const AccountNavItem = require('../../navbar/account.navitem.jsx');
const ErrorNavItem = require('../../navbar/error-navitem.jsx');
const SplitPane = require('naturalcrit/splitPane/splitPane.jsx');
const Editor = require('../../editor/editor.jsx');
const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
const { DEFAULT_BREW } = require('../../../../server/brewDefaults.js');
const HomePage = createClass({
displayName : 'HomePage',
getDefaultProps : function() {
return {
brew : {
text : '',
},
ver : '0.0.0'
brew : DEFAULT_BREW,
ver : '0.0.0'
};
},
getInitialState : function() {
return {
brew : this.props.brew,
welcomeText : this.props.brew.text
welcomeText : this.props.brew.text,
error : undefined
};
},
handleSave : function(){
request.post('/api')
.send(this.state.brew)
.end((err, res)=>{
if(err) return;
if(err) {
this.setState({ error: err });
return;
}
const brew = res.body;
window.location = `/edit/${brew.editId}`;
});
@@ -56,6 +59,10 @@ const HomePage = createClass({
renderNavbar : function(){
return <Navbar ver={this.props.ver}>
<Nav.section>
{this.state.error ?
<ErrorNavItem error={this.state.error} parent={this}></ErrorNavItem> :
null
}
<NewBrewItem />
<HelpNavItem />
<RecentNavItem />

View File

@@ -40,4 +40,11 @@
right : 350px;
}
}
.navItem.save{
background-color: @orange;
&:hover{
background-color: @green;
}
}
}

View File

@@ -36,7 +36,7 @@ After clicking the "Print" item in the navbar a new page will open and a print d
If you want to save ink or have a monochrome printer, add the **PRINT → {{fas,fa-tint}} Ink Friendly** snippet to your brew!
}}
![homebrew mug](http://i.imgur.com/hMna6G0.png) {position:absolute,bottom:20px,left:130px,width:220px}
![homebrew mug](https://i.imgur.com/hMna6G0.png) {position:absolute,bottom:20px,left:130px,width:220px}
{{artist,bottom:160px,left:100px
##### Homebrew Mug

View File

@@ -3,13 +3,14 @@ require('./newPage.less');
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const request = require('superagent');
const request = require('../../utils/request-middleware.js');
const Markdown = require('naturalcrit/markdown.js');
const Nav = require('naturalcrit/nav/nav.jsx');
const Navbar = require('../../navbar/navbar.jsx');
const AccountNavItem = require('../../navbar/account.navitem.jsx');
const ErrorNavItem = require('../../navbar/error-navitem.jsx');
const RecentNavItem = require('../../navbar/recent.navitem.jsx').both;
const HelpNavItem = require('../../navbar/help.navitem.jsx');
@@ -17,6 +18,8 @@ const SplitPane = require('naturalcrit/splitPane/splitPane.jsx');
const Editor = require('../../editor/editor.jsx');
const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
const { DEFAULT_BREW } = require('../../../../server/brewDefaults.js');
const BREWKEY = 'homebrewery-new';
const STYLEKEY = 'homebrewery-new-style';
const METAKEY = 'homebrewery-new-meta';
@@ -26,36 +29,18 @@ const NewPage = createClass({
displayName : 'NewPage',
getDefaultProps : function() {
return {
brew : {
text : '',
style : undefined,
title : '',
description : '',
renderer : 'V3',
theme : '5ePHB'
}
brew : DEFAULT_BREW
};
},
getInitialState : function() {
let brew = this.props.brew;
if(this.props.brew.shareId) {
brew = {
text : brew.text ?? '',
style : brew.style ?? undefined,
title : brew.title ?? '',
description : brew.description ?? '',
renderer : brew.renderer ?? 'legacy',
theme : brew.theme ?? '5ePHB'
};
}
const brew = this.props.brew;
return {
brew : brew,
isSaving : false,
saveGoogle : (global.account && global.account.googleId ? true : false),
errors : null,
error : null,
htmlErrors : Markdown.validate(brew.text)
};
},
@@ -76,6 +61,7 @@ const NewPage = createClass({
// brew.description = metaStorage?.description || this.state.brew.description;
brew.renderer = metaStorage?.renderer ?? brew.renderer;
brew.theme = metaStorage?.theme ?? brew.theme;
brew.lang = metaStorage?.lang ?? brew.lang;
this.setState({
brew : brew
@@ -83,8 +69,9 @@ const NewPage = createClass({
}
localStorage.setItem(BREWKEY, brew.text);
localStorage.setItem(STYLEKEY, brew.style);
localStorage.setItem(METAKEY, JSON.stringify({ 'renderer': brew.renderer, 'theme': brew.theme }));
if(brew.style)
localStorage.setItem(STYLEKEY, brew.style);
localStorage.setItem(METAKEY, JSON.stringify({ 'renderer': brew.renderer, 'theme': brew.theme, 'lang': brew.lang }));
},
componentWillUnmount : function() {
document.removeEventListener('keydown', this.handleControlKeys);
@@ -128,21 +115,16 @@ const NewPage = createClass({
handleMetaChange : function(metadata){
this.setState((prevState)=>({
brew : { ...prevState.brew, ...metadata },
}));
localStorage.setItem(METAKEY, JSON.stringify({
// 'title' : this.state.brew.title,
// 'description' : this.state.brew.description,
'renderer' : this.state.brew.renderer,
'theme' : this.state.brew.theme
}));
},
clearErrors : function(){
this.setState({
errors : null,
isSaving : false
}), ()=>{
localStorage.setItem(METAKEY, JSON.stringify({
// 'title' : this.state.brew.title,
// 'description' : this.state.brew.description,
'renderer' : this.state.brew.renderer,
'theme' : this.state.brew.theme,
'lang' : this.state.brew.lang
}));
});
;
},
save : async function(){
@@ -167,7 +149,7 @@ const NewPage = createClass({
.send(brew)
.catch((err)=>{
console.log(err);
this.setState({ isSaving: false, errors: err });
this.setState({ isSaving: false, error: err });
});
if(!res) return;
@@ -179,67 +161,6 @@ const NewPage = createClass({
},
renderSaveButton : function(){
if(this.state.errors){
let errMsg = '';
try {
errMsg += `${this.state.errors.toString()}\n\n`;
errMsg += `\`\`\`\n${this.state.errors.stack}\n`;
errMsg += `${JSON.stringify(this.state.errors.response.error, null, ' ')}\n\`\`\``;
console.log(errMsg);
} catch (e){}
// if(this.state.errors.status == '401'){
// return <Nav.item className='save error' icon='fas fa-exclamation-triangle'>
// Oops!
// <div className='errorContainer' onClick={this.clearErrors}>
// You must be signed in to a Google account
// to save this to<br />Google Drive!<br />
// <a target='_blank' rel='noopener noreferrer'
// href={`https://www.naturalcrit.com/login?redirect=${this.state.url}`}>
// <div className='confirm'>
// Sign In
// </div>
// </a>
// <div className='deny'>
// Not Now
// </div>
// </div>
// </Nav.item>;
// }
if(this.state.errors.response.req.url.match(/^\/api.*Google.*$/m)){
return <Nav.item className='save error' icon='fas fa-exclamation-triangle'>
Oops!
<div className='errorContainer' onClick={this.clearErrors}>
Looks like your Google credentials have
expired! Visit our log in page to sign out
and sign back in with Google,
then try saving again!
<a target='_blank' rel='noopener noreferrer'
href={`https://www.naturalcrit.com/login?redirect=${this.state.url}`}>
<div className='confirm'>
Sign In
</div>
</a>
<div className='deny'>
Not Now
</div>
</div>
</Nav.item>;
}
return <Nav.item className='save error' icon='fas fa-exclamation-triangle'>
Oops!
<div className='errorContainer'>
Looks like there was a problem saving. <br />
Report the issue <a target='_blank' rel='noopener noreferrer'
href={`https://github.com/naturalcrit/homebrewery/issues/new?body=${encodeURIComponent(errMsg)}`}>
here
</a>.
</div>
</Nav.item>;
}
if(this.state.isSaving){
return <Nav.item icon='fas fa-spinner fa-spin' className='save'>
save...
@@ -269,7 +190,10 @@ const NewPage = createClass({
</Nav.section>
<Nav.section>
{this.renderSaveButton()}
{this.state.error ?
<ErrorNavItem error={this.state.error} parent={this}></ErrorNavItem> :
this.renderSaveButton()
}
{this.renderLocalPrintButton()}
<HelpNavItem />
<RecentNavItem />
@@ -291,7 +215,7 @@ const NewPage = createClass({
onMetaChange={this.handleMetaChange}
renderer={this.state.brew.renderer}
/>
<BrewRenderer text={this.state.brew.text} style={this.state.brew.style} renderer={this.state.brew.renderer} theme={this.state.brew.theme} errors={this.state.htmlErrors}/>
<BrewRenderer text={this.state.brew.text} style={this.state.brew.style} renderer={this.state.brew.renderer} theme={this.state.brew.theme} lang={this.state.brew.lang} errors={this.state.htmlErrors}/>
</SplitPane>
</div>
</div>;

View File

@@ -4,79 +4,5 @@
&:hover{
background-color: @green;
}
&.error{
position : relative;
background-color : @red;
}
}
.errorContainer{
animation-name: glideDown;
animation-duration: 0.4s;
position : absolute;
top : 100%;
left : 50%;
z-index : 100000;
width : 140px;
padding : 3px;
color : white;
background-color : #333;
border : 3px solid #444;
border-radius : 5px;
transform : translate(-50% + 3px, 10px);
text-align : center;
font-size : 10px;
font-weight : 800;
text-transform : uppercase;
a{
color : @teal;
}
&:before {
content: "";
width: 0px;
height: 0px;
position: absolute;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 10px solid transparent;
border-bottom: 10px solid #444;
left: 53px;
top: -23px;
}
&:after {
content: "";
width: 0px;
height: 0px;
position: absolute;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 10px solid transparent;
border-bottom: 10px solid #333;
left: 53px;
top: -19px;
}
.deny {
width : 48%;
margin : 1px;
padding : 5px;
background-color : #333;
display : inline-block;
border-left : 1px solid #666;
.animate(background-color);
&:hover{
background-color : red;
}
}
.confirm {
width : 48%;
margin : 1px;
padding : 5px;
background-color : #333;
display : inline-block;
color : white;
.animate(background-color);
&:hover{
background-color : teal;
}
}
}
}

View File

@@ -29,9 +29,10 @@ const PrintPage = createClass({
getInitialState : function() {
return {
brew : {
text : this.props.brew.text || '',
style : this.props.brew.style || undefined,
renderer : this.props.brew.renderer || 'legacy'
text : this.props.brew.text || '',
style : this.props.brew.style || undefined,
renderer : this.props.brew.renderer || 'legacy',
theme : this.props.brew.theme || '5ePHB'
}
};
},
@@ -48,7 +49,7 @@ const PrintPage = createClass({
text : brewStorage,
style : styleStorage,
renderer : metaStorage?.renderer || 'legacy',
theme : metaStorage?.theme || '5ePHB'
theme : metaStorage?.theme || '5ePHB'
}
};
});
@@ -59,7 +60,8 @@ const PrintPage = createClass({
renderStyle : function() {
if(!this.state.brew.style) return;
return <div style={{ display: 'none' }} dangerouslySetInnerHTML={{ __html: `<style> ${this.state.brew.style} </style>` }} />;
//return <div style={{ display: 'none' }} dangerouslySetInnerHTML={{ __html: `<style>@layer styleTab {\n${this.state.brew.style}\n} </style>` }} />;
return <div style={{ display: 'none' }} dangerouslySetInnerHTML={{ __html: `<style>\n${this.state.brew.style}\n</style>` }} />;
},
renderPages : function(){

View File

@@ -5,6 +5,7 @@ const { Meta } = require('vitreum/headtags');
const Nav = require('naturalcrit/nav/nav.jsx');
const Navbar = require('../../navbar/navbar.jsx');
const MetadataNav = require('../../navbar/metadata.navitem.jsx');
const PrintLink = require('../../navbar/print.navitem.jsx');
const RecentNavItem = require('../../navbar/recent.navitem.jsx').both;
const Account = require('../../navbar/account.navitem.jsx');
@@ -12,21 +13,13 @@ const Account = require('../../navbar/account.navitem.jsx');
const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
const { DEFAULT_BREW_LOAD } = require('../../../../server/brewDefaults.js');
const SharePage = createClass({
displayName : 'SharePage',
getDefaultProps : function() {
return {
brew : {
title : '',
text : '',
style : '',
shareId : null,
createdAt : null,
updatedAt : null,
views : 0,
renderer : ''
}
brew : DEFAULT_BREW_LOAD
};
},
@@ -58,8 +51,10 @@ const SharePage = createClass({
return <div className='sharePage sitePage'>
<Meta name='robots' content='noindex, nofollow' />
<Navbar>
<Nav.section>
<Nav.item className='brewTitle'>{this.props.brew.title}</Nav.item>
<Nav.section className='titleSection'>
<MetadataNav brew={this.props.brew}>
<Nav.item className='brewTitle'>{this.props.brew.title}</Nav.item>
</MetadataNav>
</Nav.section>
<Nav.section>

View File

@@ -1,4 +1,8 @@
.sharePage{
.navContent .navSection.titleSection {
flex-grow: 1;
justify-content: center;
}
.content{
overflow-y : hidden;
}

View File

@@ -12,6 +12,7 @@ const RecentNavItem = require('../../navbar/recent.navitem.jsx').both;
const Account = require('../../navbar/account.navitem.jsx');
const NewBrew = require('../../navbar/newbrew.navitem.jsx');
const HelpNavItem = require('../../navbar/help.navitem.jsx');
const ErrorNavItem = require('../../navbar/error-navitem.jsx');
const UserPage = createClass({
displayName : 'UserPage',
@@ -19,7 +20,8 @@ const UserPage = createClass({
return {
username : '',
brews : [],
query : ''
query : '',
error : null
};
},
getInitialState : function() {
@@ -50,10 +52,19 @@ const UserPage = createClass({
brewCollection : brewCollection
};
},
errorReported : function(error) {
this.setState({
error
});
},
navItems : function() {
return <Navbar>
<Nav.section>
{this.state.error ?
<ErrorNavItem error={this.state.error} parent={this}></ErrorNavItem> :
null
}
<NewBrew />
<HelpNavItem />
<RecentNavItem />
@@ -63,7 +74,7 @@ const UserPage = createClass({
},
render : function(){
return <ListPage brewCollection={this.state.brewCollection} navItems={this.navItems()} query={this.props.query}></ListPage>;
return <ListPage brewCollection={this.state.brewCollection} navItems={this.navItems()} query={this.props.query} reportError={this.errorReported}></ListPage>;
}
});

View File

@@ -0,0 +1,12 @@
const request = require('superagent');
const addHeader = (request)=>request.set('Homebrewery-Version', global.version);
const requestMiddleware = {
get : (path)=>addHeader(request.get(path)),
put : (path)=>addHeader(request.put(path)),
post : (path)=>addHeader(request.post(path)),
delete : (path)=>addHeader(request.delete(path)),
};
module.exports = requestMiddleware;

1
client/icons/Davek.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 791.04 953.29"><title>Davek</title><g id="Layer_2" data-name="Layer 2"><g id="Davek"><path d="M178.41,13.46a19.33,19.33,0,0,0-4.71,5.38q8.07,6.07,13.46,6.07a8.27,8.27,0,0,0,4.71-1.35,130.23,130.23,0,0,0,16.83-7.07,74.55,74.55,0,0,1,18.85-6.39h2.7q8.07,0,14.81,8.74a944.19,944.19,0,0,0,95.6,4.72q19.5,0,38.37-.67,69.33-2,139.68-5.72t139.7-5.06q16.82-.64,34.34-.66,50.49,0,98.29,3.36-17.5,12.12-22.55,31.64t-5,33.66q.64,22.89.66,45.1,0,47.13-3.36,97-6.07,74.05-9.78,148.11t-5,146.09v17.51a766.1,766.1,0,0,0,8.75,118.48,38.57,38.57,0,0,0-4,17.51,30.94,30.94,0,0,0,.67,6.06q2,12.12,3.36,23.22c.9,7.42,1.57,14.92,2,22.55v3.37a57.93,57.93,0,0,1-3.36,19.52c.43,4.5.67,8.77.67,12.8a260.65,260.65,0,0,1-2.7,37,344.26,344.26,0,0,0-4,52.52,133.5,133.5,0,0,0,8.09,45.44q8.07,22.57,33,36.68-6.06,8.78-20.19,8.77H762.1c-4.5-.45-8.53-.69-12.12-.69a78.11,78.11,0,0,0-21.54,2.7,579.1,579.1,0,0,0-63.64,3.71q-33.31,3.71-67.65,6.39t-68.66,3.37h-4a188.05,188.05,0,0,1-59.92-9.43q20.19-4,39.06-23.22t20.19-47.46q11.44-22.21,11.45-49.82a320.44,320.44,0,0,1,3.36-49.15q-9.45-4.69-10.09-8.75v-2.7a73,73,0,0,1,.66-8.74,105.81,105.81,0,0,0,3.37-12.8,7.49,7.49,0,0,0,.68-3.37q0-4.7-4.05-10.09c.45-4.93.69-10.1.69-15.48a311.71,311.71,0,0,0-3.37-46.45,207.31,207.31,0,0,1-1.35-24.25,274.58,274.58,0,0,1,4-45.1l15.5,6.73q-3.37-17.49-3.37-41.07,0-24.89,8.75-44.44a27.73,27.73,0,0,0,2-9.43,15.32,15.32,0,0,0-3.36-10.09,60.75,60.75,0,0,1-10.1-15.48l-7.39,6.73q2.67-47.79,8.74-99,3.35-33.63,3.37-65.29,0-14.81-.69-29a205.09,205.09,0,0,1-4-41.74,190.26,190.26,0,0,1,2-26.92q4-37,14.81-67.33a25.14,25.14,0,0,1-2.68-11.43,31.13,31.13,0,0,1,.66-6.07V140q0-6.72-8.74-10.09-3.37-16.83-5.73-31.3T521.07,77.41q-55.2,2.7-115.78,4.71-19.55.7-39.72.69-38.38,0-74.06-2.7c-5.4,4.5-8.08,9.21-8.08,14.14v1.34a41.5,41.5,0,0,0,4.37,15.49q3.7,7.4,7.4,15.16a35,35,0,0,1,3.71,15.13q32.31,34.35,64,68.68a335.89,335.89,0,0,1,51.83,73.38q13.46,7.4,18.51,17.49t10.11,19.87q5.06,9.78,10.1,18.85t16.5,11.78v12.12a194.5,194.5,0,0,1-37.38-4q-20.52-4-40.73-6.73a114.48,114.48,0,0,0-17.49-1.35,97.2,97.2,0,0,0-20.2,2q-17.52,4.05-31,20.19-16.84-1.35-27.27-9.75a76.13,76.13,0,0,1-17.51-20.2q-7.06-11.76-14.47-24.9a79.77,79.77,0,0,0-18.84-22.57A305.87,305.87,0,0,1,177.73,237q-28.29-33.67-54.54-69T68,99.31A381.16,381.16,0,0,0,0,38.37q12.79,0,22.89-9.75A190.69,190.69,0,0,1,44.76,10.44Q56.54,2,68.66,0H72Q82.8,0,97,10.76Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 428.05 941.17"><title>Iokharic</title><g id="Layer_2" data-name="Layer 2"><g id="Iokharic"><path d="M334.76,909.61V259.3l2.74-89.18c3.43,0,6.18-8.23,7.55-24.69,3.43,0,7.55-8.92,13.72-27.44,13-11,19.89-21.27,19.89-31.56,0-13-5.48-20.58-17.15-23.32l-30.87,2.74H320.36c-21.27,13-39.79,22.64-56.94,27.44h-37c-11.67,0-26.76,7.55-46,22q-12.34,0-30.86,16.46c-10.29,0-40.48,26.75-91.93,80.95,0,8.23-6.17,21.26-18.52,38.41l-3.43,15.78v41.84L67.23,343c2.74,0,9.6,6.86,19.89,19.9,24,18.52,36.36,30.86,36.36,38.41l-12.35,10.29H105c-24.7-15.78-45.28-32.93-62.43-52.13L15.78,316.92,0,266.85c3.43-17.84,7.55-29.5,13.72-35v-11c0-18.52,7.55-39.79,22-63.8,0-9.6,8.23-21.27,24.7-34.3,0-9.6,15.77-26.07,46.64-50.08,19.9-16.46,46-28.12,76.83-35,5.49-6.86,21.27-14.41,46.65-21.95C238,5.49,251.07,0,270.28,0h137.2c8.91,0,15.77,8.23,20.57,24V40.47l-5.48,8.23V166c0,17.15-7.55,31.55-21.95,43.22v41.15l-2.75,24.7q0,9.26,24.7,30.87v38.41c0,10.29-4.81,19.9-15.09,28.82h-6.86V558.39c0,55.57-4.81,97.41-15.1,124.16-4.8,2.75-7.54,19.21-9.6,48.71l2.74,17.15-2.74,76.14v30.19q0,32.93-32.93,86.43C337.5,937.74,334.76,926.76,334.76,909.61Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 527.7 940.25"><title>Rellanic</title><g id="Layer_2" data-name="Layer 2"><g id="Rellanic"><path d="M527.7,5.45q-3.83,19.65-15,30.56a129.61,129.61,0,0,1-26.46,19.64q-9.84,6.56-31.66,15.28-19.63,7.65-31.64,16.38Q380.33,103.69,342.16,108a468.46,468.46,0,0,1-54,3.28q-15.83,0-30.56-1.1a53.19,53.19,0,0,0-20.19-6.55H217.74q-7.12,1.11-21.29,1.1a51.67,51.67,0,0,1-20.18-4.36q8.72,19.65,25.63,29.46,14.19,8.74,28.38,29.47a634.05,634.05,0,0,1,98.78,90.58l91.12,103.69a65.1,65.1,0,0,0-.54,8.19,42.47,42.47,0,0,0,.54,7.09c.73,1.82,1.27,3.29,1.64,4.37q7.08,8.75,10.92,12,1.62,1.1,12.55,14.19a14,14,0,0,1,3.27,6.55,9.75,9.75,0,0,1,1.1,4.37,9.62,9.62,0,0,1-1.1,4.36q35.46,43.66,51.3,89.5,3.25,9.82,5.45,19.64a288.59,288.59,0,0,1,10.37,68.75v8.19a296,296,0,0,1-9.81,76.94q-7.12,27.3-24,77.5L418,831.65Q383,872,344.88,899.31a243.27,243.27,0,0,1-90.59,38.19,179.84,179.84,0,0,1-31.64,2.75q-38.78,0-81.87-15.84A293.78,293.78,0,0,1,78,886.22a312.61,312.61,0,0,1-51.85-48,300.52,300.52,0,0,0-18-46.94,60.18,60.18,0,0,1-4.92-13.64,82.36,82.36,0,0,1-2.19-19.11,104.89,104.89,0,0,1,.56-10.91,176.12,176.12,0,0,1-1.64-24,199.79,199.79,0,0,1,2.72-32.74Q5.45,663,5.45,645a103.71,103.71,0,0,0-.54-10.92,242.44,242.44,0,0,1,50.74-67.66,646.83,646.83,0,0,0,57.86-61.12q11.44-10.89,25.09-13.1A88.3,88.3,0,0,1,163.71,489q14.17-1.11,29.46-1.1a108.11,108.11,0,0,0,28.38-7.63q17.44,8.75,27.29,12a124.47,124.47,0,0,1,28.38,13.1q8.71,4.38,23.46,17.46,9.29,9.86,17.47,28.38,7.07,12,9.27,21.83a35.16,35.16,0,0,1,1.64,9.83V585a80.23,80.23,0,0,1-8.73,27.28q-8.2,14.19-18,22.93a166.18,166.18,0,0,1-19.65,19.64q-13.1,8.74-20.72,13.1l-7.65-4.37v-1.64q0-12,6.55-18-8.17-6.55-10.36-10.92l-2.18-8.73c0-2.18-.74-5.81-2.19-10.91v-3.29a38,38,0,0,0-3.82-7.63,196.53,196.53,0,0,0-33.84-40.39Q185.53,542.43,162.61,537a163.71,163.71,0,0,0-50.75,9.81q-25.08,8.76-32.2,36Q67.12,615.56,67.13,654.3a256,256,0,0,0,3.26,39.83,176.75,176.75,0,0,0,5.47,28.38Q88.37,770,122.78,812a452.22,452.22,0,0,0,103.13,58.94,153.57,153.57,0,0,0,107,5.45q25.63-12,37.66-27.28,13.62-14.21,23.46-34.93,10.36-18.57,20.2-39.29Q426.72,753.05,437.1,740q3.27-44.76,5.47-61.12a228.17,228.17,0,0,0,3.26-38.21,213.15,213.15,0,0,0-1.64-26.19,245.3,245.3,0,0,0-8.17-48q-2.2-8.17-4.93-16.36-9.27-30.55-34.92-61.12a70,70,0,0,0-2.18-18,29.12,29.12,0,0,0-4.37-10.37,175.28,175.28,0,0,0-17.46-29.48l-18.55-27.27q-12-16.38-16.38-28.38a282.35,282.35,0,0,1-27.81-28.37q-20.22-26.2-24-31.66Q269,295.76,260.29,286q-10.92-12-31.1-25.11-36.56-31.65-79.12-70.94-45.31-39.28-88.41-66.58-14.74-8.17-17.46-16.9a16.93,16.93,0,0,0-.54-3.83V99.87q0-8.73,6.54-19.11A102.47,102.47,0,0,1,63.3,61.12q9.27-9.82,12.56-18.56a223.6,223.6,0,0,1,38.73-3.27,271,271,0,0,1,40.93,3.27A367.15,367.15,0,0,0,215,47.48c6.91,0,13.64-.17,20.2-.56a45,45,0,0,0,21.27,5.47q17.44,0,25.65-1.1h22.93a77.75,77.75,0,0,1,24,7.65,114,114,0,0,1,27.82-3.29H364q27.25,2.2,39.29,2.19,16.34,0,36.55-5.45,19.1-6.55,27.83-22.93h2.72A20.48,20.48,0,0,0,484.58,24c2.17-4.71,6.17-7.09,12-7.09a26.6,26.6,0,0,1,4.92.54v-.54c0-1.08.72-3.46,2.19-7.11a36.74,36.74,0,0,1,6-6.54C512.57,1.1,515.12,0,517.32,0,521,0,524.41,1.82,527.7,5.45Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

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

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 541.53217 512"
version="1.1"
id="front-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"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:17.9;stroke-linejoin:bevel;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill;stop-color:#000000"
d="m 78.783305,66.564412 c -14.022889,0 -25.4,11.377111 -25.4,25.4 v 84.666668 c 0,14.02289 11.377111,25.4 25.4,25.4 h 76.199995 8.46667 c 4.68312,0 8.46667,-3.78355 8.46667,-8.46667 0,-4.68311 -3.78355,-8.46666 -8.46667,-8.46666 v -16.93334 c 4.68312,0 8.46667,-3.78355 8.46667,-8.46666 v -1.9327 c -0.0322,-0.27545 -0.0652,-0.54693 -0.0946,-0.83923 -0.17511,-1.74441 -0.30542,-3.81626 -0.37672,-6.02909 -0.18285,-5.67612 -0.29322,-5.86808 -0.63459,-6.62698 -0.74838,-1.66366 -2.65792,-3.64941 -4.38681,-4.49844 -1.41973,-0.69716 -0.72585,-0.45434 -1.20923,-0.51934 -0.47548,-0.0639 -2.54581,-0.13856 -6.47454,-0.14056 -0.0907,2.9929 -0.0862,4.81682 -0.58601,7.244 -0.28023,1.36071 -0.97957,3.42078 -2.40812,5.10356 -1.42519,1.67884 -2.81498,2.35811 -3.28145,2.61896 -3.14428,1.76375 -5.09549,2.43427 -9.41597,1.33997 -2.05224,-0.5197 -2.32631,-0.92288 -2.76159,-1.19527 -0.43528,-0.27239 -0.71007,-0.47684 -0.97461,-0.67593 -0.52909,-0.39816 -0.97871,-0.77171 -1.48622,-1.20664 -1.015,-0.86987 -2.20927,-1.95397 -3.6096,-3.26182 -2.80065,-2.61568 -6.38094,-6.09226 -10.18335,-9.90844 -6.19117,-6.21357 -9.5466,-9.59164 -11.7874,-12.16412 -1.1204,-1.28623 -2.03413,-2.38181 -2.90576,-4.03127 -0.87162,-1.64948 -1.40664,-4.21493 -1.40664,-5.61103 0,-1.4012 0.54783,-3.99366 1.42989,-5.64668 0.88206,-1.65304 1.8039,-2.74855 2.94142,-4.04679 2.27504,-2.59646 5.70131,-6.03358 12.03699,-12.369267 7.37691,-7.376888 10.87768,-11.090687 14.75208,-13.810527 1.45289,-1.019939 3.46378,-2.249133 6.08386,-2.580204 0.87337,-0.110323 1.8133,-0.120299 2.82412,0.0098 4.0433,0.520471 6.12413,2.832857 7.01973,3.728454 1.29782,1.297845 3.1373,4.826955 3.46852,7.049182 0.29817,2.00025 0.26393,3.770666 0.25993,6.212541 0.57954,0.0034 0.50388,0.0217 1.17564,0.0217 4.54211,0 8.44363,0.111537 11.991,0.50953 v -21.41004 c 0,-4.683115 -3.78355,-8.466667 -8.46667,-8.466667 h -8.46667 z m 0,101.599998 h 67.733335 v 16.93334 H 78.783305 c -4.683115,0 -8.466667,-3.78357 -8.466667,-8.46667 0,-4.68313 3.783552,-8.46667 8.466667,-8.46667 z" />
<path
style="color:#000000;fill:#000000;stroke-width:17.9;stroke-linejoin:round;-inkscape-stroke:none;paint-order:stroke markers fill"
d="m 186.69094,157.95633 c 2.67243,-2.24871 7.17957,-9.39389 8.63888,-13.69528 1.03796,-3.05942 1.31928,-5.13546 1.33362,-9.84167 0.0278,-9.1246 -2.25302,-14.5915 -8.79325,-21.07662 -6.8535,-6.79576 -12.35348,-8.46107 -27.94423,-8.46107 -8.05417,0 -9.45684,-0.12924 -9.75203,-0.89852 -0.18964,-0.49417 -0.34479,-3.81715 -0.34479,-7.384389 0,-5.728497 -0.13266,-6.618534 -1.13607,-7.621956 -2.57777,-2.57775 -3.29907,-2.07141 -18.02212,12.651595 -12.64444,12.64444 -13.78771,13.94921 -13.78771,15.73575 0,1.78396 1.13629,3.08846 13.49078,15.48766 7.47518,7.50224 14.10644,13.69554 14.8715,13.88928 0.78576,0.19902 2.0096,-0.002 2.84016,-0.46789 1.42969,-0.80092 1.46523,-0.97351 1.74346,-8.46583 l 0.28402,-7.64825 h 8.52049 c 8.16738,0 8.65373,0.0655 11.73586,1.579 3.72428,1.82893 6.9202,5.12058 8.60236,8.86006 0.94352,2.09748 1.22898,4.1112 1.41901,10.01012 0.13083,4.06143 0.49647,7.70394 0.81253,8.09446 0.94895,1.17251 3.64241,0.80611 5.48753,-0.74645 z"
id="path20297" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 704.00001 512"
version="1.1"
id="svg22127"
sodipodi:docname="book-inside-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.47274833"
inkscape:cx="83.55397"
inkscape:cy="178.74204"
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="color:#000000;fill:#000000;fill-opacity:1;stroke-width:1;-inkscape-stroke:none"
d="m 206.76992,184 c -36.98368,0 -73.07301,9.2343 -94.76923,16.9066 v 185.1887 c 27.62799,-7.7405 62.70503,-15.0804 94.76923,-15.0804 28.33376,0 58.16312,7.6425 81.23077,14.806 V 203.0154 C 273.60322,195.1776 243.44241,184 206.76992,184 Z"
id="path4372-8"
sodipodi:nodetypes="sccsccs" />
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:63.9999;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 255.99995,122.53007 c -31.8285,-15.342 -80.43462,-15.4137 -112,0"
id="path2371-6"
sodipodi:nodetypes="cc" />
</svg>

After

Width:  |  Height:  |  Size: 4.0 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

@@ -0,0 +1,57 @@
.fac {
display : inline-block;
}
.position-top-left {
content: url('../icons/position-top-left.svg');
}
.position-top-right {
content: url('../icons/position-top-right.svg');
}
.position-bottom-left {
content: url('../icons/position-bottom-left.svg');
}
.position-bottom-right {
content: url('../icons/position-bottom-right.svg');
}
.position-top {
content: url('../icons/position-top.svg');
}
.position-right {
content: url('../icons/position-right.svg');
}
.position-bottom {
content: url('../icons/position-bottom.svg');
}
.position-left {
content: url('../icons/position-left.svg');
}
.mask-edge {
content: url('../icons/mask-edge.svg');
}
.mask-corner {
content: url('../icons/mask-corner.svg');
}
.mask-center {
content: url('../icons/mask-center.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');
}
.rellanic {
content: url('../icons/Rellanic.svg');
}
.iokharic {
content: url('../icons/Iokharic.svg');
}

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 448 512"
version="1.1"
id="svg135"
sodipodi:docname="mask-center.svg"
width="448"
height="512"
xml:space="preserve"
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:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs139"><pattern
inkscape:collect="always"
xlink:href="#Strips1_1"
id="pattern3077"
patternTransform="matrix(23.13193,-23.131931,19.25517,19.25517,18.091544,-20.306833)" /><pattern
inkscape:collect="always"
patternUnits="userSpaceOnUse"
width="2"
height="1"
patternTransform="translate(0,0) scale(10,10)"
id="Strips1_1"
inkscape:stockid="Stripes 1:1"><rect
style="fill:black;stroke:none"
x="0"
y="-0.5"
width="1"
height="2"
id="rect2097" /></pattern></defs><sodipodi:namedview
id="namedview137"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
showguides="false"
inkscape:zoom="0.67711183"
inkscape:cx="31.75251"
inkscape:cy="260.66595"
inkscape:window-width="1920"
inkscape:window-height="991"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg135" /><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path
id="rect12201"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:30;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000"
d="M 48,-5.2e-6 C 21.40803,-5.2e-6 1.98e-5,21.408025 1.98e-5,47.999995 V 464 C 1.98e-5,490.59197 21.40803,512 48,512 h 352 c 26.59198,0 48,-21.40803 48,-48 V 47.999995 C 448,21.408025 426.59198,-5.2e-6 400,-5.2e-6 Z M 64,63.999995 H 384 V 448 H 64 Z" /><rect
style="fill:url(#pattern3077);fill-opacity:1;stroke:#000000;stroke-width:48;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000"
id="rect12206"
width="176"
height="240"
x="136.00002"
y="136"
rx="48"
ry="48" /></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 448 512"
version="1.1"
id="svg135"
sodipodi:docname="mask-corner.svg"
width="448"
height="512"
xml:space="preserve"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs139"><pattern
inkscape:collect="always"
xlink:href="#Strips1_1"
id="pattern3077"
patternTransform="matrix(23.131931,-23.131931,19.25517,19.25517,26.214281,-26.952711)" /><pattern
inkscape:collect="always"
patternUnits="userSpaceOnUse"
width="2"
height="1"
patternTransform="translate(0,0) scale(10,10)"
id="Strips1_1"
inkscape:stockid="Stripes 1:1"><rect
style="fill:black;stroke:none"
x="0"
y="-0.5"
width="1"
height="2"
id="rect2097" /></pattern></defs><sodipodi:namedview
id="namedview137"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
showguides="false"
inkscape:zoom="0.95758074"
inkscape:cx="275.17262"
inkscape:cy="306.50157"
inkscape:window-width="1920"
inkscape:window-height="991"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg135" /><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path
id="rect12201"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:30;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000"
d="M 48,-5.2e-6 C 21.40803,-5.2e-6 1.98e-5,21.408025 1.98e-5,47.999995 V 464 C 1.98e-5,490.59197 21.40803,512 48,512 h 352 c 26.59198,0 48,-21.40803 48,-48 V 47.999995 C 448,21.408025 426.59198,-5.2e-6 400,-5.2e-6 Z M 64,63.999995 H 384 V 448 H 64 Z" /><rect
style="fill:url(#pattern3077);fill-opacity:1;stroke:#000000;stroke-width:48;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000"
id="rect12206"
width="208"
height="240"
x="32.000011"
y="32.000011"
rx="48"
ry="48" /></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 448 512"
version="1.1"
id="svg135"
sodipodi:docname="mask-edge.svg"
width="448"
height="512"
xml:space="preserve"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs139"><pattern
inkscape:collect="always"
xlink:href="#Strips1_1"
id="pattern3077"
patternTransform="matrix(23.131931,-23.13193,19.25517,19.25517,26.214281,-26.952711)" /><pattern
inkscape:collect="always"
patternUnits="userSpaceOnUse"
width="2"
height="1"
patternTransform="translate(0,0) scale(10,10)"
id="Strips1_1"
inkscape:stockid="Stripes 1:1"><rect
style="fill:black;stroke:none"
x="0"
y="-0.5"
width="1"
height="2"
id="rect2097" /></pattern></defs><sodipodi:namedview
id="namedview137"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
showguides="false"
inkscape:zoom="0.95758074"
inkscape:cx="231.31209"
inkscape:cy="171.78708"
inkscape:window-width="1920"
inkscape:window-height="991"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg135" /><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path
id="rect12201"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:30;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000"
d="M 48,-5.2e-6 C 21.40803,-5.2e-6 1.98e-5,21.408025 1.98e-5,47.999995 V 464 C 1.98e-5,490.59197 21.40803,512 48,512 h 352 c 26.59198,0 48,-21.40803 48,-48 V 47.999995 C 448,21.408025 426.59198,-5.2e-6 400,-5.2e-6 Z M 64,63.999995 H 384 V 448 H 64 Z" /><rect
style="fill:url(#pattern3077);fill-opacity:1;stroke:#000000;stroke-width:48;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000"
id="rect12206"
width="208"
height="447.99997"
x="32.000011"
y="32.000011"
rx="48"
ry="48" /><rect
style="fill:#000000;fill-opacity:1;stroke-width:47.9999;stroke-linejoin:round;stroke-dasharray:none;paint-order:fill markers stroke;stop-color:#000000"
id="rect4640"
width="48"
height="512"
x="216"
y="0" /></svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 448 512"
version="1.1"
id="svg135"
sodipodi:docname="position-bottom-left.svg"
width="448"
height="512"
xml:space="preserve"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
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="defs139" /><sodipodi:namedview
id="namedview137"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
showguides="false"
inkscape:zoom="0.70792086"
inkscape:cx="174.45453"
inkscape:cy="325.60137"
inkscape:window-width="1920"
inkscape:window-height="991"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg135" /><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path
id="rect12201"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:30;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000"
d="m 48,511.99998 c -26.59197,0 -48.00000035682677,-21.40803 -48.00000035682677,-48 v -416 C -3.5682677e-7,21.40801 21.40803,-1.9692461e-5 48,-1.9692461e-5 h 352 c 26.59198,0 48,21.408029692461 48,47.999999692461 v 416 c 0,26.59197 -21.40802,48 -48,48 z m 16,-64 h 320 v -384 H 64 Z" /><rect
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:30;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000"
id="rect12206"
width="208"
height="240"
x="-3.5682677e-07"
y="-512"
rx="48"
ry="48"
transform="scale(1,-1)" /></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 448 512"
version="1.1"
id="svg135"
sodipodi:docname="position-bottom-right.svg"
width="448"
height="512"
xml:space="preserve"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
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="defs139" /><sodipodi:namedview
id="namedview137"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
showguides="false"
inkscape:zoom="0.70792086"
inkscape:cx="174.45453"
inkscape:cy="325.60137"
inkscape:window-width="1920"
inkscape:window-height="991"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg135" /><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path
id="rect12201"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:30;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000"
d="m 400,511.99998 c 26.59197,0 48,-21.40803 48,-48 v -416 C 448,21.40801 426.59197,-1.9692461e-5 400,-1.9692461e-5 H 48 C 21.40802,-1.9692461e-5 -3.5682677e-7,21.40801 -3.5682677e-7,47.99998 v 416 c 0,26.59197 21.40802035682677,48 48.00000035682677,48 z m -16,-64 H 64 v -384 h 320 z" /><rect
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:30;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000"
id="rect12206"
width="208"
height="240"
x="-448"
y="-512"
rx="48"
ry="48"
transform="scale(-1)" /></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 448 512"
version="1.1"
id="svg135"
sodipodi:docname="position-bottom.svg"
width="448"
height="512"
xml:space="preserve"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
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="defs139" /><sodipodi:namedview
id="namedview137"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
showguides="false"
inkscape:zoom="1.0011513"
inkscape:cx="273.18549"
inkscape:cy="216.25103"
inkscape:window-width="1920"
inkscape:window-height="991"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg135" /><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path
id="rect12201-2"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:30;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000"
d="m 48,512.00004 c -26.5919,0 -48,-21.4081 -48,-48 V 47.999996 C 0,21.408026 21.4081,-3.8146973e-6 48,-3.8146973e-6 h 352 c 26.592,0 48,21.4080298146973 48,47.9999998146973 V 464.00004 c 0,26.5919 -21.408,48 -48,48 z m 16,-64 H 384 V 63.999996 H 64 Z" /><rect
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:30.0001;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000"
id="rect12206-8"
width="447.99997"
height="240"
x="1.40625e-05"
y="-512.00006"
rx="48"
ry="48"
transform="scale(1,-1)" /></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 448 512"
version="1.1"
id="svg135"
sodipodi:docname="position-left.svg"
width="448"
height="512"
xml:space="preserve"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
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="defs139" /><sodipodi:namedview
id="namedview137"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
showguides="false"
inkscape:zoom="0.70792086"
inkscape:cx="164.56642"
inkscape:cy="243.6713"
inkscape:window-width="1920"
inkscape:window-height="991"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg135" /><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path
id="rect12201-0"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:30;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000"
d="M 48,0 C 21.4081,0 0,21.40803 0,48 v 416 c 0,26.59197 21.4081,48 48,48 h 352.0001 c 26.5919,0 48,-21.40803 48,-48 V 48 c 0,-26.59197 -21.4081,-48 -48,-48 z M 64,64 H 384.0001 V 448 H 64 Z" /><rect
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:30;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000"
id="rect12206-2"
width="208"
height="512.00006"
x="7.0762391e-05"
y="-8.8710935e-05"
rx="48"
ry="48.000004" /></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 448 512"
version="1.1"
id="svg135"
sodipodi:docname="position-right.svg"
width="448"
height="512"
xml:space="preserve"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
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="defs139" /><sodipodi:namedview
id="namedview137"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
showguides="false"
inkscape:zoom="0.70792086"
inkscape:cx="164.56642"
inkscape:cy="243.6713"
inkscape:window-width="1920"
inkscape:window-height="991"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg135" /><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path
id="rect12201-0"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:30;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000"
d="m 400.0001,0 c 26.5919,0 48,21.40803 48,48 v 416 c 0,26.59197 -21.4081,48 -48,48 H 48 C 21.4081,512 0,490.59197 0,464 V 48 C 0,21.40803 21.4081,0 48,0 Z m -16,64 H 64 v 384 h 320.0001 z" /><rect
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:30;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000"
id="rect12206-2"
width="208"
height="512.00006"
x="-448.00003"
y="-8.8710935e-05"
rx="48"
ry="48.000004"
transform="scale(-1,1)" /></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 448 512"
version="1.1"
id="svg135"
sodipodi:docname="position-top-left.svg"
width="448"
height="512"
xml:space="preserve"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
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="defs139" /><sodipodi:namedview
id="namedview137"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
showguides="false"
inkscape:zoom="0.70792086"
inkscape:cx="174.45453"
inkscape:cy="325.60137"
inkscape:window-width="1920"
inkscape:window-height="991"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg135" /><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path
id="rect12201"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:30;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000"
d="M 48,0 C 21.40803,0 0,21.40803 0,48 v 416 c 0,26.59197 21.40803,48 48,48 h 352 c 26.59198,0 48,-21.40803 48,-48 V 48 C 448,21.40803 426.59198,0 400,0 Z M 64,64 H 384 V 448 H 64 Z" /><rect
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:30;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000"
id="rect12206"
width="208"
height="240"
x="-3.5682677e-07"
y="-1.9692461e-05"
rx="48"
ry="48" /></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 448 512"
version="1.1"
id="svg135"
sodipodi:docname="position-top-right.svg"
width="448"
height="512"
xml:space="preserve"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
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="defs139" /><sodipodi:namedview
id="namedview137"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
showguides="false"
inkscape:zoom="0.70792086"
inkscape:cx="174.45453"
inkscape:cy="325.60137"
inkscape:window-width="1920"
inkscape:window-height="991"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg135" /><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path
id="rect12201"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:30;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000"
d="m 400,0 c 26.59197,0 48,21.40803 48,48 v 416 c 0,26.59197 -21.40803,48 -48,48 H 48 C 21.40802,512 -3.5682677e-7,490.59197 -3.5682677e-7,464 V 48 C -3.5682677e-7,21.40803 21.40802,0 48,0 Z M 384,64 H 64 v 384 h 320 z" /><rect
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:30;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000"
id="rect12206"
width="208"
height="240"
x="-448"
y="-1.9692461e-05"
rx="48"
ry="48"
transform="scale(-1,1)" /></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 448 512"
version="1.1"
id="svg135"
sodipodi:docname="position-top.svg"
width="448"
height="512"
xml:space="preserve"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
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="defs139" /><sodipodi:namedview
id="namedview137"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
showguides="false"
inkscape:zoom="1.0011513"
inkscape:cx="273.18549"
inkscape:cy="216.25103"
inkscape:window-width="1920"
inkscape:window-height="991"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg135" /><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path
id="rect12201-2"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:30;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000"
d="M 48,0 C 21.4081,0 0,21.4081 0,48 v 416.00004 c 0,26.59197 21.4081,48 48,48 h 352 c 26.592,0 48,-21.40803 48,-48 V 48 C 448,21.4081 426.592,0 400,0 Z M 64,64 H 384 V 448.00004 H 64 Z" /><rect
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:30.0001;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000"
id="rect12206-8"
width="447.99997"
height="240"
x="1.40625e-05"
y="-3.8146973e-06"
rx="48"
ry="48" /></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

43
install/README.WINDOWS.md Normal file
View File

@@ -0,0 +1,43 @@
# Windows Installation Instructions
## Before Installing
These instructions assume that you are installing to a completely new, fresh Windows 10 installation. As such, some steps may not be necessary if you are installing to an existing Windows 10 instance.
## Installation instructions
1. Download the installation script from https://raw.githubusercontent.com/naturalcrit/homebrewery/master/install/windows/install.ps1.
2. Run Powershell as an Administrator.
a. Click the Start menu or press the Windows key.
b. Type `powershell` into the Search box.
c. Right click on the Powershell app and select "Run As Administrator".
d. Click YES in the prompt that appears.
3. Change the script execution policy.
a. Run the Powershell command `Set-ExecutionPolicy Bypass -Scope Process`.
b. Allow the change to be made - press Y at the prompt that appears.
4. Run the installation script.
a. Navigate to the location of the script, e.g. `cd C:\Users\ExampleUser\Downloads`.
b. Start the script - `.\install.ps1`
5. Once the script has completed, it will start the Homebrewery server. This will normally cause a Network Access prompt for NodeJS - if this appears, click "Allow".
**NOTE:** At this time, the script **ONLY** installs HomeBrewery. It does **NOT** install the NaturalCrit login system, as that is currently a completely separate project.
---
### Testing
These installation instructions have been tested on the following Ubuntu releases:
- *Windows 10 Home - OS Build 19045.2546*
## Final Notes
While this installation process works successfully at the time of writing (January 23, 2023), it relies on all of the Node.JS packages used in the HomeBrewery project retaining their cross-platform capabilities to continue to function. This is one of the inherent advantages of Node.JS, but it is by no means guaranteed and as such, functionality or even installation may fail without warning at some point in the future.
Regards,
G
January 23, 2023

View File

@@ -0,0 +1,51 @@
Write-Host Homebrewery Install -BackgroundColor Black -ForegroundColor Yellow
Write-Host =================== -BackgroundColor Black -ForegroundColor Yellow
Write-Host Install Chocolatey -BackgroundColor Black -ForegroundColor Yellow
Write-Host Instructions from https://chocolate.org/install -BackgroundColor Black -ForegroundColor Yellow
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
Write-Host Install Node JS v16.11.1 -BackgroundColor Black -ForegroundColor Yellow
choco install nodejs --version=16.11.1 -y
Write-Host Install MongoDB v 4.4.4 -BackgroundColor Black -ForegroundColor Yellow
choco install mongodb --version=4.4.4 -y
Write-Host Install GIT -BackgroundColor Black -ForegroundColor Yellow
choco install git -y
Write-Host Refresh Environment -BackgroundColor Black -ForegroundColor Yellow
Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
Update-SessionEnvironment
Write-Host Create Homebrewery directory - C:\Homebrewery -BackgroundColor Black -ForegroundColor Yellow
mkdir C:\Hombrewery
cd C:\Hombrewery
Write-Host Download Homebrewery project files -BackgroundColor Black -ForegroundColor Yellow
git clone https://github.com/naturalcrit/homebrewery.git
Write-Host Install Homebrewery files -BackgroundColor Black -ForegroundColor Yellow
cd homebrewery
npm install
npm audit fix
Write-Host Set install type to 'local' -BackgroundColor Black -ForegroundColor Yellow
[System.Environment]::SetEnvironmentVariable('NODE_ENV', 'local')
Write-Host INSTALL COMPLETE -BackgroundColor Black -ForegroundColor Yellow
Write-Host To start Homebrewery in the future, open a terminal in the Homebrewery directory and run npm start -BackgroundColor Black -ForegroundColor Yellow
Write-Host ================================================================================================== -BackgroundColor Black -ForegroundColor Yellow
Write-Host Start Homebrewery -BackgroundColor Black -ForegroundColor Yellow
npm start

46611
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.5.0",
"version": "3.9.0",
"engines": {
"node": "16.11.x"
"node": ">=18.16.x"
},
"repository": {
"type": "git",
@@ -12,20 +12,27 @@
"scripts": {
"dev": "node scripts/dev.js",
"quick": "node scripts/quick.js",
"build": "node scripts/buildHomebrew.js",
"buildall": "node scripts/buildHomebrew.js && node scripts/buildAdmin.js",
"build": "node scripts/buildHomebrew.js && node scripts/buildAdmin.js",
"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",
"test": "jest --runInBand",
"test:api-unit": "jest server/*.spec.js --verbose",
"test:coverage": "jest --coverage --silent --runInBand",
"test:dev": "jest --verbose --watch",
"test:basic": "jest tests/markdown/basic.test.js --verbose",
"test:mustache-span": "jest tests/markdown/mustache-span.test.js --verbose",
"test:mustache-syntax": "jest '.*(mustache-syntax).*' --verbose --noStackTrace",
"test:mustache-syntax:inline": "jest '.*(mustache-syntax).*' -t '^Inline:.*' --verbose --noStackTrace",
"test:mustache-syntax:block": "jest '.*(mustache-syntax).*' -t '^Block:.*' --verbose --noStackTrace",
"test:mustache-syntax:injection": "jest '.*(mustache-syntax).*' -t '^Injection:.*' --verbose --noStackTrace",
"test:route": "jest tests/routes/static-pages.test.js --verbose",
"phb": "node scripts/phb.js",
"prod": "set NODE_ENV=production && npm run build",
"postinstall": "npm run buildall",
"postinstall": "npm run build",
"start": "node server.js"
},
"author": "stolksdorf",
@@ -34,11 +41,31 @@
"build/*"
],
"jest": {
"testTimeout": 15000,
"testTimeout": 30000,
"modulePaths": [
"mode_modules",
"node_modules",
"shared",
"server"
],
"coveragePathIgnorePatterns": [
"build/*"
],
"coverageThreshold": {
"global": {
"statements": 25,
"branches": 10,
"functions": 22,
"lines": 25
},
"server/homebrew.api.js": {
"statements": 65,
"branches": 50,
"functions": 60,
"lines": 70
}
},
"setupFilesAfterEnv": [
"jest-expect-message"
]
},
"babel": {
@@ -51,45 +78,53 @@
]
},
"dependencies": {
"@babel/core": "^7.20.7",
"@babel/plugin-transform-runtime": "^7.19.6",
"@babel/preset-env": "^7.19.4",
"@babel/preset-react": "^7.18.6",
"body-parser": "^1.20.1",
"@babel/core": "^7.22.1",
"@babel/plugin-transform-runtime": "^7.22.4",
"@babel/preset-env": "^7.22.4",
"@babel/preset-react": "^7.22.3",
"@googleapis/drive": "^5.1.0",
"body-parser": "^1.20.2",
"classnames": "^2.3.2",
"codemirror": "^5.65.6",
"cookie-parser": "^1.4.6",
"create-react-class": "^15.7.0",
"dedent-tabs": "^0.10.2",
"dedent-tabs": "^0.10.3",
"express": "^4.18.2",
"express-async-handler": "^1.2.0",
"express-static-gzip": "2.1.7",
"fs-extra": "11.1.0",
"googleapis": "110.0.0",
"fs-extra": "11.1.1",
"js-yaml": "^4.1.0",
"jwt-simple": "^0.5.6",
"less": "^3.13.1",
"lodash": "^4.17.21",
"marked": "4.2.4",
"marked-extended-tables": "^1.0.5",
"marked": "5.0.4",
"marked-extended-tables": "^1.0.6",
"marked-gfm-heading-id": "^3.0.3",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.29.4",
"mongoose": "^6.8.1",
"mongoose": "^7.2.2",
"nanoid": "3.3.4",
"nconf": "^0.12.0",
"npm": "^8.10.0",
"npm": "^9.6.7",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-frame-component": "4.1.3",
"react-router-dom": "6.6.0",
"react-frame-component": "^4.1.3",
"react-router-dom": "6.11.2",
"sanitize-filename": "1.6.3",
"superagent": "^6.1.0",
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
},
"devDependencies": {
"eslint": "^8.30.0",
"eslint-plugin-react": "^7.31.11",
"jest": "^29.2.2",
"eslint": "^8.41.0",
"eslint-plugin-jest": "^27.2.1",
"eslint-plugin-react": "^7.32.2",
"jest": "^29.5.0",
"jest-expect-message": "^1.1.3",
"postcss-less": "^6.0.0",
"stylelint": "^15.6.2",
"stylelint-config-recess-order": "^4.0.0",
"stylelint-config-recommended": "^12.0.0",
"stylelint-stylistic": "^0.4.2",
"supertest": "^6.3.3"
}
}

View File

@@ -21,6 +21,7 @@ const transforms = {
const build = async ({ bundle, render, ssr })=>{
const css = await lessTransform.generate({ paths: './shared' });
//css = `@layer bundle {\n${css}\n}`;
await fs.outputFile('./build/homebrew/bundle.css', css);
await fs.outputFile('./build/homebrew/bundle.js', bundle);
await fs.outputFile('./build/homebrew/ssr.js', ssr);
@@ -72,6 +73,7 @@ fs.emptyDirSync('./build');
themeData.path = dir;
themes.V3[dir] = (themeData);
fs.copy(`./themes/V3/${dir}/dropdownTexture.png`, `./build/themes/V3/${dir}/dropdownTexture.png`);
fs.copy(`./themes/V3/${dir}/dropdownPreview.png`, `./build/themes/V3/${dir}/dropdownPreview.png`);
const src = `./themes/V3/${dir}/style.less`;
((outputDirectory)=>{
less.render(fs.readFileSync(src).toString(), {
@@ -95,6 +97,7 @@ fs.emptyDirSync('./build');
// Move assets
await fs.copy('./themes/fonts', './build/fonts');
await fs.copy('./themes/assets', './build/assets');
await fs.copy('./client/icons', './build/icons');
//v==----------------------------- BUNDLE PACKAGES --------------------------------==v//
@@ -135,7 +138,9 @@ fs.emptyDirSync('./build');
//In development set up a watch server and livereload
if(isDev){
livereload('./build');
watchFile('./server.js', {
watch : ['./client', './server'] // Watch additional folders if you want
watchFile('./server.js', { // Rebuild when change detected to this file or any nested directory from here
ignore : ['./build'], // Ignore ./build or it will rebuild again
ext : 'less', // Other extensions to watch (only .js/.json/.jsx by default)
//watch: ['./client', './server', './themes'], // Watch additional folders if you want
});
}

View File

@@ -16,7 +16,7 @@ const mw = {
.status(401)
.send('Authorization Required');
}
const [username, password] = new Buffer(req.get('authorization').split(' ').pop(), 'base64')
const [username, password] = Buffer.from(req.get('authorization').split(' ').pop(), 'base64')
.toString('ascii')
.split(':');
if(process.env.ADMIN_USER === username && process.env.ADMIN_PASS === password){

View File

@@ -15,13 +15,15 @@ const serveCompressedStaticAssets = require('./static-assets.mv.js');
const sanitizeFilename = require('sanitize-filename');
const asyncHandler = require('express-async-handler');
const { DEFAULT_BREW } = require('./brewDefaults.js');
const splitTextStyleAndMetadata = (brew)=>{
brew.text = brew.text.replaceAll('\r\n', '\n');
if(brew.text.startsWith('```metadata')) {
const index = brew.text.indexOf('```\n\n');
const metadataSection = brew.text.slice(12, index - 1);
const metadata = yaml.load(metadataSection);
Object.assign(brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer', 'theme']));
Object.assign(brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang']));
brew.text = brew.text.slice(index + 5);
}
if(brew.text.startsWith('```css')) {
@@ -29,7 +31,6 @@ const splitTextStyleAndMetadata = (brew)=>{
brew.style = brew.text.slice(7, index - 1);
brew.text = brew.text.slice(index + 5);
}
_.defaults(brew, { 'renderer': 'legacy', 'theme': '5ePHB' });
};
const sanitizeBrew = (brew, accessType)=>{
@@ -42,8 +43,7 @@ const sanitizeBrew = (brew, accessType)=>{
};
app.use('/', serveCompressedStaticAssets(`build`));
//app.use(express.static(`${__dirname}/build`));
app.use(require('./middleware/content-negotiation.js'));
app.use(require('body-parser').json({ limit: '25mb' }));
app.use(require('cookie-parser')());
app.use(require('./forcessl.mw.js'));
@@ -224,6 +224,7 @@ app.get('/user/:username', async (req, res, next)=>{
'pageCount',
'description',
'authors',
'lang',
'published',
'views',
'shareId',
@@ -293,7 +294,15 @@ app.get('/edit/:id', asyncHandler(getBrew('edit')), (req, res, next)=>{
app.get('/new/:id', asyncHandler(getBrew('share')), (req, res, next)=>{
sanitizeBrew(req.brew, 'share');
splitTextStyleAndMetadata(req.brew);
req.brew.title = `CLONE - ${req.brew.title}`;
const brew = {
shareId : req.brew.shareId,
title : `CLONE - ${req.brew.title}`,
text : req.brew.text,
style : req.brew.style,
renderer : req.brew.renderer,
theme : req.brew.theme
};
req.brew = _.defaults(brew, DEFAULT_BREW);
req.ogMeta = { ...defaultMetaTags,
title : 'New',
@@ -406,6 +415,7 @@ if(isLocalEnvironment){
//Render the page
const templateFn = require('./../client/template.js');
app.use(asyncHandler(async (req, res, next)=>{
// Create configuration object
const configuration = {
local : isLocalEnvironment,

38
server/brewDefaults.js Normal file
View File

@@ -0,0 +1,38 @@
const _ = require('lodash');
// Default properties for newly-created brews
const DEFAULT_BREW = {
title : '',
text : '',
style : undefined,
description : '',
editId : undefined,
shareId : undefined,
createdAt : undefined,
updatedAt : undefined,
renderer : 'V3',
theme : '5ePHB',
authors : [],
tags : [],
systems : [],
lang : 'en',
thumbnail : '',
views : 0,
published : false,
pageCount : 1,
gDrive : false,
trashed : false
};
// Default values for older brews with missing properties
// e.g., missing "renderer" is assumed to be "legacy"
const DEFAULT_BREW_LOAD = _.defaults(
{
renderer : 'legacy',
},
DEFAULT_BREW);
module.exports = {
DEFAULT_BREW,
DEFAULT_BREW_LOAD
};

View File

@@ -27,8 +27,8 @@ const disconnect = async ()=>{
};
const connect = async (config)=>{
return await Mongoose.connect(getMongoDBURL(config),
{ retryWrites: false }, handleConnectionError);
return await Mongoose.connect(getMongoDBURL(config), { retryWrites: false })
.catch((error)=>handleConnectionError(error));
};
module.exports = {

View File

@@ -1,6 +1,6 @@
/* eslint-disable max-lines */
const _ = require('lodash');
const { google } = require('googleapis');
const googleDrive = require('@googleapis/drive');
const { nanoid } = require('nanoid');
const token = require('./token.js');
const config = require('./config.js');
@@ -14,7 +14,7 @@ if(!config.get('service_account')){
config.get('service_account');
try {
serviceAuth = google.auth.fromJSON(keys);
serviceAuth = googleDrive.auth.fromJSON(keys);
serviceAuth.scopes = ['https://www.googleapis.com/auth/drive'];
} catch (err) {
console.warn(err);
@@ -22,7 +22,7 @@ if(!config.get('service_account')){
}
}
google.options({ auth: serviceAuth || config.get('google_api_key') });
const defaultAuth = serviceAuth || config.get('google_api_key');
const GoogleActions = {
@@ -33,7 +33,7 @@ const GoogleActions = {
throw (err);
}
const oAuth2Client = new google.auth.OAuth2(
const oAuth2Client = new googleDrive.auth.OAuth2(
config.get('google_client_id'),
config.get('google_client_secret'),
'/auth/google/redirect'
@@ -60,7 +60,7 @@ const GoogleActions = {
},
getGoogleFolder : async (auth)=>{
const drive = google.drive({ version: 'v3', auth });
const drive = googleDrive.drive({ version: 'v3', auth });
fileMetadata = {
'name' : 'Homebrewery',
@@ -97,25 +97,33 @@ const GoogleActions = {
},
listGoogleBrews : async (auth)=>{
const drive = google.drive({ version: 'v3', 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,
@@ -129,14 +137,16 @@ const GoogleActions = {
description : file.description,
views : parseInt(file.properties.views),
published : file.properties.published ? file.properties.published == 'true' : false,
systems : []
systems : [],
lang : file.properties.lang,
thumbnail : file.properties.thumbnail
};
});
return brews;
},
updateGoogleBrew : async (brew)=>{
const drive = google.drive({ version: 'v3' });
const drive = googleDrive.drive({ version: 'v3', auth: defaultAuth });
await drive.files.update({
fileId : brew.googleId,
@@ -149,7 +159,8 @@ const GoogleActions = {
editId : brew.editId || nanoid(12),
pageCount : brew.pageCount,
renderer : brew.renderer || 'legacy',
isStubbed : true
isStubbed : true,
lang : brew.lang || 'en'
}
},
media : {
@@ -167,7 +178,7 @@ const GoogleActions = {
},
newGoogleBrew : async (auth, brew)=>{
const drive = google.drive({ version: 'v3', auth });
const drive = googleDrive.drive({ version: 'v3', auth });
const media = {
mimeType : 'text/plain',
@@ -187,7 +198,8 @@ const GoogleActions = {
pageCount : brew.pageCount,
renderer : brew.renderer || 'legacy',
isStubbed : true,
version : 1
version : 1,
lang : brew.lang || 'en'
}
};
@@ -218,7 +230,7 @@ const GoogleActions = {
},
getGoogleBrew : async (id, accessId, accessType)=>{
const drive = google.drive({ version: 'v3' });
const drive = googleDrive.drive({ version: 'v3', auth: defaultAuth });
const obj = await drive.files.get({
fileId : id,
@@ -255,6 +267,7 @@ const GoogleActions = {
description : obj.data.description,
systems : obj.data.properties.systems ? obj.data.properties.systems.split(',') : [],
authors : [],
lang : obj.data.properties.lang,
published : obj.data.properties.published ? obj.data.properties.published == 'true' : false,
trashed : obj.data.trashed,
@@ -274,7 +287,7 @@ const GoogleActions = {
},
deleteGoogleBrew : async (auth, id, accessId)=>{
const drive = google.drive({ version: 'v3', auth });
const drive = googleDrive.drive({ version: 'v3', auth });
const obj = await drive.files.get({
fileId : id,
@@ -300,7 +313,7 @@ const GoogleActions = {
},
increaseView : async (id, accessId, accessType, brew)=>{
const drive = google.drive({ version: 'v3' });
const drive = googleDrive.drive({ version: 'v3', auth: defaultAuth });
await drive.files.update({
fileId : brew.googleId,

View File

@@ -9,345 +9,339 @@ const yaml = require('js-yaml');
const asyncHandler = require('express-async-handler');
const { nanoid } = require('nanoid');
const { DEFAULT_BREW, DEFAULT_BREW_LOAD } = require('./brewDefaults.js');
// const getTopBrews = (cb) => {
// HomebrewModel.find().sort({ views: -1 }).limit(5).exec(function(err, brews) {
// cb(brews);
// });
// };
const getId = (req)=>{
// Set the id and initial potential google id, where the google id is present on the existing brew.
let id = req.params.id, googleId = req.body?.googleId;
// 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);
}
return { id, googleId };
};
const getBrew = (accessType, stubOnly = false)=>{
// Create middleware with the accessType passed in as part of the scope
return async (req, res, next)=>{
// Get relevant IDs for the brew
const { id, googleId } = getId(req);
// Try to find the document in the Homebrewery database -- if it doesn't exist, that's fine.
let stub = await HomebrewModel.get(accessType === 'edit' ? { editId: id } : { shareId: id })
.catch((err)=>{
if(googleId) {
console.warn(`Unable to find document stub for ${accessType}Id ${id}`);
} else {
console.warn(err);
}
});
stub = stub?.toObject();
// If there is a google id, try to find the google brew
if(!stubOnly && (googleId || stub?.googleId)) {
let googleError;
const googleBrew = await GoogleActions.getGoogleBrew(googleId || stub?.googleId, id, accessType)
.catch((err)=>{
console.warn(err);
googleError = err;
});
// If we can't find the google brew and there is a google id for the brew, throw an error.
if(!googleBrew) throw googleError;
// Combine the Homebrewery stub with the google brew, or if the stub doesn't exist just use the google brew
stub = stub ? _.assign({ ...excludeStubProps(stub), stubbed: true }, excludeGoogleProps(googleBrew)) : googleBrew;
}
const authorsExist = stub?.authors?.length > 0;
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.`;
}
// 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';
}
if(typeof stub?.tags === 'string') {
stub.tags = [];
}
req.brew = stub || {};
next();
};
};
const mergeBrewText = (brew)=>{
let text = brew.text;
if(brew.style !== undefined) {
text = `\`\`\`css\n` +
`${brew.style || ''}\n` +
`\`\`\`\n\n` +
`${text}`;
}
const metadata = _.pick(brew, ['title', 'description', 'tags', 'systems', 'renderer', 'theme']);
text = `\`\`\`metadata\n` +
`${yaml.dump(metadata)}\n` +
`\`\`\`\n\n` +
`${text}`;
return text;
};
const MAX_TITLE_LENGTH = 100;
const getGoodBrewTitle = (text)=>{
const tokens = Markdown.marked.lexer(text);
return (tokens.find((token)=>token.type === 'heading' || token.type === 'paragraph')?.text || 'No Title')
.slice(0, MAX_TITLE_LENGTH);
};
const api = {
homebrewApi : router,
getId : (req)=>{
// Set the id and initial potential google id, where the google id is present on the existing brew.
let id = req.params.id, googleId = req.body?.googleId;
const excludePropsFromUpdate = (brew)=>{
// Remove undesired properties
const modified = _.clone(brew);
const propsToExclude = ['_id', 'views', 'lastViewed', 'editId', 'shareId', 'googleId'];
for (const prop of propsToExclude) {
delete modified[prop];
}
return modified;
};
const excludeGoogleProps = (brew)=>{
const modified = _.clone(brew);
const propsToExclude = ['version', 'tags', 'systems', 'published', 'authors', 'owner', 'views', 'thumbnail'];
for (const prop of propsToExclude) {
delete modified[prop];
}
return modified;
};
const excludeStubProps = (brew)=>{
const propsToExclude = ['text', 'textBin', 'renderer', 'pageCount'];
for (const prop of propsToExclude) {
brew[prop] = undefined;
}
return brew;
};
const beforeNewSave = (account, brew)=>{
if(!brew.title) {
brew.title = getGoodBrewTitle(brew.text);
}
brew.authors = (account) ? [account.username] : [];
brew.text = mergeBrewText(brew);
};
const newGoogleBrew = async (account, brew, res)=>{
const oAuth2Client = GoogleActions.authCheck(account, res);
const newBrew = excludeGoogleProps(brew);
return await GoogleActions.newGoogleBrew(oAuth2Client, newBrew);
};
const newBrew = async (req, res)=>{
const brew = req.body;
const { saveToGoogle } = req.query;
delete brew.editId;
delete brew.shareId;
delete brew.googleId;
beforeNewSave(req.account, brew);
const newHomebrew = new HomebrewModel(brew);
newHomebrew.editId = nanoid(12);
newHomebrew.shareId = nanoid(12);
let googleId, saved;
if(saveToGoogle) {
googleId = await newGoogleBrew(req.account, newHomebrew, res)
.catch((err)=>{
console.error(err);
res.status(err?.status || err?.response?.status || 500).send(err?.message || err);
});
if(!googleId) return;
excludeStubProps(newHomebrew);
newHomebrew.googleId = googleId;
} else {
// Compress brew text to binary before saving
newHomebrew.textBin = zlib.deflateRawSync(newHomebrew.text);
// Delete the non-binary text field since it's not needed anymore
newHomebrew.text = undefined;
}
saved = await newHomebrew.save()
.catch((err)=>{
console.error(err, err.toString(), err.stack);
throw `Error while creating new brew, ${err.toString()}`;
});
if(!saved) return;
saved = saved.toObject();
res.status(200).send(saved);
};
const updateBrew = async (req, res)=>{
// Initialize brew from request and body, destructure query params, set a constant for the google id, and set the initial value for the after-save method
const brewFromClient = excludePropsFromUpdate(req.body);
if(req.brew.version > brewFromClient.version) {
res.setHeader('Content-Type', 'application/json');
return res.status(409).send(JSON.stringify({ message: `The brew has been changed on a different device. Please save your changes elsewhere, refresh, and try again.` }));
}
let brew = _.assign(req.brew, brewFromClient);
const { saveToGoogle, removeFromGoogle } = req.query;
const googleId = brew.googleId;
let afterSave = async ()=>true;
brew.text = mergeBrewText(brew);
if(brew.googleId && removeFromGoogle) {
// If the google id exists and we're removing it from google, set afterSave to delete the google brew and mark the brew's google id as undefined
afterSave = async ()=>{
return await deleteGoogleBrew(req.account, googleId, brew.editId, res)
.catch((err)=>{
console.error(err);
res.status(err?.status || err?.response?.status || 500).send(err.message || err);
});
};
brew.googleId = undefined;
} else if(!brew.googleId && saveToGoogle) {
// If we don't have a google id and the user wants to save to google, create the google brew and set the google id on the brew
brew.googleId = await newGoogleBrew(req.account, excludeGoogleProps(brew), res)
.catch((err)=>{
console.error(err);
res.status(err.status || err.response.status).send(err.message || err);
});
if(!brew.googleId) return;
} else if(brew.googleId) {
// If the google id exists and no other actions are being performed, update the google brew
const updated = await GoogleActions.updateGoogleBrew(excludeGoogleProps(brew))
.catch((err)=>{
console.error(err);
res.status(err?.response?.status || 500).send(err);
});
if(!updated) return;
}
if(brew.googleId) {
// If the google id exists after all those actions, exclude the props that are stored in google and aren't needed for rendering the brew items
excludeStubProps(brew);
} else {
// Compress brew text to binary before saving
brew.textBin = zlib.deflateRawSync(brew.text);
// Delete the non-binary text field since it's not needed anymore
brew.text = undefined;
}
brew.updatedAt = new Date();
brew.version += 1;
if(req.account) {
brew.authors = _.uniq(_.concat(brew.authors, req.account.username));
brew.invitedAuthors = _.uniq(_.filter(brew.invitedAuthors, (a)=>req.account.username !== a));
}
// define a function to catch our save errors
const saveError = (err)=>{
console.error(err);
res.status(err.status || 500).send(err.message || 'Unable to save brew to Homebrewery database');
};
let saved;
if(!brew._id) {
// if the brew does not have a stub id, create and save it, then write the new value back to the brew.
saved = await new HomebrewModel(brew).save().catch(saveError);
brew = saved?.toObject();
} else {
// if the brew does have a stub id, update it using the stub id as the key.
brew = _.assign(await HomebrewModel.findOne({ _id: brew._id }), brew);
saved = await brew.save()
.catch(saveError);
}
if(!saved) return;
// Call and wait for afterSave to complete
const after = await afterSave();
if(!after) return;
res.status(200).send(saved);
};
const deleteGoogleBrew = async (account, id, editId, res)=>{
const auth = await GoogleActions.authCheck(account, res);
await GoogleActions.deleteGoogleBrew(auth, id, editId);
return true;
};
const deleteBrew = async (req, res, next)=>{
// Delete an orphaned stub if its Google brew doesn't exist
try {
await getBrew('edit')(req, res, ()=>{});
} catch (err) {
const { id, googleId } = 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;
const { googleId, editId } = brew;
const account = req.account;
const isOwner = account && (brew.authors.length === 0 || brew.authors[0] === account.username);
// If the user is the owner and the file is saved to google, mark the google brew for deletion
const shouldDeleteGoogleBrew = googleId && isOwner;
if(brew._id) {
brew = _.assign(await HomebrewModel.findOne({ _id: brew._id }), brew);
if(account) {
// Remove current user as author
brew.authors = _.pull(brew.authors, account.username);
brew.markModified('authors');
// 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);
}
return { id, googleId };
},
getBrew : (accessType, stubOnly = false)=>{
// Create middleware with the accessType passed in as part of the scope
return async (req, res, next)=>{
// Get relevant IDs for the brew
const { id, googleId } = api.getId(req);
if(brew.authors.length === 0) {
// Delete brew if there are no authors left
await brew.remove()
// Try to find the document in the Homebrewery database -- if it doesn't exist, that's fine.
let stub = await HomebrewModel.get(accessType === 'edit' ? { editId: id } : { shareId: id })
.catch((err)=>{
console.error(err);
throw { status: 500, message: 'Error while removing' };
if(googleId) {
console.warn(`Unable to find document stub for ${accessType}Id ${id}`);
} else {
console.warn(err);
}
});
} else {
if(shouldDeleteGoogleBrew) {
// When there are still authors remaining, we delete the google brew but store the full brew in the Homebrewery database
brew.googleId = undefined;
brew.textBin = zlib.deflateRawSync(brew.text);
brew.text = undefined;
stub = stub?.toObject();
// If there is a google id, try to find the google brew
if(!stubOnly && (googleId || stub?.googleId)) {
let googleError;
const googleBrew = await GoogleActions.getGoogleBrew(googleId || stub?.googleId, id, accessType)
.catch((err)=>{
googleError = err;
});
// Throw any error caught while attempting to retrieve Google brew.
if(googleError) throw googleError;
// 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;
}
const authorsExist = stub?.authors?.length > 0;
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.`;
}
// Otherwise, save the brew with updated author list
await brew.save()
.catch((err)=>{
throw { status: 500, message: err };
});
// 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';
}
// Clean up brew: fill in missing fields with defaults / fix old invalid values
if(stub) {
stub.tags = stub.tags || undefined; // Clear empty strings
stub.renderer = stub.renderer || undefined; // Clear empty strings
stub = _.defaults(stub, DEFAULT_BREW_LOAD); // Fill in blank fields
}
req.brew = stub ?? {};
next();
};
},
mergeBrewText : (brew)=>{
let text = brew.text;
if(brew.style !== undefined) {
text = `\`\`\`css\n` +
`${brew.style || ''}\n` +
`\`\`\`\n\n` +
`${text}`;
}
}
if(shouldDeleteGoogleBrew) {
const deleted = await deleteGoogleBrew(account, googleId, editId, res)
const metadata = _.pick(brew, ['title', 'description', 'tags', 'systems', 'renderer', 'theme']);
text = `\`\`\`metadata\n` +
`${yaml.dump(metadata)}\n` +
`\`\`\`\n\n` +
`${text}`;
return text;
},
getGoodBrewTitle : (text)=>{
const tokens = Markdown.marked.lexer(text);
return (tokens.find((token)=>token.type === 'heading' || token.type === 'paragraph')?.text || 'No Title')
.slice(0, MAX_TITLE_LENGTH);
},
excludePropsFromUpdate : (brew)=>{
// Remove undesired properties
const modified = _.clone(brew);
const propsToExclude = ['_id', 'views', 'lastViewed'];
for (const prop of propsToExclude) {
delete modified[prop];
}
return modified;
},
excludeGoogleProps : (brew)=>{
const modified = _.clone(brew);
const propsToExclude = ['version', 'tags', 'systems', 'published', 'authors', 'owner', 'views', 'thumbnail'];
for (const prop of propsToExclude) {
delete modified[prop];
}
return modified;
},
excludeStubProps : (brew)=>{
const propsToExclude = ['text', 'textBin', 'renderer', 'pageCount'];
for (const prop of propsToExclude) {
brew[prop] = undefined;
}
return brew;
},
beforeNewSave : (account, brew)=>{
if(!brew.title) {
brew.title = api.getGoodBrewTitle(brew.text);
}
brew.authors = (account) ? [account.username] : [];
brew.text = api.mergeBrewText(brew);
_.defaults(brew, DEFAULT_BREW);
},
newGoogleBrew : async (account, brew, res)=>{
const oAuth2Client = GoogleActions.authCheck(account, res);
const newBrew = api.excludeGoogleProps(brew);
return await GoogleActions.newGoogleBrew(oAuth2Client, newBrew);
},
newBrew : async (req, res)=>{
const brew = req.body;
const { saveToGoogle } = req.query;
delete brew.editId;
delete brew.shareId;
delete brew.googleId;
api.beforeNewSave(req.account, brew);
const newHomebrew = new HomebrewModel(brew);
newHomebrew.editId = nanoid(12);
newHomebrew.shareId = nanoid(12);
let googleId, saved;
if(saveToGoogle) {
googleId = await api.newGoogleBrew(req.account, newHomebrew, res)
.catch((err)=>{
console.error(err);
res.status(err?.status || err?.response?.status || 500).send(err?.message || err);
});
if(!googleId) return;
api.excludeStubProps(newHomebrew);
newHomebrew.googleId = googleId;
} else {
// Compress brew text to binary before saving
newHomebrew.textBin = zlib.deflateRawSync(newHomebrew.text);
// Delete the non-binary text field since it's not needed anymore
newHomebrew.text = undefined;
}
saved = await newHomebrew.save()
.catch((err)=>{
console.error(err);
res.status(500).send(err);
console.error(err, err.toString(), err.stack);
throw `Error while creating new brew, ${err.toString()}`;
});
if(!deleted) return;
if(!saved) return;
saved = saved.toObject();
res.status(200).send(saved);
},
updateBrew : async (req, res)=>{
// Initialize brew from request and body, destructure query params, and set the initial value for the after-save method
const brewFromClient = api.excludePropsFromUpdate(req.body);
const brewFromServer = req.brew;
if(brewFromServer.version && brewFromClient.version && brewFromServer.version > brewFromClient.version) {
console.log(`Version mismatch on brew ${brewFromClient.editId}`);
res.setHeader('Content-Type', 'application/json');
return res.status(409).send(JSON.stringify({ message: `The brew has been changed on a different device. Please save your changes elsewhere, refresh, and try again.` }));
}
let brew = _.assign(brewFromServer, brewFromClient);
const googleId = brew.googleId;
const { saveToGoogle, removeFromGoogle } = req.query;
let afterSave = async ()=>true;
brew.text = api.mergeBrewText(brew);
if(brew.googleId && removeFromGoogle) {
// If the google id exists and we're removing it from google, set afterSave to delete the google brew and mark the brew's google id as undefined
afterSave = async ()=>{
return await api.deleteGoogleBrew(req.account, googleId, brew.editId, res)
.catch((err)=>{
console.error(err);
res.status(err?.status || err?.response?.status || 500).send(err.message || err);
});
};
brew.googleId = undefined;
} else if(!brew.googleId && saveToGoogle) {
// If we don't have a google id and the user wants to save to google, create the google brew and set the google id on the brew
brew.googleId = await api.newGoogleBrew(req.account, api.excludeGoogleProps(brew), res)
.catch((err)=>{
console.error(err);
res.status(err.status || err.response.status).send(err.message || err);
});
if(!brew.googleId) return;
} else if(brew.googleId) {
// If the google id exists and no other actions are being performed, update the google brew
const updated = await GoogleActions.updateGoogleBrew(api.excludeGoogleProps(brew))
.catch((err)=>{
console.error(err);
res.status(err?.response?.status || 500).send(err);
});
if(!updated) return;
}
if(brew.googleId) {
// If the google id exists after all those actions, exclude the props that are stored in google and aren't needed for rendering the brew items
api.excludeStubProps(brew);
} else {
// Compress brew text to binary before saving
brew.textBin = zlib.deflateRawSync(brew.text);
// Delete the non-binary text field since it's not needed anymore
brew.text = undefined;
}
brew.updatedAt = new Date();
brew.version = (brew.version || 1) + 1;
if(req.account) {
brew.authors = _.uniq(_.concat(brew.authors, req.account.username));
brew.invitedAuthors = _.uniq(_.filter(brew.invitedAuthors, (a)=>req.account.username !== a));
}
// define a function to catch our save errors
const saveError = (err)=>{
console.error(err);
res.status(err.status || 500).send(err.message || 'Unable to save brew to Homebrewery database');
};
let saved;
if(!brew._id) {
// if the brew does not have a stub id, create and save it, then write the new value back to the brew.
saved = await new HomebrewModel(brew).save().catch(saveError);
} else {
// if the brew does have a stub id, update it using the stub id as the key.
brew = _.assign(await HomebrewModel.findOne({ _id: brew._id }), brew);
saved = await brew.save()
.catch(saveError);
}
if(!saved) return;
// Call and wait for afterSave to complete
const after = await afterSave();
if(!after) return;
res.status(200).send(saved);
},
deleteGoogleBrew : async (account, id, editId, res)=>{
const auth = await GoogleActions.authCheck(account, res);
await GoogleActions.deleteGoogleBrew(auth, id, editId);
return true;
},
deleteBrew : async (req, res, next)=>{
// Delete an orphaned stub if its Google brew doesn't exist
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();
}
let brew = req.brew;
const { googleId, editId } = brew;
const account = req.account;
const isOwner = account && (brew.authors.length === 0 || brew.authors[0] === account.username);
// If the user is the owner and the file is saved to google, mark the google brew for deletion
const shouldDeleteGoogleBrew = googleId && isOwner;
if(brew._id) {
brew = _.assign(await HomebrewModel.findOne({ _id: brew._id }), brew);
if(account) {
// Remove current user as author
brew.authors = _.pull(brew.authors, account.username);
}
if(brew.authors.length === 0) {
// Delete brew if there are no authors left
await HomebrewModel.deleteOne({ _id: brew._id })
.catch((err)=>{
console.error(err);
throw { status: 500, message: 'Error while removing' };
});
} else {
if(shouldDeleteGoogleBrew) {
// When there are still authors remaining, we delete the google brew but store the full brew in the Homebrewery database
brew.googleId = undefined;
brew.textBin = zlib.deflateRawSync(brew.text);
brew.text = undefined;
}
brew.markModified('authors'); //Mongo will not properly update arrays without markModified()
await brew.save()
.catch((err)=>{
throw { status: 500, message: err };
});
}
}
if(shouldDeleteGoogleBrew) {
const deleted = await api.deleteGoogleBrew(account, googleId, editId, res)
.catch((err)=>{
console.error(err);
res.status(500).send(err);
});
if(!deleted) return;
}
res.status(204).send();
}
res.status(204).send();
};
router.post('/api', asyncHandler(newBrew));
router.put('/api/:id', asyncHandler(getBrew('edit', true)), asyncHandler(updateBrew));
router.put('/api/update/:id', asyncHandler(getBrew('edit', true)), asyncHandler(updateBrew));
router.delete('/api/:id', asyncHandler(deleteBrew));
router.get('/api/remove/:id', asyncHandler(deleteBrew));
router.use('/api', require('./middleware/check-client-version.js'));
router.post('/api', asyncHandler(api.newBrew));
router.put('/api/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api.updateBrew));
router.put('/api/update/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api.updateBrew));
router.delete('/api/:id', asyncHandler(api.deleteBrew));
router.get('/api/remove/:id', asyncHandler(api.deleteBrew));
module.exports = {
homebrewApi : router,
getBrew
};
module.exports = api;

766
server/homebrew.api.spec.js Normal file
View File

@@ -0,0 +1,766 @@
/* eslint-disable max-lines */
describe('Tests for api', ()=>{
let api;
let google;
let model;
let hbBrew;
let googleBrew;
let res;
let modelBrew;
let saveFunc;
let markModifiedFunc;
let saved;
beforeEach(()=>{
saved = undefined;
saveFunc = jest.fn(async function() {
saved = { ...this, _id: '1' };
return saved;
});
markModifiedFunc = jest.fn(()=>true);
modelBrew = (brew)=>({
...brew,
save : saveFunc,
markModified : markModifiedFunc,
toObject : function() {
delete this.save;
delete this.toObject;
delete this.markModified;
return this;
}
});
google = require('./googleActions.js');
model = require('./homebrew.model.js').model;
jest.mock('./googleActions.js');
google.authCheck = jest.fn(()=>'client');
google.newGoogleBrew = jest.fn(()=>'id');
google.deleteGoogleBrew = jest.fn(()=>true);
jest.mock('./homebrew.model.js');
model.mockImplementation((brew)=>modelBrew(brew));
res = {
status : jest.fn(()=>res),
send : jest.fn(()=>{})
};
api = require('./homebrew.api');
hbBrew = {
text : `brew text`,
style : 'hello yes i am css',
title : 'some title',
description : 'this is a description',
tags : ['something', 'fun'],
systems : ['D&D 5e'],
lang : 'en',
renderer : 'v3',
theme : 'phb',
published : true,
authors : ['1', '2'],
owner : '1',
thumbnail : '',
_id : 'mongoid',
editId : 'abcdefg',
shareId : 'hijklmnop',
views : 1,
lastViewed : new Date(),
version : 1,
pageCount : 1,
textBin : '',
views : 0
};
googleBrew = {
...hbBrew,
googleId : '12345'
};
});
afterEach(()=>{
jest.restoreAllMocks();
});
describe('getId', ()=>{
it('should return only id if google id is not present', ()=>{
const { id, googleId } = api.getId({
params : {
id : 'abcdefgh'
}
});
expect(id).toEqual('abcdefgh');
expect(googleId).toBeUndefined();
});
it('should return id and google id from request body', ()=>{
const { id, googleId } = api.getId({
params : {
id : 'abcdefgh'
},
body : {
googleId : '12345'
}
});
expect(id).toEqual('abcdefgh');
expect(googleId).toEqual('12345');
});
it('should return id and google id from params', ()=>{
const { id, googleId } = api.getId({
params : {
id : '123456789012abcdefghijkl'
}
});
expect(id).toEqual('abcdefghijkl');
expect(googleId).toEqual('123456789012');
});
});
describe('getBrew', ()=>{
const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew }));
const notFoundError = 'Brew not found in Homebrewery database or Google Drive';
it('returns middleware', ()=>{
const getFn = api.getBrew('share');
expect(getFn).toBeInstanceOf(Function);
});
it('should fetch from mongoose', async ()=>{
const testBrew = { title: 'test brew', authors: [] };
api.getId = jest.fn(()=>({ id: '1', googleId: undefined }));
model.get = jest.fn(()=>toBrewPromise(testBrew));
const fn = api.getBrew('share', true);
const req = { brew: {} };
const next = jest.fn();
await fn(req, null, next);
expect(req.brew).toEqual(testBrew);
expect(next).toHaveBeenCalled();
expect(api.getId).toHaveBeenCalledWith(req);
expect(model.get).toHaveBeenCalledWith({ shareId: '1' });
});
it('should handle mongoose error', async ()=>{
api.getId = jest.fn(()=>({ id: '1', googleId: undefined }));
model.get = jest.fn(()=>new Promise((_, rej)=>rej('Unable to find brew')));
const fn = api.getBrew('share', false);
const req = { brew: {} };
const next = jest.fn();
let err;
try {
await fn(req, null, next);
} catch (e) {
err = e;
}
expect(err).toEqual(notFoundError);
expect(req.brew).toEqual({});
expect(next).not.toHaveBeenCalled();
expect(api.getId).toHaveBeenCalledWith(req);
expect(model.get).toHaveBeenCalledWith({ shareId: '1' });
});
it('changes tags from string to array', async ()=>{
const testBrew = { title: 'test brew', authors: [], tags: '' };
api.getId = jest.fn(()=>({ id: '1', googleId: undefined }));
model.get = jest.fn(()=>toBrewPromise(testBrew));
const fn = api.getBrew('share', true);
const req = { brew: {} };
const next = jest.fn();
await fn(req, null, next);
expect(req.brew.tags).toEqual([]);
expect(next).toHaveBeenCalled();
});
it('throws if 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: {} };
let err;
try {
await fn(req, null, null);
} catch (e) {
err = e;
}
expect(err).toEqual(`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.`);
});
it('does not throw if no authors', async ()=>{
api.getId = jest.fn(()=>({ id: '1', googleId: undefined }));
model.get = jest.fn(()=>toBrewPromise({ title: 'test brew', authors: [] }));
const fn = api.getBrew('edit', true);
const req = { brew: {} };
const next = jest.fn();
await fn(req, null, next);
expect(next).toHaveBeenCalled();
expect(req.brew.title).toEqual('test brew');
expect(req.brew.authors).toEqual([]);
});
it('does not throw if valid 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: 'a' } };
const next = jest.fn();
await fn(req, null, next);
expect(next).toHaveBeenCalled();
expect(req.brew.title).toEqual('test brew');
expect(req.brew.authors).toEqual(['a']);
});
it('fetches google brew if needed', async()=>{
const stubBrew = { title: 'test brew', authors: ['a'] };
const googleBrew = { title: 'test google brew', text: 'brew text' };
api.getId = jest.fn(()=>({ id: '1', googleId: '2' }));
model.get = jest.fn(()=>toBrewPromise(stubBrew));
google.getGoogleBrew = jest.fn(()=>new Promise((res)=>res(googleBrew)));
const fn = api.getBrew('share', false);
const req = { brew: {} };
const next = jest.fn();
await fn(req, null, next);
expect(req.brew).toEqual({
title : 'test google brew',
authors : ['a'],
text : 'brew text',
stubbed : true,
description : '',
editId : undefined,
pageCount : 1,
published : false,
renderer : 'legacy',
lang : 'en',
shareId : undefined,
systems : [],
tags : [],
theme : '5ePHB',
thumbnail : '',
textBin : undefined,
version : undefined,
createdAt : undefined,
gDrive : false,
style : undefined,
trashed : false,
updatedAt : undefined,
views : 0
});
expect(next).toHaveBeenCalled();
expect(api.getId).toHaveBeenCalledWith(req);
expect(model.get).toHaveBeenCalledWith({ shareId: '1' });
expect(google.getGoogleBrew).toHaveBeenCalledWith('2', '1', 'share');
});
});
describe('mergeBrewText', ()=>{
it('should set metadata and no style if it is not present', ()=>{
const result = api.mergeBrewText({
text : `brew`,
title : 'some title',
description : 'this is a description',
tags : ['something', 'fun'],
systems : ['D&D 5e'],
renderer : 'v3',
theme : 'phb',
googleId : '12345'
});
expect(result).toEqual(`\`\`\`metadata
title: some title
description: this is a description
tags:
- something
- fun
systems:
- D&D 5e
renderer: v3
theme: phb
\`\`\`
brew`);
});
it('should set metadata and style', ()=>{
const result = api.mergeBrewText({
text : `brew`,
style : 'hello yes i am css',
title : 'some title',
description : 'this is a description',
tags : ['something', 'fun'],
systems : ['D&D 5e'],
renderer : 'v3',
theme : 'phb',
googleId : '12345'
});
expect(result).toEqual(`\`\`\`metadata
title: some title
description: this is a description
tags:
- something
- fun
systems:
- D&D 5e
renderer: v3
theme: phb
\`\`\`
\`\`\`css
hello yes i am css
\`\`\`
brew`);
});
});
describe('exclusion methods', ()=>{
it('excludePropsFromUpdate removes the correct keys', ()=>{
const sent = Object.assign({}, googleBrew);
const result = api.excludePropsFromUpdate(sent);
expect(sent).toEqual(googleBrew);
expect(result._id).toBeUndefined();
expect(result.views).toBeUndefined();
expect(result.lastViewed).toBeUndefined();
});
it('excludeGoogleProps removes the correct keys', ()=>{
const sent = Object.assign({}, googleBrew);
const result = api.excludeGoogleProps(sent);
expect(sent).toEqual(googleBrew);
expect(result.tags).toBeUndefined();
expect(result.systems).toBeUndefined();
expect(result.published).toBeUndefined();
expect(result.authors).toBeUndefined();
expect(result.owner).toBeUndefined();
expect(result.views).toBeUndefined();
expect(result.thumbnail).toBeUndefined();
expect(result.version).toBeUndefined();
});
it('excludeStubProps removes the correct keys from the original object', ()=>{
const sent = Object.assign({}, googleBrew);
const result = api.excludeStubProps(sent);
expect(sent).not.toEqual(googleBrew);
expect(result.text).toBeUndefined();
expect(result.textBin).toBeUndefined();
expect(result.renderer).toBeUndefined();
expect(result.pageCount).toBeUndefined();
});
});
describe('beforeNewSave', ()=>{
it('sets the title if none', ()=>{
const brew = {
...hbBrew,
title : undefined
};
api.beforeNewSave({}, brew);
expect(brew.title).toEqual('brew text');
});
it('does not override the title if present', ()=>{
const brew = {
...hbBrew,
title : 'test'
};
api.beforeNewSave({}, brew);
expect(brew.title).toEqual('test');
});
it('does not set authors if account missing username', ()=>{
api.beforeNewSave({}, hbBrew);
expect(hbBrew.authors).toEqual([]);
});
it('sets authors if account has username', ()=>{
api.beforeNewSave({ username: 'hi' }, hbBrew);
expect(hbBrew.authors).toEqual(['hi']);
});
it('merges brew text', ()=>{
api.mergeBrewText = jest.fn(()=>'merged');
api.beforeNewSave({}, hbBrew);
expect(api.mergeBrewText).toHaveBeenCalled();
expect(hbBrew.text).toEqual('merged');
});
});
describe('newGoogleBrew', ()=>{
it('should call the correct methods', ()=>{
api.excludeGoogleProps = jest.fn(()=>'newBrew');
const acct = { username: 'test' };
const brew = { title: 'test title' };
api.newGoogleBrew(acct, brew, res);
expect(google.authCheck).toHaveBeenCalledWith(acct, res);
expect(api.excludeGoogleProps).toHaveBeenCalledWith(brew);
expect(google.newGoogleBrew).toHaveBeenCalledWith('client', 'newBrew');
});
});
describe('newBrew', ()=>{
it('should set up a default brew via Homebrew model', async ()=>{
await api.newBrew({ body: { text: 'asdf' }, query: {}, account: { username: 'test user' } }, res);
expect(res.status).toHaveBeenCalledWith(200);
expect(res.send).toHaveBeenCalledWith({
_id : '1',
authors : ['test user'],
createdAt : undefined,
description : '',
editId : expect.any(String),
gDrive : false,
pageCount : 1,
published : false,
renderer : 'V3',
lang : 'en',
shareId : expect.any(String),
style : undefined,
systems : [],
tags : [],
text : undefined,
textBin : expect.objectContaining({}),
theme : '5ePHB',
thumbnail : '',
title : 'asdf',
trashed : false,
updatedAt : undefined,
views : 0
});
});
it('should remove edit/share/google ids', async ()=>{
await api.newBrew({ body: { editId: '1234', shareId: '1234', googleId: '1234', text: 'asdf', title: '' }, query: {} }, res);
expect(res.status).toHaveBeenCalledWith(200);
expect(res.send).toHaveBeenCalled();
const sent = res.send.mock.calls[0][0];
expect(sent.editId).not.toEqual('1234');
expect(sent.shareId).not.toEqual('1234');
expect(sent.googleId).toBeUndefined();
});
it('should handle mongo error', async ()=>{
saveFunc = jest.fn(async function() {
throw 'err';
});
model.mockImplementation((brew)=>modelBrew(brew));
let err;
try {
await api.newBrew({ body: { editId: '1234', shareId: '1234', googleId: '1234', text: 'asdf', title: '' }, query: {} }, res);
} catch (e) {
err = e;
}
expect(res.send).not.toHaveBeenCalled();
expect(err).not.toBeUndefined();
});
it('should save to google if requested', async()=>{
await api.newBrew({ body: { text: 'asdf', title: '' }, query: { saveToGoogle: true }, account: { username: 'test user' } }, res);
expect(google.newGoogleBrew).toHaveBeenCalled();
expect(res.status).toHaveBeenCalledWith(200);
expect(res.send).toHaveBeenCalledWith({
_id : '1',
authors : ['test user'],
createdAt : undefined,
description : '',
editId : expect.any(String),
gDrive : false,
pageCount : undefined,
published : false,
renderer : undefined,
lang : 'en',
shareId : expect.any(String),
googleId : expect.any(String),
style : undefined,
systems : [],
tags : [],
text : undefined,
textBin : undefined,
theme : '5ePHB',
thumbnail : '',
title : 'asdf',
trashed : false,
updatedAt : undefined,
views : 0
});
});
it('should handle google error', async()=>{
google.newGoogleBrew = jest.fn(()=>{
throw 'err';
});
await api.newBrew({ body: { text: 'asdf', title: '' }, query: { saveToGoogle: true }, account: { username: 'test user' } }, res);
expect(res.status).toHaveBeenCalledWith(500);
expect(res.send).toHaveBeenCalledWith('err');
});
});
describe('deleteGoogleBrew', ()=>{
it('should check auth and delete brew', async ()=>{
const result = await api.deleteGoogleBrew({ username: 'test user' }, 'id', 'editId', res);
expect(result).toBe(true);
expect(google.authCheck).toHaveBeenCalledWith({ username: 'test user' }, expect.objectContaining({}));
expect(google.deleteGoogleBrew).toHaveBeenCalledWith('client', 'id', 'editId');
});
});
describe('deleteBrew', ()=>{
it('should handle case where fetching the brew returns an error', async ()=>{
api.getBrew = jest.fn(()=>async ()=>{ throw 'err'; });
api.getId = jest.fn(()=>({ id: '1', googleId: '2' }));
model.deleteOne = jest.fn(async ()=>{});
const next = jest.fn(()=>{});
await api.deleteBrew(null, null, next);
expect(next).toHaveBeenCalled();
expect(model.deleteOne).toHaveBeenCalledWith({ editId: '1' });
});
it('should delete if no authors', async ()=>{
const brew = {
...hbBrew,
authors : []
};
api.getBrew = jest.fn(()=>async (req)=>{
req.brew = brew;
});
model.findOne = jest.fn(async ()=>modelBrew(brew));
model.deleteOne = jest.fn(async ()=>{});
const req = {};
await api.deleteBrew(req, res);
expect(api.getBrew).toHaveBeenCalled();
expect(model.findOne).toHaveBeenCalled();
expect(model.deleteOne).toHaveBeenCalled();
});
it('should throw on delete error', async ()=>{
const brew = {
...hbBrew,
authors : []
};
api.getBrew = jest.fn(()=>async (req)=>{
req.brew = brew;
});
model.findOne = jest.fn(async ()=>modelBrew(brew));
model.deleteOne = jest.fn(async ()=>{ throw 'err'; });
const req = {};
let err;
try {
await api.deleteBrew(req, res);
} catch (e) {
err = e;
}
expect(err).not.toBeUndefined();
expect(api.getBrew).toHaveBeenCalled();
expect(model.findOne).toHaveBeenCalled();
expect(model.deleteOne).toHaveBeenCalled();
});
it('should delete when one author', async ()=>{
const brew = {
...hbBrew,
authors : ['test']
};
api.getBrew = jest.fn(()=>async (req)=>{
req.brew = brew;
});
model.findOne = jest.fn(async ()=>modelBrew(brew));
model.deleteOne = jest.fn(async ()=>{});
const req = { account: { username: 'test' } };
await api.deleteBrew(req, res);
expect(api.getBrew).toHaveBeenCalled();
expect(model.findOne).toHaveBeenCalled();
expect(model.deleteOne).toHaveBeenCalled();
});
it('should remove one author when multiple present', async ()=>{
const brew = {
...hbBrew,
authors : ['test', 'test2']
};
api.getBrew = jest.fn(()=>async (req)=>{
req.brew = brew;
});
model.findOne = jest.fn(async ()=>modelBrew(brew));
model.deleteOne = jest.fn(async ()=>{});
const req = { account: { username: 'test' } };
await api.deleteBrew(req, res);
expect(api.getBrew).toHaveBeenCalled();
expect(markModifiedFunc).toHaveBeenCalled();
expect(model.findOne).toHaveBeenCalled();
expect(model.deleteOne).not.toHaveBeenCalled();
expect(saveFunc).toHaveBeenCalled();
expect(saved.authors).toEqual(['test2']);
});
it('should handle save error', async ()=>{
const brew = {
...hbBrew,
authors : ['test', 'test2']
};
api.getBrew = jest.fn(()=>async (req)=>{
req.brew = brew;
});
model.findOne = jest.fn(async ()=>modelBrew(brew));
model.deleteOne = jest.fn(async ()=>{});
saveFunc = jest.fn(async ()=>{ throw 'err'; });
const req = { account: { username: 'test' } };
let err;
try {
await api.deleteBrew(req, res);
} catch (e) {
err = e;
}
expect(err).not.toBeUndefined();
expect(api.getBrew).toHaveBeenCalled();
expect(model.findOne).toHaveBeenCalled();
expect(model.deleteOne).not.toHaveBeenCalled();
expect(saveFunc).toHaveBeenCalled();
});
it('should delete google brew', async ()=>{
const brew = {
...googleBrew,
authors : ['test']
};
api.getBrew = jest.fn(()=>async (req)=>{
req.brew = brew;
});
model.findOne = jest.fn(async ()=>modelBrew(brew));
model.deleteOne = jest.fn(async ()=>{});
api.deleteGoogleBrew = jest.fn(async ()=>true);
const req = { account: { username: 'test' } };
await api.deleteBrew(req, res);
expect(api.getBrew).toHaveBeenCalled();
expect(model.findOne).toHaveBeenCalled();
expect(model.deleteOne).toHaveBeenCalled();
expect(api.deleteGoogleBrew).toHaveBeenCalled();
});
it('should handle google brew delete error', async ()=>{
const brew = {
...googleBrew,
authors : ['test']
};
api.getBrew = jest.fn(()=>async (req)=>{
req.brew = brew;
});
model.findOne = jest.fn(async ()=>modelBrew(brew));
model.deleteOne = jest.fn(async ()=>{});
api.deleteGoogleBrew = jest.fn(async ()=>{
throw 'err';
});
const req = { account: { username: 'test' } };
await api.deleteBrew(req, res);
expect(api.getBrew).toHaveBeenCalled();
expect(model.findOne).toHaveBeenCalled();
expect(model.deleteOne).toHaveBeenCalled();
expect(api.deleteGoogleBrew).toHaveBeenCalled();
});
it('should delete google brew and retain stub when multiple authors and owner request deletion', async ()=>{
const brew = {
...googleBrew,
authors : ['test', 'test2']
};
api.getBrew = jest.fn(()=>async (req)=>{
req.brew = brew;
});
model.findOne = jest.fn(async ()=>modelBrew(brew));
model.deleteOne = jest.fn(async ()=>{});
api.deleteGoogleBrew = jest.fn(async ()=>true);
const req = { account: { username: 'test' } };
await api.deleteBrew(req, res);
expect(api.getBrew).toHaveBeenCalled();
expect(markModifiedFunc).toHaveBeenCalled();
expect(model.findOne).toHaveBeenCalled();
expect(model.deleteOne).not.toHaveBeenCalled();
expect(api.deleteGoogleBrew).toHaveBeenCalled();
expect(saveFunc).toHaveBeenCalled();
expect(saved.authors).toEqual(['test2']);
expect(saved.googleId).toEqual(undefined);
expect(saved.text).toEqual(undefined);
expect(saved.textBin).not.toEqual(undefined);
});
it('should retain google brew and update stub when multiple authors and extra author requests deletion', async ()=>{
const brew = {
...googleBrew,
authors : ['test', 'test2']
};
api.getBrew = jest.fn(()=>async (req)=>{
req.brew = brew;
});
model.findOne = jest.fn(async ()=>modelBrew(brew));
model.deleteOne = jest.fn(async ()=>{});
api.deleteGoogleBrew = jest.fn(async ()=>true);
const req = { account: { username: 'test2' } };
await api.deleteBrew(req, res);
expect(api.getBrew).toHaveBeenCalled();
expect(model.findOne).toHaveBeenCalled();
expect(model.deleteOne).not.toHaveBeenCalled();
expect(api.deleteGoogleBrew).not.toHaveBeenCalled();
expect(saveFunc).toHaveBeenCalled();
expect(saved.authors).toEqual(['test']);
expect(saved.googleId).toEqual(brew.googleId);
});
});
});

View File

@@ -15,6 +15,7 @@ const HomebrewSchema = mongoose.Schema({
description : { type: String, default: '' },
tags : [String],
systems : [String],
lang : { type: String, default: 'en' },
renderer : { type: String, default: '' },
authors : [String],
invitedAuthors : [String],
@@ -39,32 +40,24 @@ HomebrewSchema.statics.increaseView = async function(query) {
return brew;
};
HomebrewSchema.statics.get = function(query, fields=null){
return new Promise((resolve, reject)=>{
Homebrew.find(query, fields, null, (err, brews)=>{
if(err || !brews.length) return reject('Can not find brew');
if(!_.isNil(brews[0].textBin)) { // Uncompress zipped text field
unzipped = zlib.inflateRawSync(brews[0].textBin);
brews[0].text = unzipped.toString();
}
if(!brews[0].renderer)
brews[0].renderer = 'legacy';
return resolve(brews[0]);
});
});
HomebrewSchema.statics.get = async function(query, fields=null){
const brew = await Homebrew.findOne(query, fields).orFail()
.catch((error)=>{throw 'Can not find brew';});
if(!_.isNil(brew.textBin)) { // Uncompress zipped text field
unzipped = zlib.inflateRawSync(brew.textBin);
brew.text = unzipped.toString();
}
return brew;
};
HomebrewSchema.statics.getByUser = function(username, allowAccess=false, fields=null){
return new Promise((resolve, reject)=>{
const query = { authors: username, published: true };
if(allowAccess){
delete query.published;
}
Homebrew.find(query, fields).lean().exec((err, brews)=>{ //lean() converts results to JSObjects
if(err) return reject('Can not find brew');
return resolve(brews);
});
});
HomebrewSchema.statics.getByUser = async function(username, allowAccess=false, fields=null){
const query = { authors: username, published: true };
if(allowAccess){
delete query.published;
}
const brews = await Homebrew.find(query, fields).lean().exec() //lean() converts results to JSObjects
.catch((error)=>{throw 'Can not find brews';});
return brews;
};
const Homebrew = mongoose.model('Homebrew', HomebrewSchema);

View File

@@ -0,0 +1,12 @@
module.exports = (req, res, next)=>{
const userVersion = req.get('Homebrewery-Version');
const version = require('../../package.json').version;
if(userVersion != version) {
return res.status(412).send({
message : `Client version ${userVersion} is out of date. Please save your changes elsewhere and refresh to pick up client version ${version}.`
});
}
next();
};

View File

@@ -0,0 +1,12 @@
module.exports = (req, res, next)=>{
const isImageRequest = req.get('Accept')?.split(',')
?.filter((h)=>!h.includes('q='))
?.every((h)=>/image\/.*/.test(h));
if(isImageRequest) {
return res.status(406).send({
message : 'Request for image at this URL is not supported'
});
}
next();
};

View File

@@ -0,0 +1,41 @@
const contentNegotiationMiddleware = require('./content-negotiation.js');
describe('content-negotiation-middleware', ()=>{
let request;
let response;
let next;
beforeEach(()=>{
request = {
get : function(key) {
return this[key];
}
};
response = {
status : jest.fn(()=>response),
send : jest.fn(()=>{})
};
next = jest.fn();
});
it('should return 406 on image request', ()=>{
contentNegotiationMiddleware({
Accept : 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8',
...request
}, response);
expect(response.status).toHaveBeenLastCalledWith(406);
expect(response.send).toHaveBeenCalledWith({
message : 'Request for image at this URL is not supported'
});
});
it('should call next on non-image request', ()=>{
contentNegotiationMiddleware({
Accept : 'text,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8',
...request
}, response, next);
expect(next).toHaveBeenCalled();
});
});

View File

@@ -97,11 +97,14 @@ const CodeEditor = createClass({
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,
@@ -171,6 +174,19 @@ const CodeEditor = createClass({
this.updateSize();
},
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) {
const selection = this.codeMirror.getSelection();
const header = Array(number).fill('#').join('');

View File

@@ -2,6 +2,7 @@
const _ = require('lodash');
const Marked = require('marked');
const MarkedExtendedTables = require('marked-extended-tables');
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
@@ -134,7 +135,7 @@ const mustacheInjectInline = {
const match = inlineRegex.exec(src);
if(match) {
const lastToken = tokens[tokens.length - 1];
if(!lastToken)
if(!lastToken || lastToken.type == 'mustacheInjectInline')
return false;
const tags = ` ${processStyleTags(match[1])}`;
@@ -169,7 +170,7 @@ const mustacheInjectBlock = {
const match = inlineRegex.exec(src);
if(match) {
const lastToken = tokens[tokens.length - 1];
if(!lastToken)
if(!lastToken || lastToken.type == 'mustacheInjectBlock')
return false;
lastToken.originalType = 'mustacheInjectBlock';
@@ -236,10 +237,49 @@ const definitionLists = {
}
};
const MarkedSmartyPantsLite = ()=>{
return {
tokenizer : {
inlineText(src) {
// don't escape inlineText
const cap = this.rules.inline.text.exec(src);
/* istanbul ignore next */
if(!cap) {
// should never happen
return;
}
const text = cap[0]
// em-dashes
.replace(/---/g, '\u2014')
// en-dashes
.replace(/--/g, '\u2013')
// opening singles
.replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
// closing singles & apostrophes
.replace(/'/g, '\u2019')
// opening doubles
.replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
// closing doubles
.replace(/"/g, '\u201d')
// ellipses
.replace(/\.{3}/g, '\u2026');
return {
type : 'text',
raw : cap[0],
text : text
};
}
}
};
};
Marked.use({ extensions: [mustacheSpans, mustacheDivs, mustacheInjectInline, definitionLists] });
Marked.use(MarkedExtendedTables());
Marked.use(mustacheInjectBlock);
Marked.use({ 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) {
@@ -347,10 +387,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),
{ renderer: renderer }
);
return Marked.parse(sanatizeScriptTags(rawBrewText));
},
validate : (rawBrewText)=>{

View File

@@ -29,7 +29,7 @@ const Nav = {
section : createClass({
displayName : 'Nav.section',
render : function(){
return <div className='navSection'>
return <div className={`navSection ${this.props.className ?? ''}`}>
{this.props.children}
</div>;
}

View File

@@ -13,6 +13,7 @@ nav{
position : relative;
display : flex;
justify-content : space-between;
z-index : 2;
}
.navSection{
display : flex;

View File

@@ -22,7 +22,7 @@
vertical-align : middle;
text-align : center;
i{
display : block;
display : block !important;
margin : 10px 0px;
font-size : 6px;
color : #666;

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

@@ -13,3 +13,9 @@ test('Processes the markdown within an HTML block if its just a class wrapper',
const rendered = Markdown.render(source);
expect(rendered).toBe('<div> <p><em>Bold text</em></p>\n </div>');
});
test('Check markdown is using the custom renderer; specifically that it adds target=_self attribute to internal links in HTML blocks', function() {
const source = '<div>[Has _self Attribute?](#p1)</div>';
const rendered = Markdown.render(source);
expect(rendered).toBe('<div> <p><a href="#p1" target="_self">Has _self Attribute?</a></p>\n </div>');
});

View File

@@ -1,128 +0,0 @@
/* eslint-disable max-lines */
const Markdown = require('naturalcrit/markdown.js');
test('Renders a mustache span with text only', function() {
const source = '{{ text}}';
const rendered = Markdown.render(source);
expect(rendered).toBe('<span class="inline-block ">text</span>');
});
test('Renders a mustache span with text only, but with spaces', function() {
const source = '{{ this is a text}}';
const rendered = Markdown.render(source);
expect(rendered).toBe('<span class="inline-block ">this is a text</span>');
});
test('Renders an empty mustache span', function() {
const source = '{{}}';
const rendered = Markdown.render(source);
expect(rendered).toBe('<span class="inline-block "></span>');
});
test('Renders a mustache span with just a space', function() {
const source = '{{ }}';
const rendered = Markdown.render(source);
expect(rendered).toBe('<span class="inline-block "></span>');
});
test('Renders a mustache span with a few spaces only', function() {
const source = '{{ }}';
const rendered = Markdown.render(source);
expect(rendered).toBe('<span class="inline-block "></span>');
});
test('Renders a mustache span with text and class', function() {
const source = '{{my-class text}}';
const rendered = Markdown.render(source);
// FIXME: why do we have those two extra spaces after closing "?
expect(rendered).toBe('<span class="inline-block my-class" >text</span>');
});
test('Renders a mustache span with text and two classes', function() {
const source = '{{my-class,my-class2 text}}';
const rendered = Markdown.render(source);
// FIXME: why do we have those two extra spaces after closing "?
expect(rendered).toBe('<span class="inline-block my-class my-class2" >text</span>');
});
test('Renders a mustache span with text with spaces and class', function() {
const source = '{{my-class this is a text}}';
const rendered = Markdown.render(source);
// FIXME: why do we have those two extra spaces after closing "?
expect(rendered).toBe('<span class="inline-block my-class" >this is a text</span>');
});
test('Renders a mustache span with text and id', function() {
const source = '{{#my-span text}}';
const rendered = Markdown.render(source);
// FIXME: why do we have that one extra space after closing "?
expect(rendered).toBe('<span class="inline-block " id="my-span" >text</span>');
});
test('Renders a mustache span with text and two ids', function() {
const source = '{{#my-span,#my-favorite-span text}}';
const rendered = Markdown.render(source);
// FIXME: do we need to report an error here somehow?
expect(rendered).toBe('<span class="inline-block " id="my-span" >text</span>');
});
test('Renders a mustache span with text and css property', function() {
const source = '{{color:red text}}';
const rendered = Markdown.render(source);
expect(rendered).toBe('<span class="inline-block " style="color:red;">text</span>');
});
test('Renders a mustache span with text and two css properties', function() {
const source = '{{color:red,padding:5px text}}';
const rendered = Markdown.render(source);
expect(rendered).toBe('<span class="inline-block " style="color:red; padding:5px;">text</span>');
});
test('Renders a mustache span with text and css property which contains quotes', function() {
const source = '{{font:"trebuchet ms" text}}';
const rendered = Markdown.render(source);
// FIXME: is it correct to remove quotes surrounding css property value?
expect(rendered).toBe('<span class="inline-block " style="font:trebuchet ms;">text</span>');
});
test('Renders a mustache span with text and two css properties which contains quotes', function() {
const source = '{{font:"trebuchet ms",padding:"5px 10px" text}}';
const rendered = Markdown.render(source);
expect(rendered).toBe('<span class="inline-block " style="font:trebuchet ms; padding:5px 10px;">text</span>');
});
test('Renders a mustache span with text with quotes and css property which contains quotes', function() {
const source = '{{font:"trebuchet ms" text "with quotes"}}';
const rendered = Markdown.render(source);
expect(rendered).toBe('<span class="inline-block " style="font:trebuchet ms;">text “with quotes”</span>');
});
test('Renders a mustache span with text, id, class and a couple of css properties', function() {
const source = '{{pen,#author,color:orange,font-family:"trebuchet ms" text}}';
const rendered = Markdown.render(source);
expect(rendered).toBe('<span class="inline-block pen" id="author" style="color:orange; font-family:trebuchet ms;">text</span>');
});
// TODO: add tests for ID with accordance to CSS spec:
//
// From https://drafts.csswg.org/selectors/#id-selectors:
//
// > An ID selector consists of a “number sign” (U+0023, #) immediately followed by the ID value, which must be a CSS identifier.
//
// From: https://www.w3.org/TR/CSS21/syndata.html#value-def-identifier:
//
// > In CSS, identifiers (including element names, classes, and IDs in selectors) can contain only the characters [a-zA-Z0-9]
// > and ISO 10646 characters U+00A0 and higher, plus the hyphen (-) and the underscore (_);
// > they cannot start with a digit, two hyphens, or a hyphen followed by a digit.
// > Identifiers can also contain escaped characters and any ISO 10646 character as a numeric code (see next item).
// > For instance, the identifier "B&W?" may be written as "B\&W\?" or "B\26 W\3F".
// > Note that Unicode is code-by-code equivalent to ISO 10646 (see [UNICODE] and [ISO10646]).
// TODO: add tests for class with accordance to CSS spec:
//
// From: https://drafts.csswg.org/selectors/#class-html:
//
// > The class selector is given as a full stop (. U+002E) immediately followed by an identifier.

View File

@@ -0,0 +1,375 @@
/* eslint-disable max-lines */
const dedent = require('dedent-tabs').default;
const Markdown = require('naturalcrit/markdown.js');
// Marked.js adds line returns after closing tags on some default tokens.
// This removes those line returns for comparison sake.
String.prototype.trimReturns = function(){
return this.replace(/\r?\n|\r/g, '');
};
// Adding `.failing()` method to `describe` or `it` will make failing tests "pass" as long as they continue to fail.
// Remove the `.failing()` method once you have fixed the issue.
describe('Inline: When using the Inline syntax {{ }}', ()=>{
it.failing('Renders a mustache span with text only', function() {
const source = '{{ text}}';
const rendered = Markdown.render(source);
// FIXME: adds extra \s after class names
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block">text</span>');
});
it.failing('Renders a mustache span with text only, but with spaces', function() {
const source = '{{ this is a text}}';
const rendered = Markdown.render(source);
// FIXME: adds extra \s after class names
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block">this is a text</span>');
});
it.failing('Renders an empty mustache span', function() {
const source = '{{}}';
const rendered = Markdown.render(source);
// FIXME: adds extra \s after class names
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block"></span>');
});
it.failing('Renders a mustache span with just a space', function() {
const source = '{{ }}';
const rendered = Markdown.render(source);
// FIXME: adds extra \s after class names
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block"></span>');
});
it.failing('Renders a mustache span with a few spaces only', function() {
const source = '{{ }}';
const rendered = Markdown.render(source);
// FIXME: adds extra \s after class names
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block"></span>');
});
it.failing('Renders a mustache span with text and class', function() {
const source = '{{my-class text}}';
const rendered = Markdown.render(source);
// FIXME: adds two extra \s before closing `>` in opening tag.
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block my-class">text</span>');
});
it.failing('Renders a mustache span with text and two classes', function() {
const source = '{{my-class,my-class2 text}}';
const rendered = Markdown.render(source);
// FIXME: adds two extra \s before closing `>` in opening tag.
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block my-class my-class2">text</span>');
});
it.failing('Renders a mustache span with text with spaces and class', function() {
const source = '{{my-class this is a text}}';
const rendered = Markdown.render(source);
// FIXME: adds two extra \s before closing `>` in opening tag
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block my-class">this is a text</span>');
});
it.failing('Renders a mustache span with text and id', function() {
const source = '{{#my-span text}}';
const rendered = Markdown.render(source);
// FIXME: adds extra \s before closing `>` in opening tag, and another after class names
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block" id="my-span">text</span>');
});
it.failing('Renders a mustache span with text and two ids', function() {
const source = '{{#my-span,#my-favorite-span text}}';
const rendered = Markdown.render(source);
// FIXME: adds extra \s before closing `>` in opening tag, and another after class names
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block" id="my-span">text</span>');
});
it.failing('Renders a mustache span with text and css property', function() {
const source = '{{color:red text}}';
const rendered = Markdown.render(source);
// FIXME: adds extra \s after class names
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block" style="color:red;">text</span>');
});
it.failing('Renders a mustache span with text and two css properties', function() {
const source = '{{color:red,padding:5px text}}';
const rendered = Markdown.render(source);
// FIXME: adds extra \s after class names
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block" style="color:red; padding:5px;">text</span>');
});
it.failing('Renders a mustache span with text and css property which contains quotes', function() {
const source = '{{font-family:"trebuchet ms" text}}';
const rendered = Markdown.render(source);
// FIXME: adds extra \s after class names
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block" style="font-family:trebuchet ms;">text</span>');
});
it.failing('Renders a mustache span with text and two css properties which contains quotes', function() {
const source = '{{font-family:"trebuchet ms",padding:"5px 10px" text}}';
const rendered = Markdown.render(source);
// FIXME: adds extra \s after class names
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block" style="font-family:trebuchet ms; padding:5px 10px;">text</span>');
});
it.failing('Renders a mustache span with text with quotes and css property which contains quotes', function() {
const source = '{{font-family:"trebuchet ms" text "with quotes"}}';
const rendered = Markdown.render(source);
// FIXME: adds extra \s after class names
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block" style="font-family:trebuchet ms;">text “with quotes”</span>');
});
it('Renders a mustache span with text, id, class and a couple of css properties', function() {
const source = '{{pen,#author,color:orange,font-family:"trebuchet ms" text}}';
const rendered = Markdown.render(source);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block pen" id="author" style="color:orange; font-family:trebuchet ms;">text</span>');
});
});
// BLOCK SYNTAX
describe(`Block: When using the Block syntax {{tags\\ntext\\n}}`, ()=>{
it.failing('Renders a div with text only', function() {
const source = dedent`{{
text
}}`;
const rendered = Markdown.render(source).trimReturns();
// FIXME: adds extra \s after class names
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block"><p>text</p></div>`);
});
it.failing('Renders an empty div', function() {
const source = dedent`{{
}}`;
const rendered = Markdown.render(source).trimReturns();
// FIXME: adds extra \s after class names
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block"></div>`);
});
it('Renders a single paragraph with opening and closing brackets', function() {
const source = dedent`{{
}}`;
const rendered = Markdown.render(source).trimReturns();
// this actually renders in HB as '{{ }}'...
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<p>{{}}</p>`);
});
it.failing('Renders a div with a single class', function() {
const source = dedent`{{cat
}}`;
const rendered = Markdown.render(source).trimReturns();
// FIXME: adds two extra \s before closing `>` in opening tag
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block cat"></div>`);
});
it.failing('Renders a div with a single class and text', function() {
const source = dedent`{{cat
Sample text.
}}`;
const rendered = Markdown.render(source).trimReturns();
// FIXME: adds two extra \s before closing `>` in opening tag
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block cat"><p>Sample text.</p></div>`);
});
it.failing('Renders a div with two classes and text', function() {
const source = dedent`{{cat,dog
Sample text.
}}`;
const rendered = Markdown.render(source).trimReturns();
// FIXME: adds two extra \s before closing `>` in opening tag
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block cat dog"><p>Sample text.</p></div>`);
});
it.failing('Renders a div with a style and text', function() {
const source = dedent`{{color:red
Sample text.
}}`;
const rendered = Markdown.render(source).trimReturns();
// FIXME: adds two extra \s before closing `>` in opening tag
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block" style="color:red;"><p>Sample text.</p></div>`);
});
it.failing('Renders a div with a class, style and text', function() {
const source = dedent`{{cat,color:red
Sample text.
}}`;
const rendered = Markdown.render(source).trimReturns();
// FIXME: adds extra \s after the class attribute
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block cat" style="color:red;"><p>Sample text.</p></div>`);
});
it('Renders a div with an ID, class, style and text (different order)', function() {
const source = dedent`{{color:red,cat,#dog
Sample text.
}}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block cat" id="dog" style="color:red;"><p>Sample text.</p></div>`);
});
it.failing('Renders a div with a single ID', function() {
const source = dedent`{{#cat,#dog
Sample text.
}}`;
const rendered = Markdown.render(source).trimReturns();
// FIXME: adds extra \s before closing `>` in opening tag, and another after class names
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block" id="cat"><p>Sample text.</p></div>`);
});
});
// MUSTACHE INJECTION SYNTAX
describe('Injection: When an injection tag follows an element', ()=>{
// FIXME: Most of these fail because injections currently replace attributes, rather than append to. Or just minor extra whitespace issues.
describe('and that element is an inline-block', ()=>{
it.failing('Renders a span "text" with no injection', function() {
const source = '{{ text}}{}';
const rendered = Markdown.render(source);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block">text</span>');
});
it.failing('Renders a span "text" with injected Class name', function() {
const source = '{{ text}}{ClassName}';
const rendered = Markdown.render(source);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block ClassName">text</span>');
});
it.failing('Renders a span "text" with injected style', function() {
const source = '{{ text}}{color:red}';
const rendered = Markdown.render(source);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block" style="color:red;">text</span>');
});
it.failing('Renders a span "text" with two injected styles', function() {
const source = '{{ text}}{color:red,background:blue}';
const rendered = Markdown.render(source);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block" style="color:red; background:blue;">text</span>');
});
it.failing('Renders an emphasis element with injected Class name', function() {
const source = '*emphasis*{big}';
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<p><em class="big">emphasis</em></p>');
});
it.failing('Renders a code element with injected style', function() {
const source = '`code`{background:gray}';
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<p><code style="background:gray;">code</code></p>');
});
it.failing('Renders an image element with injected style', function() {
const source = '![alt text](http://i.imgur.com/hMna6G0.png){position:absolute}';
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<p><img src="http://i.imgur.com/hMna6G0.png" alt="homebrew mug" style="position:absolute;"></p>');
});
it.failing('Renders an element modified by only the first of two consecutive injections', function() {
const source = '{{ text}}{color:red}{background:blue}';
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<p><span class="inline-block" style="color:red;">text</span>{background:blue}</p>');
});
});
describe('and that element is a block', ()=>{
it.failing('renders a div "text" with no injection', function() {
const source = '{{\ntext\n}}\n{}';
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<div class="block"><p>text</p></div>');
});
it.failing('renders a div "text" with injected Class name', function() {
const source = '{{\ntext\n}}\n{ClassName}';
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<div class="block ClassName"><p>text</p></div>');
});
it.failing('renders a div "text" with injected style', function() {
const source = '{{\ntext\n}}\n{color:red}';
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<div class="block" style="color:red;"><p>text</p></div>');
});
it.failing('renders a div "text" with two injected styles', function() {
const source = dedent`{{
text
}}
{color:red,background:blue}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<div class="block" style="color:red; background:blue;"><p>text</p></div>');
});
it.failing('renders an h2 header "text" with injected class name', function() {
const source = dedent`## text
{ClassName}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<h2 class="ClassName">text</h2>');
});
it.failing('renders a table with injected class name', function() {
const source = dedent`| Experience Points | Level |
|:------------------|:-----:|
| 0 | 1 |
| 300 | 2 |
{ClassName}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<table class="ClassName"><thead><tr><th align=left>Experience Points</th><th align=center>Level</th></tr></thead><tbody><tr><td align=left>0</td><td align=center>1</td></tr><tr><td align=left>300</td><td align=center>2</td></tr></tbody></table>`);
});
// it('renders a list with with a style injected into the <ul> tag', function() {
// const source = dedent`- Cursed Ritual of Bad Hair
// - Eliminate Vindictiveness in Gym Teacher
// - Ultimate Rite of the Confetti Angel
// - Dark Chant of the Dentists
// - Divine Spell of Crossdressing
// {color:red}`;
// const rendered = Markdown.render(source).trimReturns();
// expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`...`); // FIXME: expect this to be injected into <ul>? Currently injects into last <li>
// });
it.failing('renders an h2 header "text" with injected class name, and "secondInjection" as regular text on the next line.', function() {
const source = dedent`## text
{ClassName}
{secondInjection}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<h2 class="ClassName">text</h2><p>{secondInjection}</p>');
});
it.failing('renders a div nested into another div, the inner with class=innerDiv and the other class=outerDiv', function() {
const source = dedent`{{
outer text
{{
inner text
}}
{innerDiv}
}}
{outerDiv}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<div class="block outerDiv"><p>outer text</p><div class="block innerDiv"><p>inner text</p></div></div>');
});
});
});
// TODO: add tests for ID with accordance to CSS spec:
//
// From https://drafts.csswg.org/selectors/#id-selectors:
//
// > An ID selector consists of a “number sign” (U+0023, #) immediately followed by the ID value, which must be a CSS identifier.
//
// From: https://www.w3.org/TR/CSS21/syndata.html#value-def-identifier:
//
// > In CSS, identifiers (including element names, classes, and IDs in selectors) can contain only the characters [a-zA-Z0-9]
// > and ISO 10646 characters U+00A0 and higher, plus the hyphen (-) and the underscore (_);
// > they cannot start with a digit, two hyphens, or a hyphen followed by a digit.
// > Identifiers can also contain escaped characters and any ISO 10646 character as a numeric code (see next item).
// > For instance, the identifier "B&W?" may be written as "B\&W\?" or "B\26 W\3F".
// > Note that Unicode is code-by-code equivalent to ISO 10646 (see [UNICODE] and [ISO10646]).
// TODO: add tests for class with accordance to CSS spec:
//
// From: https://drafts.csswg.org/selectors/#class-html:
//
// > The class selector is given as a full stop (. U+002E) immediately followed by an identifier.

View File

@@ -262,6 +262,7 @@ body {
//Full Width
hr+hr+blockquote{
.useColumns(0.96);
column-fill : balance;
}
//*****************************
// * FOOTER

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 KiB

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;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 782 KiB

View File

@@ -3,9 +3,11 @@
const MagicGen = require('./snippets/magic.gen.js');
const ClassTableGen = require('./snippets/classtable.gen.js');
const MonsterBlockGen = require('./snippets/monsterblock.gen.js');
const scriptGen = require('./snippets/script.gen.js');
const 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;
@@ -31,6 +33,12 @@ module.exports = [
name : 'Table of Contents',
icon : 'fas fa-book',
gen : TableOfContentsGen
},
{
name : 'Index',
icon : 'fas fa-bars',
gen : indexGen,
experimental : true
}
]
},
@@ -169,9 +177,28 @@ module.exports = [
gen : MonsterBlockGen.monster('monster,frame,wide', 4),
},
{
name : 'Cover Page',
icon : 'fas fa-file-word',
gen : CoverPageGen,
name : 'Front Cover Page',
icon : 'fac book-front-cover',
gen : CoverPageGen.front,
experimental : true
},
{
name : 'Inside Cover Page',
icon : 'fac book-inside-cover',
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',
@@ -189,7 +216,7 @@ module.exports = [
}}
\n`;
},
},
}
]
},
@@ -231,7 +258,30 @@ module.exports = [
name : '1/3 Class Table (unframed)',
icon : 'fas fa-border-none',
gen : ClassTableGen.third('classTable'),
}
},
{
name : 'Rune Table',
icon : 'fas fa-language',
gen : scriptGen.dwarvish,
experimental : true,
subsnippets : [
{
name : 'Dwarvish',
icon : 'fac davek',
gen : scriptGen.dwarvish,
},
{
name : 'Elvish',
icon : 'fac rellanic',
gen : scriptGen.elvish,
},
{
name : 'Draconic',
icon : 'fac iokharic',
gen : scriptGen.draconic,
},
]
},
]
},

View File

@@ -1,55 +1,46 @@
const _ = require('lodash');
const dedent = require('dedent-tabs').default;
const titles = [
'The Burning Gallows',
'The Ring of Nenlast',
'Below the Blind Tavern',
'Below the Hungering River',
'Before Bahamut\'s Land',
'The Cruel Grave from Within',
'The Strength of Trade Road',
'Through The Raven Queen\'s Worlds',
'Within the Settlement',
'The Crown from Within',
'The Merchant Within the Battlefield',
'Ioun\'s Fading Traveler',
'The Legion Ingredient',
'The Explorer Lure',
'Before the Charming Badlands',
'The Living Dead Above the Fearful Cage',
'Vecna\'s Hidden Sage',
'Bahamut\'s Demonspawn',
'Across Gruumsh\'s Elemental Chaos',
'The Blade of Orcus',
'Beyond Revenge',
'Brain of Insanity',
'Breed Battle!, A New Beginning',
'Evil Lake, A New Beginning',
'Invasion of the Gigantic Cat, Part II',
'Kraken War 2020',
'The Body Whisperers',
'The Diabolical Tales of the Ape-Women',
'The Doctor Immortal',
'The Doctor from Heaven',
'The Graveyard',
'Azure Core',
'Core Battle',
'Core of Heaven: The Guardian of Amazement',
'Deadly Amazement III',
'Dry Chaos IX',
'Gate Thunder',
'Guardian: Skies of the Dark Wizard',
'Lute of Eternity',
'Mercury\'s Planet: Brave Evolution',
'Ruby of Atlantis: The Quake of Peace',
'Sky of Zelda: The Thunder of Force',
'Vyse\'s Skies',
'White Greatness III',
'Yellow Divinity',
'Zidane\'s Ghost'
'The Burning Gallows', 'The Ring of Nenlast',
'Below the Blind Tavern', 'Below the Hungering River',
'Before Bahamut\'s Land', 'The Cruel Grave from Within',
'The Strength of Trade Road', 'Through The Raven Queen\'s Worlds',
'Within the Settlement', 'The Crown from Within',
'The Merchant Within the Battlefield', 'Ioun\'s Fading Traveler',
'The Legion Ingredient', 'The Explorer Lure',
'Before the Charming Badlands', 'Vecna\'s Hidden Sage',
'The Living Dead Above the Fearful Cage', 'Bahamut\'s Demonspawn',
'Across Gruumsh\'s Elemental Chaos', 'The Blade of Orcus',
'Beyond Revenge', 'Brain of Insanity',
'A New Beginning', 'Evil Lake of the Merfolk',
'Invasion of the Gigantic Cat, Part II', 'Kraken War 2020',
'The Body Whisperers', 'The Doctor from Heaven',
'The Diabolical Tales of the Ape-Women', 'The Doctor Immortal',
'Core of Heaven: Guardian of Amazement', 'The Graveyard',
'Guardian: Skies of the Dark Wizard', 'Lute of Eternity',
'Mercury\'s Planet: Brave Evolution', 'Azure Core',
'Sky of Zelda: The Thunder of Force', 'Core Battle',
'Ruby of Atlantis: The Quake of Peace', 'Deadly Amazement III',
'Dry Chaos IX', 'Gate Thunder',
'Vyse\'s Skies', 'Blue Greatness III',
'Yellow Divinity', 'Zidane\'s Ghost'
];
const subtitles = [
'Tomb of Shadows', 'Dragon\'s Lair',
'Lost Caverns', 'The Necromancer',
'Mystic Forest', 'Cursed Ruins',
'The Dark Abyss', 'Enchanted Maze',
'Haunted Castle', 'Sands of Fate',
'Dragon\'s Hoard', 'Undead Menace',
'Lost City Ruins', 'Goblin Ambush',
'Enchanted Forest', 'Darkness Rising',
'Quest for Glory', 'Ancient Prophecy',
'Shadowy Depths', 'Mystic Isles'
];
const footnote = [
'In an ominous universe, a botanist opposes terrorism.',
'In a demon-haunted city, in an age of lies and hate, a physicist tries to find an ancient treasure and battles a mob of aliens.',
'In a land of corruption, two cyberneticists and a dungeon delver search for freedom.',
@@ -74,51 +65,92 @@ const subtitles = [
'On a planet of mysticism, three travelers and a fire fighter quest for the ultimate weapon and oppose evil.',
'In a wicked universe, five seers fight lawlessness.',
'In a kingdom of death, in an era of illusion and blood, four colonists search for fame.',
'In an amazing kingdom, in an age of sorcery and lost souls, eight space pirates quest for freedom.',
'In a cursed empire, five inventors oppose terrorism.',
'On a crime-ridden planet of conspiracy, a watchman and an artificial intelligence try to find love and oppose lawlessness.',
'In a forgotten land, a reporter and a spy try to stop the apocalypse.',
'In a forbidden land of prophecy, a scientist and an archivist oppose a cabal of barbarians intent on stealing the souls of the innocent.',
'On an infernal world of illusion, a grave robber and a watchman try to find revenge and combat a syndicate of mages intent on stealing the source of all magic.',
'In a galaxy of dark magic, four fighters seek freedom.',
'In an empire of deception, six tomb-robbers quest for the ultimate weapon and combat an army of raiders.',
'In a kingdom of corruption and lost souls, in an age of panic, eight planetologists oppose evil.',
'In a galaxy of misery and hopelessness, in a time of agony and pain, five planetologists search for vengance.',
'In a universe of technology and insanity, in a time of sorcery, a computer techician quests for hope.',
'On a planet of dark magic and barbarism, in an age of horror and blasphemy, seven librarians search for fame.',
'In an empire of dark magic, in a time of blood and illusions, four monks try to find the ultimate weapon and combat terrorism.',
'In a forgotten empire of dark magic, six kings try to prevent the destruction of mankind.',
'In a galaxy of dark magic and horror, in an age of hopelessness, four marines and an outlaw combat evil.',
'In a mysterious city of illusion, in an age of computerization, a witch-hunter tries to find the ultimate weapon and opposes an evil corporation.',
'In a damned kingdom of technology, a virtual reality programmer and a fighter seek fame.',
'In a hellish kingdom, in an age of blasphemy and blasphemy, an astrologer searches for fame.',
'In a damned world of devils, an alien and a ranger quest for love and oppose a syndicate of demons.',
'In a cursed galaxy, in a time of pain, seven librarians hope to avert the apocalypse.',
'In a crime-infested galaxy, in an era of hopelessness and panic, three champions and a grave robber try to solve the ultimate crime.'
'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 = ()=>{
return `<style>
.page#p1{ text-align:center; counter-increment: none; }
.page#p1:after{ display:none; }
.page:nth-child(2n) .pageNumber { left: inherit !important; right: 2px !important; }
.page:nth-child(2n+1) .pageNumber { right: inherit !important; left: 2px !important; }
.page:nth-child(2n)::after { transform: scaleX(1); }
.page:nth-child(2n+1)::after { transform: scaleX(-1); }
.page:nth-child(2n) .footnote { left: inherit; text-align: right; }
.page:nth-child(2n+1) .footnote { left: 80px; text-align: left; }
</style>
module.exports = {
{{margin-top:225px}}
front : function() {
return dedent`
{{frontCover}}
# ${_.sample(titles)}
{{logo ![](/assets/naturalCritLogoRed.svg)}}
{{margin-top:25px}}
# ${_.sample(titles)}
## ${_.sample(subtitles)}
___
{{wide
##### ${_.sample(subtitles)}
}}
{{banner HOMEBREW}}
\\page`;
};
{{footnote
${_.sample(footnote)}
}}
![background image](https://i.imgur.com/IwHRrbF.jpg){position:absolute,bottom:0,left:0,height:100%}
\page`;
},
inside : function() {
return dedent`
{{insideCover}}
# ${_.sample(titles)}
## ${_.sample(subtitles)}
___
{{imageMaskCenter${_.random(1, 16)},--offsetX:0%,--offsetY:0%,--rotation:0
![background image](https://i.imgur.com/IsfUnFR.jpg){position:absolute,bottom:0,left:0,height:100%}
}}
{{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

@@ -0,0 +1,48 @@
const _ = require('lodash');
const dedent = require('dedent-tabs').default;
module.exports = {
dwarvish : ()=>{
return dedent `##### Dwarvish Runes: Sample Alphabet
{{runeTable,wide,frame,font-family:Davek
| a | b | c | d | e | f | g | h | i | j | k | l | m |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| a | b | c | d | e | f | g | h | i | j | k | l | m |
:
| n | o | p | q | r | s | t | u | v | w | x | y | z |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| n | o | p | q | r | s | t | u | v | w | x | y | z |
}}\n\n`;
},
elvish : ()=>{
return dedent `##### Elvish Runes: Sample Alphabet
{{runeTable,wide,frame,font-family:Rellanic
| a | b | c | d | e | f | g | h | i | j | k | l | m |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| a | b | c | d | e | f | g | h | i | j | k | l | m |
:
| n | o | p | q | r | s | t | u | v | w | x | y | z |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| n | o | p | q | r | s | t | u | v | w | x | y | z |
}}\n\n`;
},
draconic : ()=>{
return dedent `##### Draconic Runes: Sample Alphabet
{{runeTable,wide,frame,font-family:Iokharic
| a | b | c | d | e | f | g | h | i | j | k | l | m |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| a | b | c | d | e | f | g | h | i | j | k | l | m |
:
| n | o | p | q | r | s | t | u | v | w | x | y | z |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| n | o | p | q | r | s | t | u | v | w | x | y | z |
}}\n\n`;
}
};
()=>{
};

View File

@@ -253,7 +253,7 @@ body {
border-image-outset : 9px 0px;
border-image-width : 11px;
padding : 0.13cm 0.16cm;
filter : drop-shadow(1px 4px 6px #888);
box-shadow : 1px 4px 14px #888;
.page :where(&) {
margin-top : 9px; //Prevent top border getting cut off on colbreak
}
@@ -282,7 +282,7 @@ body {
border-image : @descriptiveBoxImage 12 stretch;
border-image-outset : 4px;
padding : 0.1em;
filter : drop-shadow(0 0 3px #faf7ea);
box-shadow : 0 0 6px #faf7ea;
.page :where(&) {
margin-top : 4px; //Prevent top border getting cut off on colbreak
}
@@ -397,7 +397,7 @@ body {
border-image-outset : 0px 2px;
background-blend-mode : overlay;
background-attachment : fixed;
filter : drop-shadow(1px 4px 6px #888);
box-shadow : 1px 4px 14px #888;
padding : 4px 2px;
margin-left : -0.16cm;
margin-right : -0.16cm;
@@ -624,134 +624,406 @@ body {
// * CLASS TABLE
// *****************************/
.page .classTable{
th[colspan]:not([rowspan]) {
white-space : nowrap;
th[colspan]:not([rowspan]) {
white-space : nowrap;
}
&.frame {
margin-top : 0.7cm;
margin-bottom : 0.9cm;
margin-left : -0.1cm;
margin-right : -0.1cm;
width : calc(100% + 0.2cm);
border-collapse : separate;
background-color : white;
border : initial;
border-style : solid;
border-image-outset : 0.4cm 0.3cm;
border-image-repeat : stretch;
border-image-slice : 200;
border-image-source : @frameBorderImage;
border-image-width : 47px;
&.wide:first-child {
margin-top: 0.12cm;
}
&.frame {
margin-top : 0.7cm;
margin-bottom : 0.9cm;
margin-left : -0.1cm;
margin-right : -0.1cm;
width : calc(100% + 0.2cm);
border-collapse : separate;
background-color : white;
border : initial;
border-style : solid;
border-image-outset : 0.4cm 0.3cm;
border-image-repeat : stretch;
border-image-slice : 200;
border-image-source : @frameBorderImage;
border-image-width : 47px;
&.wide:first-child {
margin-top: 0.12cm;
}
& + * {
margin-top: 0;
}
}
&.decoration {
position:relative;
}
&.decoration::before {
content :'';
position : absolute;
background-image : @classTableDecoration,
@classTableDecoration;
background-size : contain, contain;
background-repeat : no-repeat, no-repeat;
background-position : top, bottom;
width : 7.75cm;
height : calc(100% + 3.3cm);
top : 50%;
left : 50%;
transform : translateY(-50%) translateX(-50%);
filter : drop-shadow(0px 0px 1px #C8C5C080);
z-index : -1;
}
&.decoration.wide::before {
width : calc(100% + 3.3cm);
height : 7.75cm;
background-position : left, right;
}
h5 + table{
margin-top : 0.2cm;
& + * {
margin-top: 0;
}
}
&.decoration {
position:relative;
}
&.decoration::before {
content :'';
position : absolute;
background-image : @classTableDecoration,
@classTableDecoration;
background-size : contain, contain;
background-repeat : no-repeat, no-repeat;
background-position : top, bottom;
width : 7.75cm;
height : calc(100% + 3.3cm);
top : 50%;
left : 50%;
transform : translateY(-50%) translateX(-50%);
filter : drop-shadow(0px 0px 1px #C8C5C080);
z-index : -1;
}
&.decoration.wide::before {
width : calc(100% + 3.3cm);
height : 7.75cm;
background-position : left, right;
}
h5 + table{
margin-top : 0.2cm;
}
}
//*****************************
// * FRONT COVER PAGE
// *****************************/
.page:has(.frontCover) {
columns : 1;
text-align : center;
&:after {
all: unset;
}
h1 {
text-shadow: unset;
filter : drop-shadow(0 0 1.5px black) drop-shadow(0 0 0 black)
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black)
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black)
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black);
text-transform : uppercase;
font-weight : normal;
margin-top : 1.2cm;
margin-bottom : 0;
color : white;
font-family : NodestoCapsCondensed;
font-size : 2.245cm;
line-height : 0.85em;
}
h2 {
filter : drop-shadow(0 0 1px black) drop-shadow(0 0 0 black)
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black)
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black)
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black);
font-family : NodestoCapsCondensed;
font-weight : normal;
font-size : 0.85cm;
letter-spacing : 0.1cm;
color : white;
}
hr {
display : block;
position : relative;
background-image : @horizontalRule;
background-size : 100% 100%;
visibility : visible;
height : 0.5cm;
width : 12cm;
border : none;
margin : auto;
filter : drop-shadow(0 0 3px black);
}
.banner {
filter : drop-shadow(2px 2px 2px black);
position : absolute;
left : 0;
bottom : 4.2cm;
background-image : url('/assets/coverPageBanner.svg');
height : 1.7cm;
width : 10.5cm;
color : white;
font-family : NodestoCapsCondensed;
font-weight : normal;
font-size : 1cm;
letter-spacing : 0.014cm;
text-align : left;
padding-left : 1cm;
display : flex;
justify-content : center;
flex-direction : column;
padding-top : 0.1cm;
}
.footnote {
filter : drop-shadow(0 0 0.7px black) drop-shadow(0 0 0 black)
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black)
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black)
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black);
position : absolute;
text-align : center;
color : white;
font-size : 0.496cm;
bottom : 1.3cm;
left : 0;
right : 0;
margin-left : auto;
margin-right : auto;
width : 70%;
font-family : Overpass;
}
.logo {
position : absolute;
top : 0.5cm;
left : 0;
right : 0;
filter : drop-shadow(0 0 0.075cm black);
img {
height : 2cm;
width : 100%;
}
}
}
//*****************************
// * INSIDE COVER PAGE
// *****************************/
.page:has(.insideCover) {
columns : 1;
text-align : center;
&:after {
all : unset;
}
h1 {
font-family : NodestoCapsCondensed;
font-weight : normal;
font-size : 2.1cm;
margin-top : 1.2cm;
margin-bottom : 0;
text-transform : uppercase;
line-height : 0.85em;
}
h2 {
font-family : NodestoCapsCondensed;
font-weight : normal;
font-size : 0.85cm;
letter-spacing : 0.5cm;
}
hr {
display : block;
position : relative;
background-image : @horizontalRule;
background-size : 100% 100%;
visibility : visible;
height : 0.5cm;
width : 12cm;
border : none;
margin : auto;
}
.logo {
position : absolute;
bottom : 1cm;
left : 0;
right : 0;
height : 2cm;
img {
height : 2cm;
width : 100%;
}
}
}
//*****************************
// * 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
// *****************************/
.page {
&:has(.toc):after {
display: none;
&:has(.toc):after {
display: none;
}
.toc {
-webkit-column-break-inside : avoid;
page-break-inside : avoid;
break-inside : avoid;
h1 {
text-align : center;
margin-bottom : 0.3cm;
}
.toc {
-webkit-column-break-inside : avoid;
page-break-inside : avoid;
break-inside : avoid;
h1 {
text-align : center;
margin-bottom : 0.3cm;
}
a{
display : inline;
color : inherit;
text-decoration : none;
&:hover{
text-decoration : underline;
}
}
h4 {
margin-top : 0.2cm;
line-height : 0.4cm;
& + ul li {
line-height: 1.2em;
}
}
ul{
padding-left : 0;
list-style-type : none;
margin-top : 0;
a {
width : 100%;
display : flex;
flex-flow : row nowrap;
justify-content : space-between;
}
li + li h3 {
margin-top : 0.26cm;
line-height : 1em
}
h3 span:first-child::after {
border : none;
}
span {
display : contents;
&:first-child::after {
content : "";
bottom : 0.08cm;
flex : 1;
margin-left : 0.08cm; /* Spacing before dot leaders */
margin-right : 0.16cm;
border-bottom : 0.05cm dotted #000;
margin-bottom : 0.08cm;
}
&:last-child {
display : inline-block;
align-self : flex-end;
font-family : "BookInsanityRemake";
font-size : 0.34cm;
font-weight : normal;
color : #000;
}
}
ul { /*List indent*/
margin-left : 1em;
}
}
&.wide{
.useColumns(0.96, @fillMode: balance);
a{
display : inline;
color : inherit;
text-decoration : none;
&:hover{
text-decoration : underline;
}
}
h4 {
margin-top : 0.2cm;
line-height : 0.4cm;
& + ul li {
line-height: 1.2em;
}
}
ul{
padding-left : 0;
list-style-type : none;
margin-top : 0;
a {
width : 100%;
display : flex;
flex-flow : row nowrap;
justify-content : space-between;
}
li + li h3 {
margin-top : 0.26cm;
line-height : 1em
}
h3 span:first-child::after {
border : none;
}
span {
display : contents;
&:first-child::after {
content : "";
bottom : 0.08cm;
flex : 1;
margin-left : 0.08cm; /* Spacing before dot leaders */
margin-right : 0.16cm;
border-bottom : 0.05cm dotted #000;
margin-bottom : 0.08cm;
}
&:last-child {
display : inline-block;
align-self : flex-end;
font-family : "BookInsanityRemake";
font-size : 0.34cm;
font-weight : normal;
color : #000;
}
}
ul { /*List indent*/
margin-left : 1em;
}
}
&.wide{
.useColumns(0.96, @fillMode: balance);
}
}
}
//*****************************
@@ -794,3 +1066,66 @@ body {
.page h1 + *{
margin-top : 0;
}
//*****************************
// * RUNE TABLE
// *****************************/
.page {
.runeTable {
margin-block: 0.7cm;
table {
font-family : inherit;
tbody tr {
background: unset;
}
th, td {
width: 1.3cm;
height: 1.3cm;
vertical-align: middle;
text-transform: uppercase;
outline: 1px solid #000;
font-weight: normal;
}
th{
font-family: BookInsanityRemake;
font-size: 0.45cm;
}
td {
font-size: 0.7cm;
}
}
&.frame {
border: initial;
border-style: solid;
border-image-outset: .45cm .35cm .4cm .4cm;
border-image-repeat: stretch;
border-image-slice: 170;
border-image-source: @scriptBorder;
border-image-width: 1.4cm;
}
}
}
//*****************************
// * 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;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Some files were not shown because too many files have changed in this diff Show More