0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2026-01-23 18:43:02 +00:00

Compare commits

...

1024 Commits

Author SHA1 Message Date
Víctor Losada Hernández
ec36365697 add letter size snippet 2025-03-18 12:39:31 +01:00
Víctor Losada Hernández
f47a32067e add changelog 2025-03-18 12:39:24 +01:00
Víctor Losada Hernández
fef571b1d6 version bump + npm audit fix 2025-03-18 12:13:17 +01:00
Víctor Losada Hernández
80b33e3fed Merge pull request #4099 from G-Ambatte/revertColonChange
Fix minor v3.18.0 issues
2025-03-18 12:07:03 +01:00
Víctor Losada Hernández
8b67118303 Merge branch 'master' into revertColonChange 2025-03-18 09:40:23 +01:00
Víctor Losada Hernández
d5969a6573 Merge pull request #4095 from naturalcrit/allow-all-origins-when-local
[LOCAL]: Fix cors issue in local network
2025-03-18 09:38:15 +01:00
Víctor Losada Hernández
547682a59a Merge branch 'master' into allow-all-origins-when-local 2025-03-18 09:31:10 +01:00
G.Ambatte
b2903137eb Fix hard-breaks tests 2025-03-18 11:08:15 +13:00
G.Ambatte
7329c69cfd Update tests 2025-03-18 11:02:09 +13:00
G.Ambatte
83a095923e Add columnSplit to end of each page for older Chrome versions 2025-03-18 10:51:09 +13:00
G.Ambatte
a44056a64b Restore blank styling 2025-03-18 10:02:29 +13:00
G.Ambatte
a705e3b9d8 Change : from br to div class='blank' 2025-03-18 09:54:27 +13:00
Víctor Losada Hernández
94bcc8e997 update to include all possible local adresses 2025-03-13 22:59:23 +01:00
Víctor Losada Hernández
72c2857237 initial fix 2025-03-13 22:32:12 +01:00
Trevor Buckner
f083391efd Merge pull request #4080 from naturalcrit/fix-vault-pagination
Vault fixes
2025-03-10 19:38:06 -04:00
Trevor Buckner
2c63c01723 Update Changelog 2025-03-10 19:37:32 -04:00
Trevor Buckner
85af5bbd27 Merge branch 'master' into fix-vault-pagination 2025-03-10 19:34:37 -04:00
Trevor Buckner
17f26b803c Merge pull request #4086 from naturalcrit/non-content_spans_dont_impact_flow
Style .frontCover and .insideCover to position : absolute
2025-03-10 19:32:27 -04:00
Trevor Buckner
8093380e0c .frontCover and .insideCover to position : absolute
.partCover and .backCover are already position : absolute.
2025-03-10 19:15:16 -04:00
Trevor Buckner
07f0cef67c Up marked-extended-tables to v2.0.1 2025-03-10 17:05:45 -04:00
Trevor Buckner
4241aa535b Merge pull request #4083 from G-Ambatte/killDomPurify
Remove unused DOMPurify package
2025-03-10 15:03:13 -04:00
Trevor Buckner
4c85f3ec4b Merge branch 'master' into killDomPurify 2025-03-10 15:02:21 -04:00
Trevor Buckner
57f273a276 Merge pull request #4084 from naturalcrit/v3.18.0
v3.18.0
2025-03-10 14:55:58 -04:00
Trevor Buckner
e159e57222 Changelog up to v3.18.0 2025-03-10 14:54:30 -04:00
G.Ambatte
d4991164e9 Merge branch 'master' into killDomPurify 2025-03-11 07:40:34 +13:00
Trevor Buckner
baa1ed2b53 Merge pull request #4082 from naturalcrit/dependabot/npm_and_yarn/nanoid-5.1.3
Bump nanoid from 5.1.2 to 5.1.3
2025-03-10 14:38:17 -04:00
G.Ambatte
f1e291e313 Remove unused DOMPurify package 2025-03-11 07:32:58 +13:00
dependabot[bot]
814f3a6c20 Bump nanoid from 5.1.2 to 5.1.3
Bumps [nanoid](https://github.com/ai/nanoid) from 5.1.2 to 5.1.3.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/5.1.2...5.1.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-10 18:03:14 +00:00
Trevor Buckner
43dc1bed7d Merge pull request #4081 from naturalcrit/dependabot/npm_and_yarn/eslint-9.22.0
Bump eslint from 9.21.0 to 9.22.0
2025-03-10 14:01:55 -04:00
dependabot[bot]
313492a344 Bump eslint from 9.21.0 to 9.22.0
Bumps [eslint](https://github.com/eslint/eslint) from 9.21.0 to 9.22.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/v9.21.0...v9.22.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-10 03:19:07 +00:00
Víctor Losada Hernández
4cd5c13841 lint styles 2025-03-08 19:38:42 +01:00
Víctor Losada Hernández
c7a19857dd remove visual glitch when performing aa search 2025-03-08 19:35:12 +01:00
Víctor Losada Hernández
b07317b0f7 display pagination on top as well 2025-03-08 19:32:26 +01:00
Víctor Losada Hernández
c0eef7530e added transition to smooth change 2025-03-08 17:27:34 +01:00
Víctor Losada Hernández
55618a10b9 fix container query 2025-03-08 17:16:23 +01:00
Víctor Losada Hernández
5f48b30449 lint styles 2025-03-08 13:46:11 +01:00
Víctor Losada Hernández
e523886345 lint server api 2025-03-08 13:42:49 +01:00
Víctor Losada Hernández
4918dc5239 manual lint 2025-03-08 13:42:29 +01:00
Víctor Losada Hernández
a0de6295c7 fix space in help text 2025-03-08 13:39:06 +01:00
Víctor Losada Hernández
3db778a665 fix 2 column issue 2025-03-08 13:30:06 +01:00
Víctor Losada Hernández
a7eef65694 fix pagination not correctly updating 2025-03-08 13:16:41 +01:00
Trevor Buckner
8d1464a2c4 Merge pull request #4078 from naturalcrit/dependabot/npm_and_yarn/react-router-7.3.0
Bump react-router from 7.2.0 to 7.3.0
2025-03-06 23:39:16 -05:00
dependabot[bot]
552cf30863 Bump react-router from 7.2.0 to 7.3.0
Bumps [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router) from 7.2.0 to 7.3.0.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router@7.3.0/packages/react-router)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-07 03:48:38 +00:00
Trevor Buckner
4daa8042a2 Merge pull request #4005 from dbolack-ab/issue_3206
Workaround for unclosed <pre> blocks before rendering.
2025-03-05 20:13:45 -05:00
Trevor Buckner
51e79c2c5f Remove extra column break entirely
Not needed with change to column-fill auto

See https://github.com/naturalcrit/homebrewery/pull/3013
2025-03-05 20:13:35 -05:00
Trevor Buckner
88e8140b60 Merge branch 'master' into pr/4005 2025-03-05 19:59:36 -05:00
Trevor Buckner
252698b135 Merge pull request #4077 from naturalcrit/Update-Marked.js-to-v14.0.0
Update to Marked v14
2025-03-05 15:50:08 -05:00
Trevor Buckner
21f1704626 Update to Marked v14 2025-03-05 15:40:14 -05:00
David Bolack
19556d9f36 Merge branch 'master' into issue_3206 2025-03-05 11:09:03 -06:00
Trevor Buckner
0d4d97c5c5 Merge pull request #4070 from naturalcrit/dependabot/npm_and_yarn/stylelint-16.15.0
Bump stylelint from 16.14.1 to 16.15.0
2025-03-05 12:00:37 -05:00
David Bolack
55f333a9e5 Changed tactic per suggestion
Unsure if the test is absolutely necessary.
2025-03-05 10:52:43 -06:00
dependabot[bot]
2361cdeadc Bump stylelint from 16.14.1 to 16.15.0
Bumps [stylelint](https://github.com/stylelint/stylelint) from 16.14.1 to 16.15.0.
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint/compare/16.14.1...16.15.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-05 16:47:30 +00:00
Trevor Buckner
aeae704173 Merge pull request #4071 from naturalcrit/dependabot/npm_and_yarn/core-js-3.41.0
Bump core-js from 3.40.0 to 3.41.0
2025-03-05 11:46:08 -05:00
David Bolack
c420410904 Merge branch 'master' into issue_3206 2025-03-05 10:37:58 -06:00
dependabot[bot]
0daf8c5c83 Bump core-js from 3.40.0 to 3.41.0
Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.40.0 to 3.41.0.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/commits/v3.41.0/packages/core-js)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-05 16:37:35 +00:00
Trevor Buckner
924d014c69 Merge pull request #4074 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.12.1
Bump mongoose from 8.11.0 to 8.12.1
2025-03-05 11:36:18 -05:00
dependabot[bot]
8992cf8251 Bump mongoose from 8.11.0 to 8.12.1
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.11.0 to 8.12.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/8.11.0...8.12.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-05 16:26:08 +00:00
Trevor Buckner
7c6aa0ffec Merge pull request #4075 from naturalcrit/dependabot/npm_and_yarn/marked-emoji-2.0.0
Bump marked-emoji from 1.4.3 to 2.0.0
2025-03-05 11:24:42 -05:00
Trevor Buckner
ebe64c508f Merge branch 'master' into dependabot/npm_and_yarn/marked-emoji-2.0.0 2025-03-05 11:20:08 -05:00
Trevor Buckner
f3514cfea6 Merge pull request #4076 from MollyMaclachlan/master
Fix formatting inconsistencies in 5ePHB monster stat block
2025-03-05 10:52:29 -05:00
Trevor Buckner
8ed25fb7cf Merge branch 'master' into master 2025-03-05 10:52:21 -05:00
Trevor Buckner
762cd58d52 Update usage of Marked-extended-tables options 2025-03-05 10:49:46 -05:00
Murdo B. Maclachlan
477f706eb9 Fix formatting inconsistencies in 5ePHB monster stat block
Closes #4073. Fixes minor formatting inconsistencies in the monster stat block between the 5ePHB theme and actual 5e manuals.
2025-03-05 13:01:31 +00:00
dependabot[bot]
edcf9979a7 Bump marked-emoji from 1.4.3 to 2.0.0
Bumps [marked-emoji](https://github.com/UziTech/marked-emoji) from 1.4.3 to 2.0.0.
- [Release notes](https://github.com/UziTech/marked-emoji/releases)
- [Changelog](https://github.com/UziTech/marked-emoji/blob/main/release.config.cjs)
- [Commits](https://github.com/UziTech/marked-emoji/compare/v1.4.3...v2.0.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-05 03:48:15 +00:00
Trevor Buckner
ef2beec590 Merge pull request #4068 from naturalcrit/dependabot/npm_and_yarn/googleapis/drive-8.16.0
Bump @googleapis/drive from 8.14.0 to 8.16.0
2025-02-28 16:01:32 -05:00
dependabot[bot]
c10559ba5f Bump @googleapis/drive from 8.14.0 to 8.16.0
Bumps [@googleapis/drive](https://github.com/googleapis/google-api-nodejs-client) from 8.14.0 to 8.16.0.
- [Release notes](https://github.com/googleapis/google-api-nodejs-client/releases)
- [Changelog](https://github.com/googleapis/google-api-nodejs-client/blob/main/release-please-config.json)
- [Commits](https://github.com/googleapis/google-api-nodejs-client/compare/drive-v8.14.0...drive-v8.16.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>
2025-02-28 19:59:46 +00:00
Trevor Buckner
69c633dabe Merge pull request #4067 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.11.0
Bump mongoose from 8.10.2 to 8.11.0
2025-02-28 14:58:32 -05:00
dependabot[bot]
8bdcdcd510 Bump mongoose from 8.10.2 to 8.11.0
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.10.2 to 8.11.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/8.10.2...8.11.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-28 13:01:06 +00:00
Trevor Buckner
ce03f598b2 Merge pull request #4066 from naturalcrit/dependabot/npm_and_yarn/marked-extended-tables-2.0.0
Bump marked-extended-tables from 1.1.0 to 2.0.0
2025-02-28 07:59:47 -05:00
dependabot[bot]
addbf19682 Bump marked-extended-tables from 1.1.0 to 2.0.0
Bumps [marked-extended-tables](https://github.com/calculuschild/marked-extended-tables) from 1.1.0 to 2.0.0.
- [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/compare/v1.1.0...v2.0.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-27 03:57:55 +00:00
Trevor Buckner
479aae4b2f Merge pull request #4065 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.10.2
Bump mongoose from 8.10.1 to 8.10.2
2025-02-26 10:46:36 -05:00
Trevor Buckner
4b6652c470 Merge pull request #4052 from G-Ambatte/fixSaveBug
Fix bug in save logic
2025-02-26 10:45:53 -05:00
dependabot[bot]
e9d1209ce8 Bump mongoose from 8.10.1 to 8.10.2
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.10.1 to 8.10.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/8.10.1...8.10.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-26 03:33:15 +00:00
G.Ambatte
7c62e49767 Merge branch 'master' into fixSaveBug 2025-02-25 22:39:18 +13:00
G.Ambatte
9b0da36365 Rework isPending & hasChanges 2025-02-25 19:56:23 +13:00
Trevor Buckner
1391a9053d Merge pull request #4062 from naturalcrit/dependabot/npm_and_yarn/globals-16.0.0
Bump globals from 15.15.0 to 16.0.0
2025-02-24 14:21:59 -05:00
dependabot[bot]
fee88d1d47 Bump globals from 15.15.0 to 16.0.0
Bumps [globals](https://github.com/sindresorhus/globals) from 15.15.0 to 16.0.0.
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v15.15.0...v16.0.0)

---
updated-dependencies:
- dependency-name: globals
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-24 18:39:19 +00:00
Trevor Buckner
a47dc51bd1 Merge pull request #4064 from naturalcrit/dependabot/npm_and_yarn/eslint-9.21.0
Bump eslint from 9.20.1 to 9.21.0
2025-02-24 13:37:52 -05:00
dependabot[bot]
cfb9e1afa2 Bump eslint from 9.20.1 to 9.21.0
Bumps [eslint](https://github.com/eslint/eslint) from 9.20.1 to 9.21.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/v9.20.1...v9.21.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-24 18:34:06 +00:00
Trevor Buckner
540a0a7a36 Merge pull request #4063 from naturalcrit/dependabot/npm_and_yarn/nanoid-5.1.2
Bump nanoid from 5.1.0 to 5.1.2
2025-02-24 13:32:41 -05:00
dependabot[bot]
b7e422ac06 Bump nanoid from 5.1.0 to 5.1.2
Bumps [nanoid](https://github.com/ai/nanoid) from 5.1.0 to 5.1.2.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/5.1.0...5.1.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-24 03:57:12 +00:00
Víctor Losada Hernández
df5eeb5c97 Merge pull request #4023 from 5e-Cleric/fix-snippet-styling
Small adjustments to the PHB theme snippets
2025-02-20 21:18:24 +01:00
Víctor Losada Hernández
e2de225625 Merge branch 'fix-snippet-styling' of https://github.com/5e-Cleric/homebrewery into fix-snippet-styling 2025-02-20 20:44:32 +01:00
Víctor Losada Hernández
5b7d5bee24 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into fix-snippet-styling 2025-02-20 20:44:18 +01:00
Trevor Buckner
18eb3ec643 Merge branch 'master' into fix-snippet-styling 2025-02-20 13:35:05 -05:00
Trevor Buckner
5f9cc48fe1 Merge pull request #4060 from naturalcrit/dependabot/npm_and_yarn/react-router-7.2.0
Bump react-router from 7.1.5 to 7.2.0
2025-02-20 13:02:43 -05:00
dependabot[bot]
56d1855518 Bump react-router from 7.1.5 to 7.2.0
Bumps [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router) from 7.1.5 to 7.2.0.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router@7.2.0/packages/react-router)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-20 03:59:59 +00:00
Trevor Buckner
758b508955 Merge pull request #4058 from naturalcrit/Change_Hardbreak_-_to_-br-
Change hardbreak  to `<br>`
2025-02-19 16:25:54 -05:00
Trevor Buckner
3221b40903 Merge pull request #4043 from dbolack-ab/marked-subsuper
Move Superscript/Subscript functions into their own module
2025-02-19 16:25:31 -05:00
Trevor Buckner
39a49a6d62 Merge branch 'master' into marked-subsuper 2025-02-19 16:21:04 -05:00
Trevor Buckner
02f63e0b02 Merge branch 'master' into Change_Hardbreak_-_to_-br- 2025-02-19 16:15:49 -05:00
Trevor Buckner
0ba943ceb0 Update Test Cases 2025-02-19 16:15:31 -05:00
Trevor Buckner
578a8d7eba Add \n after each <br> 2025-02-19 16:00:37 -05:00
Trevor Buckner
9a9d7a6b5e Merge pull request #3984 from G-Ambatte/headerNaxExtension
Extend header nav to skip headers in "top level" pages
2025-02-19 15:54:32 -05:00
Trevor Buckner
917b6b3145 Shrinking down some logic 2025-02-19 15:52:52 -05:00
Trevor Buckner
b36376f9e8 Linting 2025-02-19 13:44:28 -05:00
David Bolack
58a22750c5 Update package-lock 2025-02-19 11:38:38 -06:00
David Bolack
df1b601de7 Merge branch 'master' into marked-subsuper 2025-02-19 11:37:38 -06:00
David Bolack
1ed44282e3 Merge branch 'master' of github.com:naturalcrit/homebrewery 2025-02-19 11:36:51 -06:00
G.Ambatte
f421ce1d93 Fix missing depth styling 2025-02-19 16:10:27 +13:00
G.Ambatte
ca0f18acd6 Update getTextContent function to getHeaderContent 2025-02-19 15:22:08 +13:00
G.Ambatte
87d76ea8f6 Change topLevelPages functions for cover pages 2025-02-19 13:46:35 +13:00
G.Ambatte
9f5a29099c Address requested changes 2025-02-19 13:24:07 +13:00
G.Ambatte
0360d6b6c5 Merge branch 'master' into headerNaxExtension 2025-02-19 07:59:38 +13:00
Trevor Buckner
8d2057431b Merge pull request #3923 from dbolack-ab/writeinBrewTheme
WIP: User Brew Theme Write-in
2025-02-18 13:54:34 -05:00
Trevor Buckner
ee0d737b9c Merge branch 'master' into writeinBrewTheme 2025-02-18 13:44:56 -05:00
Trevor Buckner
cb27b26103 Merge pull request #4055 from naturalcrit/dependabot/npm_and_yarn/babel/preset-env-7.26.9
Bump @babel/preset-env from 7.26.8 to 7.26.9
2025-02-18 09:39:19 -05:00
dependabot[bot]
0564fb82f6 Bump @babel/preset-env from 7.26.8 to 7.26.9
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.26.8 to 7.26.9.
- [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.26.9/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>
2025-02-18 02:06:21 +00:00
Trevor Buckner
5596f2d9da Merge pull request #4056 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.10.1
Bump mongoose from 8.10.0 to 8.10.1
2025-02-17 21:05:06 -05:00
dependabot[bot]
a11b67f139 Bump mongoose from 8.10.0 to 8.10.1
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.10.0 to 8.10.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/8.10.0...8.10.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-17 22:02:38 +00:00
Trevor Buckner
17717ea2a9 Merge pull request #4053 from naturalcrit/dependabot/npm_and_yarn/nanoid-5.1.0
Bump nanoid from 5.0.9 to 5.1.0
2025-02-17 17:01:18 -05:00
dependabot[bot]
c15e7b2da3 Bump nanoid from 5.0.9 to 5.1.0
Bumps [nanoid](https://github.com/ai/nanoid) from 5.0.9 to 5.1.0.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/5.0.9...5.1.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-17 21:53:00 +00:00
Trevor Buckner
fcca56f502 Merge pull request #4054 from naturalcrit/dependabot/npm_and_yarn/babel/core-7.26.9
Bump @babel/core from 7.26.8 to 7.26.9
2025-02-17 16:51:47 -05:00
dependabot[bot]
68f66b2bac Bump @babel/core from 7.26.8 to 7.26.9
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.26.8 to 7.26.9.
- [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.26.9/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>
2025-02-17 21:47:15 +00:00
Trevor Buckner
0d71f291e7 Merge pull request #4057 from naturalcrit/dependabot/npm_and_yarn/babel/plugin-transform-runtime-7.26.9
Bump @babel/plugin-transform-runtime from 7.26.8 to 7.26.9
2025-02-17 16:45:56 -05:00
Trevor Buckner
fc065d250b Fix useSansSerif() case (monster stat blocks, descriptiven note, etc.)
Removed line-height value that affects only <br> height. Doesn't impact anywhere else because they all have their own explicit line-heights already.
2025-02-17 16:27:22 -05:00
Trevor Buckner
01d93b98d5 Remove LESS styling for .blank 2025-02-17 15:09:04 -05:00
Trevor Buckner
f5aa37bd5e Change Marked extension to emit <br> instead of <div class="blank"> 2025-02-17 15:08:47 -05:00
dependabot[bot]
d6d445dad5 Bump @babel/plugin-transform-runtime from 7.26.8 to 7.26.9
Bumps [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-runtime) from 7.26.8 to 7.26.9.
- [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.26.9/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>
2025-02-17 03:58:22 +00:00
G.Ambatte
1af66cf571 Add default case for SAVE button text 2025-02-15 00:13:23 +13:00
G.Ambatte
2cb8b5d014 Set brew state to exactly match savedBrew 2025-02-15 00:12:55 +13:00
G.Ambatte
34a0b4eb05 Base savedBrew on current brew state, apply only updated properties from API call 2025-02-15 00:12:20 +13:00
Trevor Buckner
854a2ab35e Fix /new 2025-02-13 17:56:39 -05:00
Trevor Buckner
42accdb54f linting 2025-02-13 17:54:37 -05:00
Trevor Buckner
7e5bade4fa Merge branch 'master' into writeinBrewTheme 2025-02-13 16:21:17 -05:00
Trevor Buckner
ed30a1cd7d Update other tests to pass 2025-02-13 16:20:59 -05:00
Trevor Buckner
94f478477d Add test for missing meta:theme tag 2025-02-13 16:20:50 -05:00
Trevor Buckner
50bda9455f Immediately clear errors if a theme successfully loads 2025-02-13 15:51:22 -05:00
Trevor Buckner
d8d672fada Error message if chosen theme does not have "meta:theme" tag. 2025-02-13 15:51:06 -05:00
Trevor Buckner
bf297939dc Debounce validation popup 2025-02-13 15:01:35 -05:00
Trevor Buckner
df563b9294 Change combobox default text 2025-02-13 14:53:02 -05:00
Trevor Buckner
e584eec8c2 When clicked, combobox textbox clears 2025-02-13 14:51:45 -05:00
Trevor Buckner
557178172b Merge pull request #4050 from naturalcrit/dependabot/npm_and_yarn/elliptic-6.6.1
Bump elliptic from 6.6.0 to 6.6.1
2025-02-13 14:14:17 -05:00
Trevor Buckner
45e98debbd Remove z-index for metadata editor to not cover nav bar (errors/dropdowns/etc)
The other editor panels don't have a z-index. For some reason the metadata editor does, and it covers items from the navbar
2025-02-13 00:43:14 -05:00
Trevor Buckner
0bd5ac42b6 Remove too-small height for themes + thumbnail 2025-02-13 00:40:59 -05:00
dependabot[bot]
af729de096 Bump elliptic from 6.6.0 to 6.6.1
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.6.0 to 6.6.1.
- [Commits](https://github.com/indutny/elliptic/compare/v6.6.0...v6.6.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-13 05:13:33 +00:00
Trevor Buckner
40cd53fcb8 Merge pull request #4048 from naturalcrit/dependabot/npm_and_yarn/globals-15.15.0
Bump globals from 15.14.0 to 15.15.0
2025-02-13 00:12:26 -05:00
Trevor Buckner
f326d11232 Added input validation (allows Share ID or Share URL) 2025-02-13 00:05:30 -05:00
dependabot[bot]
85ea91fed8 Bump globals from 15.14.0 to 15.15.0
Bumps [globals](https://github.com/sindresorhus/globals) from 15.14.0 to 15.15.0.
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v15.14.0...v15.15.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-13 03:21:18 +00:00
David Bolack
a0c9b8849c Merge branch 'master' of github.com:naturalcrit/homebrewery 2025-02-12 16:23:54 -06:00
Víctor Losada Hernández
ff91ebb06a Merge pull request #4022 from 5e-Cleric/update-admin
Update admin
2025-02-12 23:14:39 +01:00
Víctor Losada Hernández
21baab784e Merge branch 'update-admin' of https://github.com/5e-Cleric/homebrewery into update-admin 2025-02-12 23:11:17 +01:00
Víctor Losada Hernández
1f3a0f1f99 adapt width of table to date iso and remove colors 2025-02-12 23:10:51 +01:00
Trevor Buckner
6b4f5bd0af Linting on .less files 2025-02-12 15:30:20 -05:00
David Bolack
52cf1ddea0 Merge branch 'master' of github.com:naturalcrit/homebrewery 2025-02-12 10:03:45 -06:00
Víctor Losada Hernández
b79c5954ff minor style changes 2025-02-12 13:02:26 +01:00
Víctor Losada Hernández
9944398e4c add decent table styles 2025-02-12 12:54:34 +01:00
Víctor Losada Hernández
489f00b785 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into update-admin 2025-02-12 12:08:34 +01:00
Trevor Buckner
1a515f8d9c Merge pull request #4045 from naturalcrit/dependabot/npm_and_yarn/eslint-9.20.1
Bump eslint from 9.20.0 to 9.20.1
2025-02-11 23:16:57 -05:00
dependabot[bot]
f386ba3f45 Bump eslint from 9.20.0 to 9.20.1
Bumps [eslint](https://github.com/eslint/eslint) from 9.20.0 to 9.20.1.
- [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/v9.20.0...v9.20.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-12 03:52:31 +00:00
David Bolack
db16248afb Remove Paragraph Justifcation test execution. 2025-02-11 14:57:24 -06:00
Trevor Buckner
634450d4a9 Merge pull request #4031 from G-Ambatte/addAdminGetBrewsByUser
Add Admin function to get list of brews by username
2025-02-11 15:21:22 -05:00
G.Ambatte
559f55f781 Merge branch 'master' into addAdminGetBrewsByUser 2025-02-12 08:23:43 +13:00
G.Ambatte
64b7527ad0 Convert space indentation to tabs 2025-02-12 08:01:07 +13:00
G.Ambatte
d48d5260a4 Fix missing } 2025-02-12 07:54:15 +13:00
David Bolack
41dc78375c Merge branch 'master' into marked-subsuper 2025-02-11 12:50:46 -06:00
G.Ambatte
bbc601cf47 Simplify sort algorithm
Co-authored-by: Trevor Buckner <calculuschild@gmail.com>
2025-02-12 07:42:35 +13:00
G.Ambatte
e89920bd1e Remove unneeded .then()
Co-authored-by: Trevor Buckner <calculuschild@gmail.com>
2025-02-12 07:41:53 +13:00
Trevor Buckner
2e12980180 Merge branch 'master' into fix-snippet-styling 2025-02-11 11:23:05 -05:00
Trevor Buckner
b77af1bcc8 Merge pull request #4040 from naturalcrit/dependabot/npm_and_yarn/babel/preset-env-7.26.8
Bump @babel/preset-env from 7.26.7 to 7.26.8
2025-02-11 11:22:14 -05:00
dependabot[bot]
45d188fea1 Bump @babel/preset-env from 7.26.7 to 7.26.8
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.26.7 to 7.26.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.26.8/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>
2025-02-11 16:19:50 +00:00
Trevor Buckner
1ce26ca953 Merge pull request #4041 from naturalcrit/dependabot/npm_and_yarn/babel/core-7.26.8
Bump @babel/core from 7.26.7 to 7.26.8
2025-02-11 11:18:26 -05:00
dependabot[bot]
d1c0557341 Bump @babel/core from 7.26.7 to 7.26.8
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.26.7 to 7.26.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.26.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>
2025-02-11 16:04:52 +00:00
Trevor Buckner
4e857a1a99 Merge pull request #4033 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.10.0
Bump mongoose from 8.9.6 to 8.10.0
2025-02-11 11:03:19 -05:00
Trevor Buckner
547ac11756 Merge branch 'master' into dependabot/npm_and_yarn/mongoose-8.10.0 2025-02-11 11:01:27 -05:00
Trevor Buckner
0e2443f772 Merge pull request #4039 from naturalcrit/dependabot/npm_and_yarn/eslint-9.20.0
Bump eslint from 9.19.0 to 9.20.0
2025-02-11 11:01:03 -05:00
dependabot[bot]
9d16f4556e Bump mongoose from 8.9.6 to 8.10.0
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.9.6 to 8.10.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/8.9.6...8.10.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-11 15:23:08 +00:00
dependabot[bot]
6d0d0057f6 Bump eslint from 9.19.0 to 9.20.0
Bumps [eslint](https://github.com/eslint/eslint) from 9.19.0 to 9.20.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/v9.19.0...v9.20.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-11 15:22:28 +00:00
Trevor Buckner
b8d9023c98 Merge pull request #4038 from naturalcrit/dependabot/npm_and_yarn/babel/plugin-transform-runtime-7.26.8
Bump @babel/plugin-transform-runtime from 7.25.9 to 7.26.8
2025-02-11 10:21:48 -05:00
Trevor Buckner
4578cf6584 Merge branch 'master' into dependabot/npm_and_yarn/babel/plugin-transform-runtime-7.26.8 2025-02-11 10:19:58 -05:00
Trevor Buckner
111869d33b Merge pull request #4032 from naturalcrit/dependabot/npm_and_yarn/stylistic/stylelint-plugin-3.1.2
Bump @stylistic/stylelint-plugin from 3.1.1 to 3.1.2
2025-02-11 10:19:31 -05:00
Trevor Buckner
d0b4486e15 Merge branch 'master' into dependabot/npm_and_yarn/stylistic/stylelint-plugin-3.1.2 2025-02-11 10:15:39 -05:00
Trevor Buckner
1aed753911 Use ComboBox component for Theme Selector 2025-02-10 22:20:54 -05:00
Trevor Buckner
c080e5b191 Add author to snippetBundle 2025-02-10 22:20:12 -05:00
David Bolack
11396389ab Move Superscript/Subscript functions into their own module 2025-02-10 20:47:17 -06:00
Trevor Buckner
0bcf228881 Merge branch 'master' into writeinBrewTheme 2025-02-10 00:49:22 -05:00
Trevor Buckner
de30722554 Merge pull request #4042 from naturalcrit/cleanUpCombobox
Clean up combobox component
2025-02-10 00:48:48 -05:00
Trevor Buckner
6cfdfad7d3 Clean up combobox component 2025-02-10 00:33:33 -05:00
dependabot[bot]
a9fa0bd32d Bump @babel/plugin-transform-runtime from 7.25.9 to 7.26.8
Bumps [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-runtime) from 7.25.9 to 7.26.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.26.8/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>
2025-02-10 03:10:29 +00:00
Trevor Buckner
cfbf4021dc Remove unneeded filter 2025-02-09 12:23:42 -05:00
Trevor Buckner
e3780e844d Merge branch 'writeinBrewTheme' of https://github.com/dbolack-ab/homebrewery into pr/3923 2025-02-09 12:07:31 -05:00
Trevor Buckner
659510e364 Remove unused function 2025-02-09 12:07:09 -05:00
Trevor Buckner
29da0396fd Merge branch 'master' into writeinBrewTheme 2025-02-09 12:03:06 -05:00
Trevor Buckner
c3e08181e9 Merge branch 'master' into dependabot/npm_and_yarn/stylistic/stylelint-plugin-3.1.2 2025-02-09 12:02:12 -05:00
Víctor Losada Hernández
213a719337 Merge pull request #4036 from G-Ambatte/correctChangeLogTypo
Correct typo in date of v3.17.0
2025-02-09 11:33:37 +01:00
G.Ambatte
a7a7e46e89 Correct typo in date of v3.17.0 2025-02-09 22:40:54 +13:00
dependabot[bot]
ada06c9618 Bump @stylistic/stylelint-plugin from 3.1.1 to 3.1.2
Bumps [@stylistic/stylelint-plugin](https://github.com/stylelint-stylistic/stylelint-stylistic) from 3.1.1 to 3.1.2.
- [Release notes](https://github.com/stylelint-stylistic/stylelint-stylistic/releases)
- [Changelog](https://github.com/stylelint-stylistic/stylelint-stylistic/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint-stylistic/stylelint-stylistic/compare/v3.1.1...v3.1.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-06 03:24:23 +00:00
G.Ambatte
03798e945d Add UI 2025-02-05 21:35:33 +13:00
G.Ambatte
6d2cbaacc0 Add Admin API for getByUser 2025-02-05 21:35:21 +13:00
David Bolack
f2f894381e Merge branch 'master' into issue_3206 2025-02-04 21:10:25 -06:00
Trevor Buckner
10fae6dbac Merge pull request #4026 from 5e-Cleric/fix-errorpage-error-if-brew-title-doesn't-exist
fix undefined value in errorIndex.js if brew doesn't exist
2025-02-03 14:24:30 -05:00
Víctor Losada Hernández
ebc7f055fa Merge branch 'master' into fix-errorpage-error-if-brew-title-doesn't-exist 2025-02-03 15:26:36 +01:00
Víctor Losada Hernández
ce01b6c1ff initial commit 2025-02-03 15:10:34 +01:00
Trevor Buckner
553562611f Merge pull request #4024 from naturalcrit/dependabot/npm_and_yarn/react-router-7.1.5
Bump react-router from 7.1.4 to 7.1.5
2025-02-03 00:07:11 -05:00
dependabot[bot]
423caefe1a Bump react-router from 7.1.4 to 7.1.5
Bumps [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router) from 7.1.4 to 7.1.5.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router@7.1.5/packages/react-router)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-03 04:45:39 +00:00
Trevor Buckner
ae1de819ea Merge pull request #4025 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.9.6
Bump mongoose from 8.9.5 to 8.9.6
2025-02-02 23:44:17 -05:00
dependabot[bot]
27c4cfd25c Bump mongoose from 8.9.5 to 8.9.6
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.9.5 to 8.9.6.
- [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/8.9.5...8.9.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-03 03:16:41 +00:00
Víctor Losada Hernández
bf22104474 move padding to a more deserving place 2025-02-02 22:19:38 +01:00
Víctor Losada Hernández
c3e0a687c0 Merge branch 'master' into writeinBrewTheme 2025-02-02 22:18:20 +01:00
Víctor Losada Hernández
00a2b130eb Merge branch 'master' into headerNaxExtension 2025-02-02 16:44:30 +01:00
Víctor Losada Hernández
8eef810f3f backcover logo width 2025-02-01 20:30:54 +01:00
Víctor Losada Hernández
a04df0fdfc small adjustements 2025-02-01 19:27:55 +01:00
Víctor Losada Hernández
a504703d41 removed unnecessary files and refactored layout of dl 2025-02-01 15:47:41 +01:00
Víctor Losada Hernández
3ce9bb1310 initial commit 2025-01-31 23:20:35 +01:00
Víctor Losada Hernández
66bfc8f27b style change 2025-01-31 22:33:47 +01:00
Trevor Buckner
6c8b94453e Merge pull request #4019 from naturalcrit/update-notif-to-handle-markdown
upadte notification popup to handle markdown
2025-01-31 14:31:31 -05:00
Víctor Losada Hernández
460fb655d8 bring margin back 2025-01-31 20:11:57 +01:00
Víctor Losada Hernández
be1742d01d remove unnecessary spaces 2025-01-31 20:08:10 +01:00
Víctor Losada Hernández
5d3742aea6 Merge branch 'update-notif-to-handle-markdown' of https://github.com/naturalcrit/homebrewery into update-notif-to-handle-markdown 2025-01-31 20:02:33 +01:00
Víctor Losada Hernández
1966027289 linting & suggested changes 2025-01-31 20:02:31 +01:00
Víctor Losada Hernández
35d50cc9d1 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into update-notif-to-handle-markdown 2025-01-31 20:01:29 +01:00
Trevor Buckner
3f41306306 Merge branch 'master' into update-notif-to-handle-markdown 2025-01-31 13:43:50 -05:00
Trevor Buckner
988bf1b0a9 Merge pull request #4020 from naturalcrit/FixStyleLintImport
Fix StyleLint require to import
2025-01-31 13:42:19 -05:00
Trevor Buckner
2f1ade8463 lint 2025-01-31 13:38:25 -05:00
Trevor Buckner
518924d725 Use import, run eslint 2025-01-31 13:36:42 -05:00
Trevor Buckner
6269651c8d Update Marked to v13.0.3 2025-01-31 12:42:54 -05:00
Víctor Losada Hernández
057abcda0d reduce style between li elements 2025-01-31 12:04:40 +01:00
Víctor Losada Hernández
b6b23a787c upadte notification popup to handle markdown 2025-01-31 11:52:46 +01:00
Trevor Buckner
899004cfaf Merge pull request #4017 from naturalcrit/dependabot/npm_and_yarn/react-router-7.1.4
Bump react-router from 7.1.3 to 7.1.4
2025-01-31 00:35:03 -05:00
dependabot[bot]
7e826cd4f5 Bump react-router from 7.1.3 to 7.1.4
Bumps [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router) from 7.1.3 to 7.1.4.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router@7.1.4/packages/react-router)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-31 05:22:30 +00:00
Trevor Buckner
3b150891bc Merge pull request #4016 from naturalcrit/dependabot/npm_and_yarn/dompurify-3.2.4
Bump dompurify from 3.2.3 to 3.2.4
2025-01-31 00:21:09 -05:00
dependabot[bot]
e87acc3f0f Bump dompurify from 3.2.3 to 3.2.4
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.2.3 to 3.2.4.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.2.3...3.2.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-31 05:17:57 +00:00
Trevor Buckner
b1e99f1385 Marked 12.0.2 2025-01-31 00:16:37 -05:00
Trevor Buckner
4e0b6d634d Marked 12.0.1 2025-01-31 00:12:13 -05:00
Trevor Buckner
a72f0f2f34 Merge pull request #4018 from naturalcrit/up-Marked-to-v12
Update Marked.js to v12.0.0
2025-01-31 00:08:01 -05:00
Trevor Buckner
23944f4fe0 smartypants package updated to support higher Marked versions
Next Marked versions break things; need to update incrementally
2025-01-31 00:03:44 -05:00
Trevor Buckner
c244199190 Merge pull request #4015 from naturalcrit/v3.17
Update to v3.17.0
2025-01-30 22:38:26 -05:00
Trevor Buckner
8848c06b15 Rewording. Add more detailed examples. Add Table width syntax 2025-01-30 22:37:55 -05:00
Víctor Losada Hernández
37d56f7365 compile removed items 2025-01-30 23:35:42 +01:00
Víctor Losada Hernández
e2d6b5afc4 Merge branch 'v3.17' of https://github.com/naturalcrit/homebrewery into v3.17 2025-01-30 23:33:54 +01:00
Víctor Losada Hernández
e4df577a32 remove internal changes 2025-01-30 23:33:49 +01:00
Trevor Buckner
f005cb784f Update changelog.md 2025-01-30 14:18:26 -05:00
Víctor Losada Hernández
d733b1f8f8 reformat changelog 2025-01-30 20:02:34 +01:00
Víctor Losada Hernández
d8d403ffb8 Update to v3.17.0 2025-01-30 18:54:27 +01:00
Trevor Buckner
574d68f678 Merge pull request #4004 from naturalcrit/altpageattributes
Alternate \page{curlies}
2025-01-30 09:33:13 -05:00
Trevor Buckner
1b3d7b33c6 Merge branch 'master' into altpageattributes 2025-01-29 12:11:53 -05:00
Trevor Buckner
7f4a304f04 Fix custom CSS variables 2025-01-29 12:10:50 -05:00
Trevor Buckner
d0a06b5cf7 Fix class injection 2025-01-29 12:00:36 -05:00
Trevor Buckner
6dfd44e2f1 Allow spaces between \page and {}
Consistent behavior with other curly injections
2025-01-29 11:48:18 -05:00
David Bolack
f608cb2d65 Merge branch 'issue_3206' of github.com:dbolack-ab/homebrewery into issue_3206 2025-01-28 19:26:37 -06:00
David Bolack
28a1610573 Merge branch 'master' into issue_3206 2025-01-28 19:26:10 -06:00
Trevor Buckner
03e7699b8b Merge pull request #3977 from dbolack-ab/Ubuntu_Document_Upgrade
Ubuntu document upgrade
2025-01-28 10:01:17 -05:00
Trevor Buckner
11f4275e7b Merge branch 'master' into Ubuntu_Document_Upgrade 2025-01-28 10:01:00 -05:00
Trevor Buckner
07fe1c6f19 Merge pull request #3978 from dbolack-ab/issue_3231
Wrap titles in error messages with pre blocks to prevent rendering.
2025-01-28 09:59:10 -05:00
Trevor Buckner
3e78b03785 Remove lodash again 2025-01-28 00:28:46 -05:00
Trevor Buckner
6a31d612e6 Escape to HTML entities 2025-01-28 00:24:15 -05:00
Trevor Buckner
ecd8869097 Add a comment 2025-01-28 00:17:08 -05:00
Trevor Buckner
73c2be147c Custom escape function 2025-01-28 00:13:51 -05:00
Trevor Buckner
caa290f580 Merge branch 'master' into pr/3978 2025-01-27 23:34:59 -05:00
Trevor Buckner
d69288076a Change to _.escape() to escape HTML characters 2025-01-27 23:34:50 -05:00
Trevor Buckner
df00160bc4 Merge branch 'master' into pr/4005 2025-01-27 23:29:28 -05:00
Trevor Buckner
be18843b09 Allow empty braces: \page{} 2025-01-27 23:27:03 -05:00
Trevor Buckner
f1ff032e1e Extract repeated pagebreak regex into a constant 2025-01-27 23:24:25 -05:00
Trevor Buckner
36df121cf6 Lint 2025-01-27 23:10:37 -05:00
Trevor Buckner
c22bb7fb92 Merge branch 'master' into altpageattributes 2025-01-27 23:06:34 -05:00
Trevor Buckner
b94bb38922 Merge pull request #4012 from naturalcrit/dependabot/npm_and_yarn/babel/preset-env-7.26.7
Bump @babel/preset-env from 7.26.0 to 7.26.7
2025-01-27 13:12:28 -05:00
dependabot[bot]
1576a946b0 Bump @babel/preset-env from 7.26.0 to 7.26.7
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.26.0 to 7.26.7.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.26.7/packages/babel-preset-env)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-27 18:09:34 +00:00
Trevor Buckner
4de0a11f1a Merge pull request #4009 from naturalcrit/dependabot/npm_and_yarn/babel/core-7.26.7
Bump @babel/core from 7.26.0 to 7.26.7
2025-01-27 13:08:16 -05:00
dependabot[bot]
66fd9e188b Bump @babel/core from 7.26.0 to 7.26.7
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.26.0 to 7.26.7.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.26.7/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>
2025-01-27 16:36:51 +00:00
Víctor Losada Hernández
a0f44a088f Merge pull request #4013 from naturalcrit/dependabot/npm_and_yarn/stylelint-16.14.1
Bump stylelint from 16.13.2 to 16.14.1
2025-01-27 17:35:26 +01:00
dependabot[bot]
fb20be833c Bump stylelint from 16.13.2 to 16.14.1
Bumps [stylelint](https://github.com/stylelint/stylelint) from 16.13.2 to 16.14.1.
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint/compare/16.13.2...16.14.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-27 16:32:07 +00:00
Víctor Losada Hernández
fc43f95ea5 Merge pull request #4011 from naturalcrit/dependabot/npm_and_yarn/eslint-9.19.0
Bump eslint from 9.18.0 to 9.19.0
2025-01-27 17:30:13 +01:00
dependabot[bot]
29d04fe57d Bump eslint from 9.18.0 to 9.19.0
Bumps [eslint](https://github.com/eslint/eslint) from 9.18.0 to 9.19.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/v9.18.0...v9.19.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-27 03:42:09 +00:00
Trevor Buckner
bd32f5a1b8 Merge branch 'master' into altpageattributes 2025-01-24 18:54:44 -05:00
David Bolack
98c353b9fe Merge branch 'master' into writeinBrewTheme 2025-01-24 14:31:28 -06:00
David Bolack
41b80422c5 Merge branch 'master' into Ubuntu_Document_Upgrade 2025-01-24 14:25:37 -06:00
David Bolack
c1f608d02f Merge branch 'master' into issue_3231 2025-01-24 14:12:50 -06:00
David Bolack
abc830eda2 Change backticks to <pre> literals. 2025-01-24 14:09:13 -06:00
David Bolack
60b6dbb388 Workaround for unclosed <pre> blocks before rendering.
Unsure if this is a fix you really need but it resolves the issue posted.
2025-01-24 13:55:48 -06:00
Trevor Buckner
7610466ee4 Off by 1 error 2025-01-24 01:48:18 -05:00
Trevor Buckner
9f8831eed6 Adjust display and page count when first line has \page 2025-01-24 01:16:55 -05:00
Trevor Buckner
0ac981586f Clean up 2025-01-24 01:16:22 -05:00
Víctor Losada Hernández
fc085111db Merge pull request #4001 from naturalcrit/revert-react-frame
revert react frame update
2025-01-23 13:59:31 +01:00
Víctor Losada Hernández
5e03d97869 revert react frame update 2025-01-23 13:56:07 +01:00
Trevor Buckner
a11ae6655e Merge branch 'master' into altpageattributes 2025-01-23 01:01:56 -05:00
Trevor Buckner
2471de20a9 Merge pull request #4000 from naturalcrit/CurlyStylesAsKeyValues
Parse mustache "style" properties into object instead of string
2025-01-23 01:00:48 -05:00
Trevor Buckner
8e99d47869 Parse mustache "style" properties into object instead of string 2025-01-23 00:54:07 -05:00
Trevor Buckner
eebc9c2bfa commit changes so far 2025-01-22 15:04:33 -05:00
Víctor Losada Hernández
bd5c85147d Merge pull request #3996 from naturalcrit/dependabot/npm_and_yarn/react-router-7.1.3
Bump react-router from 7.1.2 to 7.1.3
2025-01-21 23:27:17 +01:00
Víctor Losada Hernández
7f7a8338ff Merge branch 'master' into dependabot/npm_and_yarn/react-router-7.1.3 2025-01-21 23:24:38 +01:00
Trevor Buckner
2a9945f09f Extract common function to merge HTML tags 2025-01-21 16:14:36 -05:00
G.Ambatte
b7241f79cb Merge branch 'master' into headerNaxExtension 2025-01-22 08:46:42 +13:00
dependabot[bot]
76ccbfbf20 Bump react-router from 7.1.2 to 7.1.3
Bumps [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router) from 7.1.2 to 7.1.3.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router@7.1.3/packages/react-router)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-20 09:12:11 +00:00
Víctor Losada Hernández
77c58eae2e Merge pull request #3997 from naturalcrit/dependabot/npm_and_yarn/stylelint-config-recess-order-6.0.0
Bump stylelint-config-recess-order from 5.1.1 to 6.0.0
2025-01-20 10:10:54 +01:00
dependabot[bot]
4a2b8dc261 Bump stylelint-config-recess-order from 5.1.1 to 6.0.0
Bumps [stylelint-config-recess-order](https://github.com/stormwarning/stylelint-config-recess-order) from 5.1.1 to 6.0.0.
- [Release notes](https://github.com/stormwarning/stylelint-config-recess-order/releases)
- [Changelog](https://github.com/stormwarning/stylelint-config-recess-order/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stormwarning/stylelint-config-recess-order/compare/v5.1.1...v6.0.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-20 03:44:58 +00:00
Víctor Losada Hernández
fa1a0e2351 Merge pull request #3908 from dbolack-ab/justifiedParagraphs
V4 proposed aligned paragraph tokens
2025-01-17 19:05:09 +01:00
Víctor Losada Hernández
f7b36a9b05 Merge branch 'master' into justifiedParagraphs 2025-01-17 19:04:48 +01:00
Víctor Losada Hernández
f4ce2437a7 Merge pull request #3995 from naturalcrit/dependabot/npm_and_yarn/react-router-7.1.2
Bump react-router from 7.1.1 to 7.1.2
2025-01-17 19:03:59 +01:00
dependabot[bot]
aa34bb44c9 Bump react-router from 7.1.1 to 7.1.2
Bumps [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router) from 7.1.1 to 7.1.2.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router@7.1.2/packages/react-router)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-17 18:00:50 +01:00
Víctor Losada Hernández
e3c90ace73 Merge pull request #3994 from naturalcrit/dependabot/npm_and_yarn/fs-extra-11.3.0
Bump fs-extra from 11.2.0 to 11.3.0
2025-01-17 18:00:37 +01:00
dependabot[bot]
7c1545a07d Bump fs-extra from 11.2.0 to 11.3.0
Bumps [fs-extra](https://github.com/jprichardson/node-fs-extra) from 11.2.0 to 11.3.0.
- [Changelog](https://github.com/jprichardson/node-fs-extra/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jprichardson/node-fs-extra/compare/11.2.0...11.3.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-17 16:52:32 +00:00
Trevor Buckner
953c612830 Merge pull request #3992 from dbolack-ab/issue_3448
Implement suggested fix for 3448
2025-01-17 11:25:08 -05:00
David Bolack
5dbb5499c6 fix test 2025-01-17 10:02:32 -06:00
David Bolack
d4f6c329b8 Add a test! 2025-01-15 17:36:18 -06:00
David Bolack
a574ec0777 Merge branch 'master' into issue_3448 2025-01-15 16:48:01 -06:00
David Bolack
3e5a72fa96 Merge branch 'master' into justifiedParagraphs 2025-01-15 07:06:37 -06:00
Víctor Losada Hernández
4df2a73800 Merge pull request #3991 from naturalcrit/dependabot/npm_and_yarn/stylelint-16.13.2
Bump stylelint from 16.13.1 to 16.13.2
2025-01-15 09:30:52 +01:00
dependabot[bot]
aea9296908 Bump stylelint from 16.13.1 to 16.13.2
Bumps [stylelint](https://github.com/stylelint/stylelint) from 16.13.1 to 16.13.2.
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint/compare/16.13.1...16.13.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-15 08:29:16 +00:00
Víctor Losada Hernández
08eeb57cb0 Merge pull request #3990 from naturalcrit/dependabot/npm_and_yarn/eslint-plugin-jest-28.11.0
Bump eslint-plugin-jest from 28.10.0 to 28.11.0
2025-01-15 09:28:05 +01:00
dependabot[bot]
e5e9a9efe1 Bump eslint-plugin-jest from 28.10.0 to 28.11.0
Bumps [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) from 28.10.0 to 28.11.0.
- [Release notes](https://github.com/jest-community/eslint-plugin-jest/releases)
- [Changelog](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jest-community/eslint-plugin-jest/compare/v28.10.0...v28.11.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-15 03:42:56 +00:00
David Bolack
aafc6fad7d Implement suggested fix for 3488
Per issue
2025-01-14 21:40:15 -06:00
David Bolack
b91f18a8a0 Merge branch 'master' into justifiedParagraphs 2025-01-14 07:02:53 -06:00
David Bolack
20bfff5157 Remove it back? Meh. Just trying to revert to last 2025-01-14 07:00:24 -06:00
David Bolack
3c735e599f Add a CR 2025-01-14 06:59:46 -06:00
David Bolack
4958ade937 Remove V4 cruft that should never have been merged 2025-01-14 06:58:48 -06:00
Víctor Losada Hernández
57dc5d4923 Merge pull request #3986 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.9.5
Bump mongoose from 8.9.4 to 8.9.5
2025-01-14 08:27:37 +01:00
dependabot[bot]
3c5ad74e38 Bump mongoose from 8.9.4 to 8.9.5
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.9.4 to 8.9.5.
- [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/8.9.4...8.9.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-14 08:13:17 +01:00
Víctor Losada Hernández
e988e20f5b Merge pull request #3987 from naturalcrit/dependabot/npm_and_yarn/eslint-plugin-react-7.37.4
Bump eslint-plugin-react from 7.37.3 to 7.37.4
2025-01-14 08:13:00 +01:00
dependabot[bot]
cac6dbd40c Bump eslint-plugin-react from 7.37.3 to 7.37.4
Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.37.3 to 7.37.4.
- [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.37.3...v7.37.4)

---
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>
2025-01-14 08:09:57 +01:00
Víctor Losada Hernández
2461b4ab6a Merge pull request #3985 from naturalcrit/dependabot/npm_and_yarn/stylelint-16.13.1
Bump stylelint from 16.13.0 to 16.13.1
2025-01-14 08:09:03 +01:00
dependabot[bot]
7c4f163042 Bump stylelint from 16.13.0 to 16.13.1
Bumps [stylelint](https://github.com/stylelint/stylelint) from 16.13.0 to 16.13.1.
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint/compare/16.13.0...16.13.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-14 03:57:47 +00:00
G.Ambatte
f6c95fb8b7 Extend header nav to exclude frontCover pages 2025-01-14 08:25:46 +13:00
Víctor Losada Hernández
2fee37239f Merge pull request #3982 from naturalcrit/dependabot/npm_and_yarn/stylelint-config-recommended-15.0.0
Bump stylelint-config-recommended from 14.0.1 to 15.0.0
2025-01-13 13:56:52 +01:00
dependabot[bot]
2cb19848aa Bump stylelint-config-recommended from 14.0.1 to 15.0.0
Bumps [stylelint-config-recommended](https://github.com/stylelint/stylelint-config-recommended) from 14.0.1 to 15.0.0.
- [Release notes](https://github.com/stylelint/stylelint-config-recommended/releases)
- [Changelog](https://github.com/stylelint/stylelint-config-recommended/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint-config-recommended/compare/14.0.1...15.0.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-13 12:54:21 +00:00
Víctor Losada Hernández
913cde44ff Merge pull request #3983 from naturalcrit/dependabot/npm_and_yarn/eslint-9.18.0
Bump eslint from 9.17.0 to 9.18.0
2025-01-13 13:53:12 +01:00
Víctor Losada Hernández
c7ff1fc07f Merge branch 'master' into dependabot/npm_and_yarn/eslint-9.18.0 2025-01-13 13:50:38 +01:00
Víctor Losada Hernández
da42e835c5 Merge pull request #3981 from naturalcrit/dependabot/npm_and_yarn/stylelint-16.13.0
Bump stylelint from 16.12.0 to 16.13.0
2025-01-13 13:50:18 +01:00
dependabot[bot]
7a071496f3 Bump eslint from 9.17.0 to 9.18.0
Bumps [eslint](https://github.com/eslint/eslint) from 9.17.0 to 9.18.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/v9.17.0...v9.18.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-13 03:36:04 +00:00
dependabot[bot]
b8d65f2f56 Bump stylelint from 16.12.0 to 16.13.0
Bumps [stylelint](https://github.com/stylelint/stylelint) from 16.12.0 to 16.13.0.
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint/compare/16.12.0...16.13.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-13 03:35:40 +00:00
David Bolack
9c197ea25a Merge branch 'master' into issue_3231 2025-01-12 13:52:37 -06:00
David Bolack
d75db5d378 Merge branch 'master' into justifiedParagraphs 2025-01-12 13:51:28 -06:00
Víctor Losada Hernández
a2538bed20 Merge pull request #3503 from naturalcrit/dependabot/npm_and_yarn/react-frame-component-5.2.7
Bump react-frame-component from 4.1.3 to 5.2.7
2025-01-11 16:50:46 +01:00
dependabot[bot]
69c45d63a4 Bump react-frame-component from 4.1.3 to 5.2.7
Bumps [react-frame-component](https://github.com/ryanseddon/react-frame-component) from 4.1.3 to 5.2.7.
- [Release notes](https://github.com/ryanseddon/react-frame-component/releases)
- [Commits](https://github.com/ryanseddon/react-frame-component/compare/v4.1.3...v5.2.7)

---
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>
2025-01-11 15:46:07 +00:00
David Bolack
80003f6c57 Return overremoved backtick 2025-01-11 08:44:11 -06:00
David Bolack
9d67724da9 Wrap titles in error messages with pre blocks to prevent rendering. 2025-01-10 23:22:22 -06:00
David Bolack
3578a7e1e2 Updated for last three LTS releases 2025-01-10 22:52:18 -06:00
David Bolack
533586f516 Rough draft of update. 2025-01-10 21:09:50 -06:00
David Bolack
591ccf564c Working changes 2025-01-10 20:22:33 -06:00
Trevor Buckner
ecc91af1d6 Merge pull request #3973 from naturalcrit/dependabot/npm_and_yarn/core-js-3.40.0
Bump core-js from 3.39.0 to 3.40.0
2025-01-10 15:53:33 -05:00
Trevor Buckner
4ff043f759 Merge branch 'master' into dependabot/npm_and_yarn/core-js-3.40.0 2025-01-10 15:09:51 -05:00
Trevor Buckner
84e18aae5a Merge pull request #3976 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.9.4
Bump mongoose from 8.9.3 to 8.9.4
2025-01-10 15:09:05 -05:00
Trevor Buckner
b53bda937a Merge pull request #3975 from dbolack-ab/issue_3974
Apply fix to clear error.
2025-01-10 15:08:52 -05:00
David Bolack
4db4bba73f Merge branch 'master' into issue_3974 2025-01-10 11:19:13 -06:00
Víctor Losada Hernández
2c2e6d6027 Merge pull request #3589 from G-Ambatte/experimentalHeaderNavigation
Experimental Header Navigation
2025-01-10 11:37:54 +01:00
David Bolack
1aeea034d2 Requested corrections? 2025-01-09 22:34:35 -06:00
dependabot[bot]
63bd483b3e Bump mongoose from 8.9.3 to 8.9.4
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.9.3 to 8.9.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/8.9.3...8.9.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-10 03:51:06 +00:00
G.Ambatte
19cb24d8db Add explanatory comments to HeaderNav.jsx 2025-01-10 16:48:02 +13:00
David Bolack
96ebe0f617 Apply fix to clear error. 2025-01-09 16:42:55 -06:00
G.Ambatte
eb3178bf80 Update nav item selector 2025-01-09 14:17:41 +13:00
G.Ambatte
a72f47df46 Add identifier to ToC pages in header nav 2025-01-09 12:53:52 +13:00
G.Ambatte
a9823d39e2 Update selection query 2025-01-09 12:29:18 +13:00
G.Ambatte
6ec65eee23 Skip Table of Contents pages 2025-01-09 08:13:59 +13:00
G.Ambatte
9c2610ff40 Add guard clause to prevent empty nav lines 2025-01-09 08:07:59 +13:00
David Bolack
2d47cd2a76 Formatting cleanup 2025-01-08 09:28:37 -06:00
David Bolack
6eb938bb37 Change theme button toggle to be a bit more obvious. 2025-01-08 09:25:16 -06:00
David Bolack
94a431eec8 Update tests. 2025-01-07 22:28:12 -06:00
David Bolack
4eb71b1220 Merge branch 'master' into writeinBrewTheme 2025-01-07 22:16:39 -06:00
David Bolack
74122d9057 Display name of write in theme next to write-in
Clear user's active ThemeBundle when an incomplete/broken/invalid writein.

Needs theming help.
2025-01-07 22:11:01 -06:00
Trevor Buckner
914521cada Merge branch 'master' into experimentalHeaderNavigation 2025-01-07 22:49:05 -05:00
Trevor Buckner
70bda94033 Lint Toolbar.jsx 2025-01-07 22:47:18 -05:00
Trevor Buckner
915137af5e Lint BrewRenderer.jsx 2025-01-07 22:47:04 -05:00
dependabot[bot]
7516c0cbd3 Bump core-js from 3.39.0 to 3.40.0
Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.39.0 to 3.40.0.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/commits/v3.40.0/packages/core-js)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-08 03:46:18 +00:00
Trevor Buckner
fdfae9a771 Merge branch 'master' into experimentalHeaderNavigation 2025-01-07 22:43:29 -05:00
Trevor Buckner
8cc693461d Lint EditPage.jsx 2025-01-07 22:43:06 -05:00
David Bolack
e7f8cda6ae Merge branch 'master' into writeinBrewTheme 2025-01-07 20:36:53 -06:00
David Bolack
b9f7e820c7 Functionally? working. 2025-01-07 20:36:38 -06:00
Víctor Losada Hernández
26cc272b37 Merge pull request #3972 from G-Ambatte/pr/3841
Error Bar refactor - fixes
2025-01-07 21:53:04 +01:00
G.Ambatte
bffa6eb0c9 Limit max-height to prevent overflow
Co-authored-by: Víctor Losada Hernández <5ecleric.naturalcrit@gmail.com>
2025-01-08 07:22:17 +13:00
G.Ambatte
2779055e50 Stop error bar from blocking menus 2025-01-07 18:02:17 +13:00
G.Ambatte
37d00f1255 Remove dismissKeys check before displaying dialog 2025-01-07 18:01:58 +13:00
G.Ambatte
d9b599e814 Fix error listing 2025-01-07 18:01:17 +13:00
G.Ambatte
40d453bc7c Return if no notifications 2025-01-07 18:00:45 +13:00
Trevor Buckner
6ff0cfe383 Merge branch 'master' into refactor-errorBar-to-functional-and-using-dialog 2025-01-06 12:03:34 -05:00
G.Ambatte
a6b7ed4dd2 Improve link text generation 2025-01-06 23:54:05 +13:00
G.Ambatte
bf0614026d Use classes rather than inline styling for indentation 2025-01-06 23:53:33 +13:00
G.Ambatte
06005009e4 HeaderList now in nav > ul > li 2025-01-06 23:20:52 +13:00
G.Ambatte
cf16566da8 Move Header Navigation button to Toolbar 2025-01-06 22:30:03 +13:00
G.Ambatte
34f104b406 Remove showHeaderNav prop from Edit and Share page BrewRenderer 2025-01-06 22:29:22 +13:00
Trevor Buckner
766ab8f10a Lint 2025-01-05 23:07:53 -05:00
Trevor Buckner
aa4276a50e Move exit condition to start 2025-01-05 23:06:56 -05:00
Trevor Buckner
fbedafb204 typo 2025-01-05 23:04:57 -05:00
Trevor Buckner
85cd7c7336 Move calculation of error states outside of render
Our previous approach was technically bad practice to calculate side-effects inside of the render step. We can separate that out as part of this refactor.

Also use native javascript map instead of lodash.
2025-01-05 23:04:48 -05:00
Trevor Buckner
c137d40037 More alignment 2025-01-05 22:58:48 -05:00
Trevor Buckner
5a9e7850c2 space to tabs 2025-01-05 22:53:30 -05:00
G.Ambatte
6e7342d6f0 Merge branch 'master' into experimentalHeaderNavigation 2025-01-06 16:41:21 +13:00
Trevor Buckner
1598adfa67 Merge pull request #3971 from naturalcrit/dependabot/npm_and_yarn/babel-plugin-transform-import-meta-2.3.2
Bump babel-plugin-transform-import-meta from 2.2.1 to 2.3.2
2025-01-05 22:36:47 -05:00
dependabot[bot]
b49936c24b Bump babel-plugin-transform-import-meta from 2.2.1 to 2.3.2
Bumps [babel-plugin-transform-import-meta](https://github.com/javiertury/babel-plugin-transform-import-meta) from 2.2.1 to 2.3.2.
- [Changelog](https://github.com/javiertury/babel-plugin-transform-import-meta/blob/master/CHANGELOG.md)
- [Commits](https://github.com/javiertury/babel-plugin-transform-import-meta/compare/v2.2.1...v2.3.2)

---
updated-dependencies:
- dependency-name: babel-plugin-transform-import-meta
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-06 03:13:48 +00:00
Trevor Buckner
816f4f75f6 Merge pull request #3970 from naturalcrit/dependabot/npm_and_yarn/marked-extended-tables-1.1.0
Bump marked-extended-tables from 1.0.10 to 1.1.0
2025-01-05 22:12:36 -05:00
dependabot[bot]
a091a18604 Bump marked-extended-tables from 1.0.10 to 1.1.0
Bumps [marked-extended-tables](https://github.com/calculuschild/marked-extended-tables) from 1.0.10 to 1.1.0.
- [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.1.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-06 03:06:16 +00:00
Trevor Buckner
edadb3cb77 Merge pull request #3959 from dbolack-ab/updateDockerInstructions
Update Docker instructions in support of #1930
2025-01-05 15:06:12 -05:00
Trevor Buckner
3749a5c2b1 Merge branch 'master' into updateDockerInstructions 2025-01-05 15:06:03 -05:00
Trevor Buckner
e9b5e4ab0c indent 2025-01-05 15:04:55 -05:00
G.Ambatte
28109d28dc Merge branch 'master' into experimentalHeaderNavigation 2025-01-04 20:22:37 +13:00
Trevor Buckner
7f56797779 Merge pull request #3967 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.9.3
Bump mongoose from 8.9.2 to 8.9.3
2025-01-03 17:51:38 -05:00
G.Ambatte
a95eef0545 Add maximum length, use span for spacing 2025-01-03 13:34:52 +13:00
G.Ambatte
bbf6c3589a Switch from innerText to textContent 2025-01-03 11:53:29 +13:00
G.Ambatte
4a4a14b2ab Add ref correctly, fix typo 2025-01-03 11:37:51 +13:00
G.Ambatte
6b0c3b65b4 Merge branch 'master' into experimentalHeaderNavigation 2025-01-03 11:20:16 +13:00
dependabot[bot]
59006d354f Bump mongoose from 8.9.2 to 8.9.3
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.9.2 to 8.9.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/8.9.2...8.9.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-31 03:43:42 +00:00
David Bolack
fe2d02a24c Work in progress.
Still issues with saving the state  of the theme pulldowns and collecting the written in theme.
2024-12-30 12:28:47 -06:00
David Bolack
7c357a2aa1 Attempt to save state but seems to break brew. 2024-12-29 23:23:48 -06:00
David Bolack
26c9406211 Merge branch 'master' into justifiedParagraphs 2024-12-28 16:02:53 -06:00
David Bolack
5eb8432544 Merge branch 'master' into writeinBrewTheme 2024-12-28 16:02:36 -06:00
David Bolack
fb13a1c98d Merge branch 'master' into updateDockerInstructions 2024-12-28 16:01:46 -06:00
Trevor Buckner
b20eb28a37 Merge pull request #3922 from 5e-Cleric/refactor-share-page-as-functional-comp
Refactor sharepage as functional comp
2024-12-26 19:21:55 -05:00
Trevor Buckner
d84f071c62 Other small cleanup 2024-12-26 19:20:25 -05:00
Trevor Buckner
bc7297de2e Mirror editId logic from shareId 2024-12-26 19:15:33 -05:00
Trevor Buckner
a2c4f73e7d processShareId does not need useCallback() 2024-12-26 19:12:34 -05:00
Trevor Buckner
9804c3933f Remove unneeded dependencies for useEffect
UseEffect is only intended to be called once.

Similarly, handleControlKeys doesn't need "useCallBack" because it will never be passed to a child or trigger any re-render by changing.
2024-12-26 19:09:23 -05:00
Trevor Buckner
e2b0da7830 Merge branch 'master' into refactor-share-page-as-functional-comp 2024-12-26 18:50:48 -05:00
Víctor Losada Hernández
5a5119a367 Merge pull request #3852 from 5e-Cleric/refactor-brewItem-component
Refactor brewItem into functional component
2024-12-26 21:18:48 +01:00
Víctor Losada Hernández
c310a8c1c2 Merge branch 'master' into refactor-brewItem-component 2024-12-26 21:07:44 +01:00
Trevor Buckner
11bfdd89b8 Merge pull request #3965 from naturalcrit/ImplementContentVisibility
Implement content-visibility on pages
2024-12-26 14:59:22 -05:00
Trevor Buckner
6898425435 Merge branch 'master' into ImplementContentVisibility 2024-12-24 01:21:20 -05:00
Trevor Buckner
be2557611e Merge pull request #3964 from naturalcrit/dependabot/npm_and_yarn/eslint-plugin-react-7.37.3
Bump eslint-plugin-react from 7.37.2 to 7.37.3
2024-12-24 01:12:46 -05:00
dependabot[bot]
1a9a726263 Bump eslint-plugin-react from 7.37.2 to 7.37.3
Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.37.2 to 7.37.3.
- [Release notes](https://github.com/jsx-eslint/eslint-plugin-react/releases)
- [Changelog](https://github.com/jsx-eslint/eslint-plugin-react/blob/v7.37.3/CHANGELOG.md)
- [Commits](https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.37.2...v7.37.3)

---
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>
2024-12-24 06:02:15 +00:00
Trevor Buckner
dbf82f69f1 Merge pull request #3963 from naturalcrit/dependabot/npm_and_yarn/react-router-7.1.1
Bump react-router from 7.0.2 to 7.1.1
2024-12-24 01:01:03 -05:00
Trevor Buckner
107e54688b Implement content-visibility on pages 2024-12-24 01:00:32 -05:00
Trevor Buckner
b99282a5a7 Merge pull request #3845 from Gazook89/Intersection-Observer
Intersection Observers for getting "Current Page(s)"
2024-12-24 00:44:08 -05:00
Trevor Buckner
1c0eb720ad Undo 2024-12-24 00:38:36 -05:00
Trevor Buckner
93482f9022 Only list one page when in single page mode 2024-12-24 00:37:03 -05:00
Trevor Buckner
8159c408c8 Move formatVisiblePages
After simplifying, this has become a single-line function used in only one place. Can just be placed directly in the one place it is used.
2024-12-24 00:24:52 -05:00
Trevor Buckner
0632d78f71 Remove toolbar checks for empty visiblePages list
With `centerPage`, ToolBar will never receive an empty visiblePages array. No need to check if visiblepages.length == 0
2024-12-24 00:18:37 -05:00
Trevor Buckner
c0155052ea Further simplifying 2024-12-24 00:06:30 -05:00
Trevor Buckner
628b2542a0 Simplify logic for previous/next buttons 2024-12-24 00:02:55 -05:00
Trevor Buckner
85f1da942f Restore looping over entries. Needed for very fast scrolling 2024-12-23 23:08:30 -05:00
Trevor Buckner
3909d5aef9 remove unused iFrameRef
iFrameRef is not used anywhere
2024-12-23 22:48:57 -05:00
Trevor Buckner
f0e047e7cc Remove loop on intersectionObserver entries
Guaranteed to only be one entry each time, since we are attaching each page to its own observers.
2024-12-23 22:43:37 -05:00
dependabot[bot]
a1237305d7 Bump react-router from 7.0.2 to 7.1.1
Bumps [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router) from 7.0.2 to 7.1.1.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router@7.1.1/packages/react-router)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-24 03:11:17 +00:00
Trevor Buckner
d588a92147 Change page range to only display a single range
Having multiple page ranges visible is a weird edge case that only happens in two-page view. Simplifying logic to just group all page ranges together if a middle page is partly obscured.
2024-12-23 18:37:20 -05:00
Trevor Buckner
2b7a1e1cb2 Reduce overlapping observer handlers
Combine handlePageVisibilityChange and handleCenterPageChange to reduce some of the infrastructure burden for handling centerPage.
2024-12-23 18:35:36 -05:00
Trevor Buckner
c8efca3120 useCallBack is not needed here. 2024-12-23 17:22:50 -05:00
Trevor Buckner
a53eacf055 remove CenterPage from ToolBar props
centerPage is not used in the toolbar component.
2024-12-23 17:17:13 -05:00
Trevor Buckner
1b10a4001a Merge branch 'master' into pr/3845 2024-12-23 11:37:40 -05:00
Trevor Buckner
75e71dd6f5 Merge pull request #3960 from G-Ambatte/addGoogleRefreshInfoToErrorPage-#3955
Add google refresh info to error page #3955
2024-12-22 22:31:31 -05:00
Trevor Buckner
3f87b9f7d3 Merge branch 'master' into addGoogleRefreshInfoToErrorPage-#3955 2024-12-22 22:30:04 -05:00
Trevor Buckner
32561cf368 Moving to just HBErrorCode 01
02 is specifically for 404 errors when the file is actually missing. In that case, refreshing credentials probably won't work. (We should update the errorNav to make this distinction as well.)
2024-12-22 22:19:02 -05:00
Trevor Buckner
bf94cdcb6f Merge pull request #3961 from naturalcrit/toWellFormedPolyfill
Use project babel config for buildHomebrew script
2024-12-22 21:39:14 -05:00
Trevor Buckner
e8eedcf6d6 Import polyfill from core-js
Possible to have babel automatically detect and import polyfills as needed, but Browserify just can't handle it. Manually importing the one troublesome one into the root of our project.
2024-12-22 21:32:30 -05:00
Trevor Buckner
92d1238a46 Use project babel config for buildHomebrew script
Jest uses the babel.config file already. Might as well all use the same config.
2024-12-22 21:31:31 -05:00
G.Ambatte
fcfd3171bd Tweak start of instructions 2024-12-22 18:00:27 +13:00
G.Ambatte
9a6cf8c5d2 Linter fix 2024-12-22 17:53:14 +13:00
G.Ambatte
91d928fd8a End list properly 2024-12-22 17:52:58 +13:00
G.Ambatte
bca653bc4d Add instructions to HBErrorCode 01 & 02 2024-12-22 17:52:09 +13:00
David Bolack
2bedc6d7d4 Updates to docker files and cooresponding documentation. 2024-12-20 21:30:19 -06:00
David Bolack
674fb6ff57 Update Docker instructions in support of #1930
Updates README.DOCKER.md and Dockerfile
2024-12-20 20:33:12 -06:00
David Bolack
79c8309291 Add circleci 2024-12-20 19:54:25 -06:00
David Bolack
9745daf6e2 Merge branch 'master' into writeinBrewTheme 2024-12-20 15:19:06 -06:00
David Bolack
90632b78ce Add direct tests for paragraph justification 2024-12-20 14:58:56 -06:00
David Bolack
f71850d8b1 Merge branch 'master' into justifiedParagraphs 2024-12-20 14:55:30 -06:00
Trevor Buckner
dceb5e516b Merge pull request #3909 from dbolack-ab/horizontalSpace
V4 proposed non-breaking space token
2024-12-20 15:42:58 -05:00
Trevor Buckner
adb1db1d3c Revert one more regex change 2024-12-20 15:39:57 -05:00
David Bolack
e8d1e632b4 Merge branch 'master' into horizontalSpace 2024-12-20 14:08:31 -06:00
David Bolack
50fcffb253 Revert exclusion on single definition list regex
This permits  `Term ::> Definition` to process as a single line definition list
2024-12-20 14:06:20 -06:00
Trevor Buckner
aae5367ad2 Add test case for single-line definition list 2024-12-20 11:01:55 -05:00
Trevor Buckner
40b0c1ce3a Merge pull request #3957 from naturalcrit/dependabot/npm_and_yarn/eslint-plugin-jest-28.10.0
Bump eslint-plugin-jest from 28.9.0 to 28.10.0
2024-12-20 10:38:26 -05:00
dependabot[bot]
ba83dfacd9 Bump eslint-plugin-jest from 28.9.0 to 28.10.0
Bumps [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) from 28.9.0 to 28.10.0.
- [Release notes](https://github.com/jest-community/eslint-plugin-jest/releases)
- [Changelog](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jest-community/eslint-plugin-jest/compare/v28.9.0...v28.10.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-20 04:26:51 +00:00
Trevor Buckner
2717e6a9a4 Merge pull request #3956 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.9.2
Bump mongoose from 8.9.1 to 8.9.2
2024-12-19 23:25:40 -05:00
Trevor Buckner
d576bddd32 Merge pull request #3958 from naturalcrit/Add-missing-test-suites-to-circleci
Add emoji tests to circleci
2024-12-19 23:25:26 -05:00
Trevor Buckner
fde21868cd Add emoji tests to circleci 2024-12-19 23:20:01 -05:00
Trevor Buckner
ed8c4d0eef Add tests to circleCi 2024-12-19 23:14:32 -05:00
Trevor Buckner
6e9d293bbe Rename tests to "Non-breaking Spaces"
Hard Breaks name was leftover from copying the `::::` test file.
2024-12-19 23:09:43 -05:00
dependabot[bot]
7e1312805f Bump mongoose from 8.9.1 to 8.9.2
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.9.1 to 8.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/8.9.1...8.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>
2024-12-20 03:38:26 +00:00
David Bolack
d629fa1731 Merge branch 'master' into horizontalSpace 2024-12-19 17:45:51 -06:00
David Bolack
6301a66fd3 Add additional tests 2024-12-19 17:44:48 -06:00
Trevor Buckner
980a7bd57e Merge pull request #3954 from naturalcrit/dependabot/npm_and_yarn/globals-15.14.0
Bump globals from 15.13.0 to 15.14.0
2024-12-18 23:52:01 -05:00
Trevor Buckner
6b0022ad00 Merge branch 'master' into dependabot/npm_and_yarn/globals-15.14.0 2024-12-18 23:22:22 -05:00
Trevor Buckner
0f33973e58 Merge pull request #3953 from G-Ambatte/fixAdminAddedAsAuthor-#3952
Fix admin added as author #3952
2024-12-18 23:22:06 -05:00
G.Ambatte
7a41a140fd Merge branch 'master' into fixAdminAddedAsAuthor-#3952 2024-12-19 17:00:26 +13:00
Trevor Buckner
57467701d0 Fetch Google Brew if only stub requested but nothing found
/update/ requests only the stub for updating. But if no stub exists, we should fetch the full brew so we return *something*.
2024-12-18 23:00:01 -05:00
dependabot[bot]
9dbfb26e6c Bump globals from 15.13.0 to 15.14.0
Bumps [globals](https://github.com/sindresorhus/globals) from 15.13.0 to 15.14.0.
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v15.13.0...v15.14.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-19 03:47:25 +00:00
G.Ambatte
7a169cbd9e Linter clean up 2024-12-19 16:20:28 +13:00
G.Ambatte
2dc8a8fbe9 Remove req.account from update request 2024-12-19 16:20:04 +13:00
Trevor Buckner
5f14f656ef Logging 2024-12-18 17:23:38 -05:00
Trevor Buckner
6e8a0d7314 current user owns 0-author brew only if edit mode
Previous code was treating /share/ visits to google brews with no stub as visits by owner, thus using their own credentials to open the file instead of serviceaccount
2024-12-18 17:07:09 -05:00
Trevor Buckner
e61144beb8 Mark as owner if stub doesn't exist
Old Google Drive files without a stub have no author, so if no stub exists, consider the current user the owner.
2024-12-18 13:45:53 -05:00
Trevor Buckner
64b792c645 Fix case where no stub is found
When retrieving a Google Brew with no stub yet, if the user is not logged in or has expired credentials, we enter this error handler. However, the error message itself tries to send a list of authors.

If there was no stub, we crash here with a 500 error.

This adds conditional operator to any stub value so we can send the actual "not logged in" error in case of no stub.
2024-12-18 13:02:14 -05:00
Trevor Buckner
aee5b7a8cc Require user to be logged in to change name 2024-12-18 12:14:08 -05:00
David Bolack
99d3d28754 Correct end of match criteria for justified paragraph to account for end of stream 2024-12-17 21:48:11 -06:00
David Bolack
912f9f0cf6 Remove extraneous linefeeds in horizontalbreaks 2024-12-17 21:40:56 -06:00
David Bolack
c63b6ffaf0 Add test for a pair of inline horizontal breaks 2024-12-17 21:38:32 -06:00
David Bolack
0c90d1a14d Merge branch 'master' into horizontalSpace 2024-12-17 21:35:26 -06:00
David Bolack
08b0f47ea2 Fix Regex for Justified paragraphs 2024-12-17 21:33:33 -06:00
David Bolack
f9b42a30f7 Merge branch 'master' into justifiedParagraphs 2024-12-17 20:34:24 -06:00
Trevor Buckner
0148eafce0 Merge pull request #3951 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.9.1
Bump mongoose from 8.9.0 to 8.9.1
2024-12-17 19:34:44 -05:00
dependabot[bot]
a3ec5b8d3b Bump mongoose from 8.9.0 to 8.9.1
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.9.0 to 8.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/8.9.0...8.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>
2024-12-17 03:25:20 +00:00
Trevor Buckner
4ded48df1e Merge pull request #3905 from naturalcrit/fixContentNegotiationTestFail-#3904
Fixes #3904 - content negotiation test failure
2024-12-16 18:11:52 -05:00
Trevor Buckner
bc14246fe7 fix import 2024-12-16 17:58:08 -05:00
Trevor Buckner
fcf985a115 Restore content-negotiation test 2024-12-16 17:42:06 -05:00
Trevor Buckner
a060fd123c Merge branch 'master' into fixContentNegotiationTestFail-#3904 2024-12-16 17:39:34 -05:00
Víctor Losada Hernández
7c7e143365 Merge pull request #3950 from naturalcrit/quickfix-CORS
Remove app.js logs to avoid cluttering and buffer overflow errors in heroku
2024-12-16 22:16:12 +01:00
Víctor Losada Hernández
efa8f3fedf remove unnecessary, cluttering logs 2024-12-16 22:13:14 +01:00
Víctor Losada Hernández
972a93d292 Merge pull request #3949 from naturalcrit/quickfix-CORS
quickfix to the CORS policy
2024-12-16 16:47:09 +01:00
Víctor Losada Hernández
35be1e9b94 quickfix 2024-12-16 16:43:40 +01:00
Trevor Buckner
1a91c390f8 Merge pull request #3948 from naturalcrit/dependabot/npm_and_yarn/stylelint-16.12.0
Bump stylelint from 16.11.0 to 16.12.0
2024-12-16 00:09:18 -05:00
dependabot[bot]
206e4fbda8 Bump stylelint from 16.11.0 to 16.12.0
Bumps [stylelint](https://github.com/stylelint/stylelint) from 16.11.0 to 16.12.0.
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint/compare/16.11.0...16.12.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-16 05:01:24 +00:00
Trevor Buckner
af98cb3867 Merge pull request #3947 from naturalcrit/dependabot/npm_and_yarn/eslint-9.17.0
Bump eslint from 9.16.0 to 9.17.0
2024-12-16 00:00:08 -05:00
dependabot[bot]
f8fc6f7aa4 Bump eslint from 9.16.0 to 9.17.0
Bumps [eslint](https://github.com/eslint/eslint) from 9.16.0 to 9.17.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/v9.16.0...v9.17.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-16 04:59:23 +00:00
Trevor Buckner
eb0fa28a03 Merge pull request #3946 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.9.0
Bump mongoose from 8.8.4 to 8.9.0
2024-12-15 23:58:09 -05:00
Trevor Buckner
4ab1a22eb3 Merge pull request #3863 from 5e-Cleric/fix-reddit-link-generation-crashing-website-if-encodeURI-fails
Fix crashes if title is invalid as URI
2024-12-15 23:57:38 -05:00
Trevor Buckner
962a46a670 Merge branch 'master' into fix-reddit-link-generation-crashing-website-if-encodeURI-fails 2024-12-15 23:46:54 -05:00
Trevor Buckner
cb16b32016 tabs 2024-12-15 23:45:54 -05:00
Trevor Buckner
56f348f7ed Replace with toWellFormed() 2024-12-15 23:44:56 -05:00
dependabot[bot]
b7c99b2d52 Bump mongoose from 8.8.4 to 8.9.0
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.8.4 to 8.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/8.8.4...8.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>
2024-12-16 03:57:07 +00:00
Trevor Buckner
889f80f537 Replace react-router-dom with react-router
react-router-dom has been replaced by react-router, so changing packages
2024-12-14 21:48:13 -05:00
Trevor Buckner
c270a69bb9 Merge pull request #3933 from naturalcrit/dependabot/npm_and_yarn/react-router-dom-7.0.2
Bump react-router-dom from 6.28.0 to 7.0.2
2024-12-14 21:36:20 -05:00
Trevor Buckner
db0df82202 Change imports 2024-12-14 21:31:49 -05:00
Trevor Buckner
1346361f80 Merge branch 'dependabot/npm_and_yarn/react-router-dom-7.0.2' of https://github.com/naturalcrit/homebrewery into dependabot/npm_and_yarn/react-router-dom-7.0.2 2024-12-14 19:13:44 -05:00
dependabot[bot]
fdaf9d4808 Bump react-router-dom from 6.28.0 to 7.0.2
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.28.0 to 7.0.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@7.0.2/packages/react-router-dom)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-15 00:10:44 +00:00
Víctor Losada Hernández
3cdfae4270 Merge pull request #3942 from naturalcrit/re-author-brews-on-batch
Create backend batch re-author framework
2024-12-15 00:09:48 +01:00
Víctor Losada Hernández
a9275698fa add comment to tell future me to remove logs when feature comes 2024-12-14 23:41:05 +01:00
Víctor Losada Hernández
99f2972079 fixes as asked 2024-12-14 23:34:12 +01:00
Víctor Losada Hernández
afc92c4545 fix check client version middleware to stop checking outside calls 2024-12-14 22:30:24 +01:00
Víctor Losada Hernández
b26526a2f1 lint and logging pass prepared for in server auth from this end 2024-12-14 22:24:52 +01:00
Víctor Losada Hernández
4f57f006ce log cookies at auth middleware 2024-12-14 21:20:39 +01:00
Víctor Losada Hernández
666a94cd65 fix log 2024-12-14 21:15:16 +01:00
Víctor Losada Hernández
f0c094e9d8 logs to account middleware 2024-12-14 21:12:35 +01:00
Víctor Losada Hernández
a1c228b1d1 log req account 2024-12-14 21:01:38 +01:00
Víctor Losada Hernández
5e5c637c79 revert api catch on wrong route middleware 2024-12-14 20:59:51 +01:00
Víctor Losada Hernández
d573129f31 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into re-author-brews-on-batch 2024-12-14 20:34:41 +01:00
David Bolack
7c69d2a74d Update tests to match 2024-12-10 23:37:48 -06:00
David Bolack
89bd082967 Shift alignment assignment from CSS to HTML 2024-12-10 23:28:06 -06:00
David Bolack
f4c26053c0 Merge branch 'master' into justifiedParagraphs 2024-12-10 23:22:10 -06:00
David Bolack
abd52f93d8 Merge branch 'master' into horizontalSpace 2024-12-10 23:21:26 -06:00
David Bolack
47d7c69d1b Merge branch 'master' into writeinBrewTheme 2024-12-10 23:20:48 -06:00
Trevor Buckner
57cb334c15 Update pull_request_template.md 2024-12-10 13:35:16 -05:00
Víctor Losada Hernández
c29e1905bf add localhost to allowed origins only if in local, also remake regex 2024-12-10 19:24:23 +01:00
Trevor Buckner
52d00b17a4 Merge branch 'master' into fixContentNegotiationTestFail-#3904 2024-12-10 11:58:05 -05:00
dependabot[bot]
35364c400a Bump react-router-dom from 6.28.0 to 7.0.2
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.28.0 to 7.0.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@7.0.2/packages/react-router-dom)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-10 16:23:58 +00:00
Trevor Buckner
77f0c1bf56 Merge pull request #3944 from naturalcrit/dependabot/npm_and_yarn/dompurify-3.2.3
Bump dompurify from 3.2.2 to 3.2.3
2024-12-10 11:22:39 -05:00
dependabot[bot]
2d281072fa Bump dompurify from 3.2.2 to 3.2.3
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.2.2 to 3.2.3.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.2.2...3.2.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-10 03:53:51 +00:00
Trevor Buckner
870a4c3363 small cleanups 2024-12-09 17:06:26 -05:00
Trevor Buckner
aa951ff96c Small cleanups 2024-12-09 17:04:16 -05:00
Víctor Losada Hernández
83b8f9c3b7 Merge pull request #3809 from 5e-Cleric/adress-small-accessibility-concerns
Adress small accessibility concerns
2024-12-09 22:28:52 +01:00
Víctor Losada Hernández
3a20452214 hide unusable editors 2024-12-09 22:18:15 +01:00
Trevor Buckner
bae9fe939d Merge branch 'master' into Intersection-Observer 2024-12-09 16:16:11 -05:00
Víctor Losada Hernández
3e4ba89ed9 change div selector 2024-12-09 22:11:10 +01:00
Víctor Losada Hernández
2c5c3d40df revert toolbar changes 2024-12-09 22:08:39 +01:00
Víctor Losada Hernández
213240327d resolve issues 2024-12-09 22:05:04 +01:00
Víctor Losada Hernández
eca0f59b40 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into adress-small-accessibility-concerns 2024-12-09 21:52:25 +01:00
Trevor Buckner
51936a1b99 Merge pull request #3936 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.8.4
Bump mongoose from 8.8.3 to 8.8.4
2024-12-09 13:44:42 -05:00
Trevor Buckner
6136b78395 Merge pull request #3943 from naturalcrit/Fix_#2954
Get Google Brews with user auth if owner
2024-12-09 13:44:01 -05:00
Víctor Losada Hernández
81f56ec91d add heroku apps to cors 2024-12-09 18:59:48 +01:00
Trevor Buckner
c7d94b0779 Small cleanup 2024-12-08 23:59:27 -05:00
Trevor Buckner
9758797e2b If user is owner, fetch Google Brew with user auth
Fixes the case where a user can see a Google Brew under their account (`listBrew()` uses their personal auth) but can't actually delete it (`getBrew()`  only uses the serviceAccount). Occurs if a Google brew has lost its permissions somehow (set to "restricted", etc.) such that serviceAccount can no longer interact with it.
2024-12-08 23:42:14 -05:00
Trevor Buckner
74a7983757 Refactor and clean up "getBrew()"
Some redundant logic and sprawling formatting
2024-12-08 23:39:26 -05:00
Víctor Losada Hernández
4eb8abf1e7 Update CORS error message in app.js 2024-12-08 23:46:27 +01:00
Víctor Losada Hernández
23910cc94c add cors policy and rename route 2024-12-08 23:43:32 +01:00
Víctor Losada Hernández
ef0ee78758 revert check client version changes 2024-12-08 23:43:06 +01:00
Víctor Losada Hernández
1b20c00842 log headers 2024-12-08 20:46:02 +01:00
Víctor Losada Hernández
db9212bd12 log req 2024-12-08 20:45:43 +01:00
Víctor Losada Hernández
7348ecbb3d Merge branch 'master' of https://github.com/naturalcrit/homebrewery into re-author-brews-on-batch 2024-12-08 12:07:53 +01:00
Víctor Losada Hernández
31a22703c1 initial commit 2024-12-08 12:05:01 +01:00
Trevor Buckner
33f8f6bf38 Merge branch 'master' into dependabot/npm_and_yarn/mongoose-8.8.4 2024-12-07 21:32:53 -05:00
Trevor Buckner
a62d2bd457 Merge pull request #3937 from naturalcrit/dependabot/npm_and_yarn/express-4.21.2
Bump express from 4.21.1 to 4.21.2
2024-12-06 16:30:42 -05:00
dependabot[bot]
ffa9666bb9 Bump express from 4.21.1 to 4.21.2
Bumps [express](https://github.com/expressjs/express) from 4.21.1 to 4.21.2.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.2/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.21.1...4.21.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-06 21:29:54 +00:00
Trevor Buckner
406f5d4e14 Merge branch 'master' into dependabot/npm_and_yarn/mongoose-8.8.4 2024-12-06 16:29:02 -05:00
Trevor Buckner
ed404d3906 Merge pull request #3935 from naturalcrit/dependabot/npm_and_yarn/babel/preset-react-7.26.3
Bump @babel/preset-react from 7.25.9 to 7.26.3
2024-12-06 16:28:35 -05:00
dependabot[bot]
3178c8722e Bump mongoose from 8.8.3 to 8.8.4
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.8.3 to 8.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/8.8.3...8.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>
2024-12-06 03:07:01 +00:00
David Bolack
b7cb6dc444 Merge branch 'master' into justifiedParagraphs 2024-12-04 21:26:03 -06:00
David Bolack
596c4ad68d Add Tests 2024-12-04 21:24:48 -06:00
dependabot[bot]
14a0f79ac8 Bump @babel/preset-react from 7.25.9 to 7.26.3
Bumps [@babel/preset-react](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-react) from 7.25.9 to 7.26.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.26.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>
2024-12-05 03:16:54 +00:00
David Bolack
e7f4611a00 Merge branch 'master' into horizontalSpace 2024-12-04 20:40:55 -06:00
David Bolack
8492c63f62 Merge branch 'master' into writeinBrewTheme 2024-12-04 20:40:14 -06:00
Trevor Buckner
136a6d4024 Merge pull request #3930 from naturalcrit/dependabot/npm_and_yarn/globals-15.13.0
Bump globals from 15.12.0 to 15.13.0
2024-12-03 20:43:13 -05:00
Trevor Buckner
737e27f062 Merge pull request #3934 from 5e-Cleric/fix-buttons
Fix Vault styles
2024-12-03 20:42:54 -05:00
Víctor Losada Hernández
ee9143fa35 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into fix-buttons 2024-12-03 20:20:42 +01:00
Víctor Losada Hernández
c62bb53660 turn back checkboxes to default, fix button styles and filter bar to correct font. 2024-12-03 20:16:42 +01:00
dependabot[bot]
4e5a971f0a Bump globals from 15.12.0 to 15.13.0
Bumps [globals](https://github.com/sindresorhus/globals) from 15.12.0 to 15.13.0.
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v15.12.0...v15.13.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-02 22:22:41 +00:00
Trevor Buckner
16184f1b8d Merge pull request #3916 from naturalcrit/dependabot/npm_and_yarn/nanoid-5.0.9
Bump nanoid from 5.0.8 to 5.0.9
2024-12-02 17:21:22 -05:00
dependabot[bot]
23bd0309b9 Bump nanoid from 5.0.8 to 5.0.9
Bumps [nanoid](https://github.com/ai/nanoid) from 5.0.8 to 5.0.9.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/5.0.8...5.0.9)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-02 22:17:58 +00:00
Trevor Buckner
20dba6b7b3 Merge pull request #3929 from naturalcrit/dependabot/npm_and_yarn/eslint-9.16.0
Bump eslint from 9.15.0 to 9.16.0
2024-12-02 17:15:55 -05:00
dependabot[bot]
5177c9a64e Bump eslint from 9.15.0 to 9.16.0
Bumps [eslint](https://github.com/eslint/eslint) from 9.15.0 to 9.16.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/v9.15.0...v9.16.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-02 22:04:50 +00:00
Trevor Buckner
d179c18c35 Merge pull request #3928 from naturalcrit/dependabot/npm_and_yarn/dompurify-3.2.2
Bump dompurify from 3.2.1 to 3.2.2
2024-12-02 17:03:16 -05:00
dependabot[bot]
6e4e35c7ad Bump dompurify from 3.2.1 to 3.2.2
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.2.1 to 3.2.2.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.2.1...3.2.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-02 17:27:52 +00:00
Trevor Buckner
6c2721d49f Merge pull request #3924 from naturalcrit/dependabot/npm_and_yarn/stylelint-16.11.0
Bump stylelint from 16.10.0 to 16.11.0
2024-12-02 12:26:19 -05:00
Trevor Buckner
029d61b6ad Merge branch 'master' into dependabot/npm_and_yarn/stylelint-16.11.0 2024-12-02 12:25:48 -05:00
Trevor Buckner
f58040e9a4 Merge pull request #3931 from G-Ambatte/tagsToArrayOnLoad-#3927
Convert any `tags` strings to arrays
2024-12-02 12:25:05 -05:00
Trevor Buckner
9f9948f531 Add comment 2024-12-02 12:23:54 -05:00
G.Ambatte
2743ab869a Merge branch 'master' into tagsToArrayOnLoad-#3927 2024-12-02 17:17:35 +13:00
G.Ambatte
4b21538e3e Add splitTextStyleAndMetadata tests 2024-12-02 17:14:45 +13:00
G.Ambatte
e17db0788c Convert any tags strings to arrays 2024-12-02 16:18:18 +13:00
Trevor Buckner
bea74c3b46 Merge pull request #3926 from dbolack-ab/Issue_3919
Implement Gazook89's suggested fix for missing Page Shadows
2024-12-01 20:57:57 -05:00
David Bolack
e252a39bd2 Implement Gazook89's suggested fix 2024-12-01 11:41:29 -06:00
dependabot[bot]
7ef259ddbe Bump stylelint from 16.10.0 to 16.11.0
Bumps [stylelint](https://github.com/stylelint/stylelint) from 16.10.0 to 16.11.0.
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint/compare/16.10.0...16.11.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-30 17:40:38 +00:00
Trevor Buckner
d18005fad4 Merge pull request #3915 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.8.3
Bump mongoose from 8.8.2 to 8.8.3
2024-11-30 12:39:20 -05:00
Trevor Buckner
86402cdbc8 Merge pull request #3920 from 5e-Cleric/changelog-v3.17.0
v3.16.1 FaQ fix
2024-11-30 12:38:46 -05:00
David Bolack
73c68fd11c Functional first pass.
Needs:

 - [ ] opinions on UI placement
 - [ ] opinions on best choice for displaying a write-in based User Brew ( flip to writin box? Add to drop-down list? )
2024-11-27 21:35:29 -06:00
Víctor Losada Hernández
8c986bb97d initial commit 2024-11-28 00:21:35 +01:00
Trevor Buckner
e28b4e8c20 Merge pull request #3921 from 5e-Cleric/add-vault-to-more-navs
add vault navitem to share and edit pages
2024-11-27 17:50:12 -05:00
Víctor Losada Hernández
7c09680939 add vault navitem to share and edit pages 2024-11-27 23:45:25 +01:00
Víctor Losada Hernández
3f0a6a577f faq new version 2024-11-27 23:28:08 +01:00
dependabot[bot]
6f4cc0d91b Bump mongoose from 8.8.2 to 8.8.3
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.8.2 to 8.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/8.8.2...8.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>
2024-11-27 21:29:38 +00:00
Trevor Buckner
e711a1c207 Merge pull request #3917 from naturalcrit/v3.16.1
Version 3.16.1
2024-11-27 16:28:20 -05:00
Trevor Buckner
add088c2a9 Up version to 3.16.1 2024-11-27 16:26:26 -05:00
Trevor Buckner
6d8415bfeb Merge pull request #3911 from dbolack-ab/autoESM
Fix regression in emoji auto-complete due to ESM update
2024-11-25 12:11:38 -05:00
David Bolack
decb334808 Fix regression in emoji auto-complete due to ESM update 2024-11-25 10:41:11 -06:00
G.Ambatte
7a76c67038 Merge branch 'master' into fixContentNegotiationTestFail-#3904 2024-11-24 20:44:24 +13:00
David Bolack
b45686eb3b Create an element for serial non-breaking spaces as proposed in V4 discussion 2024-11-23 11:18:44 -06:00
David Bolack
deb9c6651f Add Styles for Forced Justifcation Tokens 2024-11-22 20:45:58 -06:00
David Bolack
440ad516df Add justification token testing 2024-11-22 20:39:31 -06:00
David Bolack
929469d0c0 Working feature. 2024-11-22 20:11:14 -06:00
Trevor Buckner
66f71972eb Merge pull request #3860 from naturalcrit/dependabot/npm_and_yarn/nanoid-5.0.8
Bump nanoid from 3.3.4 to 5.0.8
2024-11-21 13:36:36 -05:00
Trevor Buckner
ebe8e1067c Move babel config to separate file
Jest struggles to read all babel configurations if directly inside package.json.

This now allows us to install nanoid 5 and pass all tests with it.
2024-11-21 13:33:32 -05:00
dependabot[bot]
9807cf762b Bump nanoid from 3.3.4 to 5.0.8
Bumps [nanoid](https://github.com/ai/nanoid) from 3.3.4 to 5.0.8.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.3.4...5.0.8)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-21 16:51:39 +00:00
Trevor Buckner
b58563cb42 Merge pull request #3897 from naturalcrit/dependabot/npm_and_yarn/eslint-9.15.0
Bump eslint from 9.14.0 to 9.15.0
2024-11-21 11:37:22 -05:00
dependabot[bot]
7c3f3b87af Bump eslint from 9.14.0 to 9.15.0
Bumps [eslint](https://github.com/eslint/eslint) from 9.14.0 to 9.15.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/v9.14.0...v9.15.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-21 16:32:02 +00:00
Trevor Buckner
e7daad592c Merge pull request #3859 from naturalcrit/dependabot/npm_and_yarn/elliptic-6.6.0
Bump elliptic from 6.5.7 to 6.6.0
2024-11-21 11:30:40 -05:00
Trevor Buckner
992359e239 Merge branch 'master' into dependabot/npm_and_yarn/elliptic-6.6.0 2024-11-21 11:27:47 -05:00
Trevor Buckner
b2546f3458 Merge pull request #3903 from naturalcrit/dependabot/npm_and_yarn/dompurify-3.2.1
Bump dompurify from 3.2.0 to 3.2.1
2024-11-21 11:27:32 -05:00
dependabot[bot]
6f016bf5b6 Bump dompurify from 3.2.0 to 3.2.1
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.2.0 to 3.2.1.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.2.0...3.2.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-21 16:25:09 +00:00
Trevor Buckner
7cd3c69fbd Merge pull request #3898 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.8.2
Bump mongoose from 8.8.1 to 8.8.2
2024-11-21 11:23:50 -05:00
Trevor Buckner
9b1507d4f5 Merge branch 'master' into dependabot/npm_and_yarn/mongoose-8.8.2 2024-11-21 11:21:55 -05:00
Trevor Buckner
2e49bf4fa8 Merge pull request #3902 from naturalcrit/updateToES6Modules
Upgrade server-side code to ESM (import vs require)
2024-11-21 11:21:21 -05:00
G.Ambatte
108d368d45 Add content-negotiation test to CircleCI config 2024-11-21 18:54:23 +13:00
G.Ambatte
bd413cfc55 Add content negotiation test command 2024-11-21 18:53:20 +13:00
G.Ambatte
1af13b4e94 Fixes #3904 - content negotiation test failure 2024-11-21 18:46:59 +13:00
Trevor Buckner
e5624434d6 Update buildAdmin.js 2024-11-20 17:04:23 -05:00
Trevor Buckner
1850173f87 Remove unused dependency 2024-11-20 16:22:48 -05:00
Trevor Buckner
fb9148ada5 Site runs and all tests pass 2024-11-20 16:21:35 -05:00
dependabot[bot]
b857a91ab8 Bump mongoose from 8.8.1 to 8.8.2
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.8.1 to 8.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/8.8.1...8.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>
2024-11-19 03:21:50 +00:00
Trevor Buckner
b7c49218ae Merge pull request #3735 from Gazook89/Functional-Tag-Editor
TagInput - Functional component for tag-like inputs
2024-11-13 13:58:42 -05:00
Trevor Buckner
f4d4334a75 Merge branch 'master' into Functional-Tag-Editor 2024-11-13 13:52:01 -05:00
Víctor Losada Hernández
38b4c285a3 Merge pull request #3890 from Gazook89/Update-core-and-reset
Update Core.less and reset.less
2024-11-12 22:09:16 +01:00
Víctor Losada Hernández
cf46a975aa Merge branch 'master' into Update-core-and-reset 2024-11-12 22:05:27 +01:00
Trevor Buckner
9f693547f7 Merge pull request #3889 from naturalcrit/dependabot/npm_and_yarn/express-static-gzip-2.2.0
Bump express-static-gzip from 2.1.8 to 2.2.0
2024-11-12 13:27:28 -05:00
Trevor Buckner
a69dd998f5 Merge branch 'master' into dependabot/npm_and_yarn/express-static-gzip-2.2.0 2024-11-12 13:16:34 -05:00
Trevor Buckner
f141515446 Merge pull request #3888 from naturalcrit/dependabot/npm_and_yarn/marked-emoji-1.4.3
Bump marked-emoji from 1.4.2 to 1.4.3
2024-11-12 13:16:23 -05:00
dependabot[bot]
f749706cb3 Bump marked-emoji from 1.4.2 to 1.4.3
Bumps [marked-emoji](https://github.com/UziTech/marked-emoji) from 1.4.2 to 1.4.3.
- [Release notes](https://github.com/UziTech/marked-emoji/releases)
- [Changelog](https://github.com/UziTech/marked-emoji/blob/main/release.config.cjs)
- [Commits](https://github.com/UziTech/marked-emoji/compare/v1.4.2...v1.4.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-12 18:15:37 +00:00
dependabot[bot]
b22f3d041c Bump express-static-gzip from 2.1.8 to 2.2.0
Bumps [express-static-gzip](https://github.com/tkoenig89/express-static-gzip) from 2.1.8 to 2.2.0.
- [Release notes](https://github.com/tkoenig89/express-static-gzip/releases)
- [Commits](https://github.com/tkoenig89/express-static-gzip/compare/v2.1.8...v2.2.0)

---
updated-dependencies:
- dependency-name: express-static-gzip
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-12 18:15:31 +00:00
Trevor Buckner
dd8692d82b Merge pull request #3887 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.8.1
Bump mongoose from 8.7.3 to 8.8.1
2024-11-12 13:14:11 -05:00
dependabot[bot]
0d2dfe66bc Bump mongoose from 8.7.3 to 8.8.1
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.7.3 to 8.8.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/8.7.3...8.8.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-12 05:36:16 +00:00
Trevor Buckner
0437635861 Merge pull request #3892 from naturalcrit/dependabot/npm_and_yarn/dompurify-3.2.0
Bump dompurify from 3.1.7 to 3.2.0
2024-11-12 00:35:00 -05:00
Trevor Buckner
a5f12ca0b4 Merge branch 'master' into dependabot/npm_and_yarn/dompurify-3.2.0 2024-11-12 00:27:07 -05:00
Trevor Buckner
07e0a7c1b5 Merge pull request #3820 from G-Ambatte/addAdminFixScriptTool-#3801
Add script fix tool to Admin page #3801
2024-11-12 00:21:05 -05:00
Trevor Buckner
2e9c7b1d9b Shorten label 2024-11-12 00:20:37 -05:00
Trevor Buckner
0ddc3ae5b9 Merge branch 'master' into addAdminFixScriptTool-#3801 2024-11-12 00:16:07 -05:00
Trevor Buckner
8c6c8f861d Automatically re-check for scripts
Adding a separate `keepText` field for the `updateBrew()` API might be a bandaid for something that should be looked at more deeply as a separate refactor, considering `updateBrew()` is configured to just return the stub and not the whole document.

For now, re-scanning for script tags after updating can be as simple as just re-looking up the brew.
2024-11-12 00:08:56 -05:00
dependabot[bot]
107aa34ee4 Bump dompurify from 3.1.7 to 3.2.0
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.1.7 to 3.2.0.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.1.7...3.2.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-12 03:12:02 +00:00
Trevor Buckner
e006826e3e Merge pull request #3891 from dbolack-ab/Issue_3718
Fix Issue 3718 by bounds checking prerender.
2024-11-11 22:04:36 -05:00
David Bolack
4e4463fe4d Fix Issue 3718 by bounds checking prerender. 2024-11-11 11:17:00 -06:00
Gazook89
1a56c393ab Merge branch 'master' into Update-core-and-reset 2024-11-10 21:50:03 -06:00
Gazook89
9bc4b1fb56 Changes to core.less, reset.less, and toolbar
Making some changes to the reset.less so that some default UA button styling is removed.

Then, changing core.less so that the classic "HB" button styling is scoped to a certain class `.colorButton`.  This will make it easier to use the button element in other places.
2024-11-10 21:48:01 -06:00
Gazook89
4bad047f93 Merge branch 'master' into Intersection-Observer 2024-11-10 15:56:03 -06:00
Gazook89
234d484a74 Merge remote-tracking branch 'upstream/master' 2024-11-10 15:55:54 -06:00
G.Ambatte
dc1d40512b Reinstate length check 2024-11-10 21:45:17 +13:00
G.Ambatte
2dafbf2080 Simplify Admin brew lookup function 2024-11-10 20:19:30 +13:00
G.Ambatte
033b7fa44f Lint fix 2024-11-10 19:35:57 +13:00
G.Ambatte
2c4f705072 Merge branch 'addAdminFixScriptTool-#3801' of https://github.com/G-Ambatte/homebrewery into addAdminFixScriptTool-#3801 2024-11-10 19:34:25 +13:00
G.Ambatte
ee811e94e1 Remove error handling that can never trigger 2024-11-10 19:34:19 +13:00
G.Ambatte
fcae147723 Merge branch 'master' into addAdminFixScriptTool-#3801 2024-11-10 19:34:17 +13:00
G.Ambatte
b3793a3330 Simplify scriptCount logic 2024-11-10 19:30:57 +13:00
G.Ambatte
952b67aed3 Remove checkForScript state 2024-11-10 19:29:28 +13:00
G.Ambatte
27f14b042b Remove comment about irrelevant tag cleaning 2024-11-10 19:24:54 +13:00
G.Ambatte
49d30007d3 Merge branch 'addAdminFixScriptTool-#3801' of https://github.com/G-Ambatte/homebrewery into addAdminFixScriptTool-#3801 2024-11-10 19:23:47 +13:00
G.Ambatte
bd26f02ddb Remove getBrew admin regex search 2024-11-10 19:23:42 +13:00
Trevor Buckner
ccc37fc0d5 Merge pull request #3873 from naturalcrit/dependabot/npm_and_yarn/globals-15.12.0
Bump globals from 15.11.0 to 15.12.0
2024-11-10 01:15:53 -05:00
dependabot[bot]
9973999e86 Bump globals from 15.11.0 to 15.12.0
Bumps [globals](https://github.com/sindresorhus/globals) from 15.11.0 to 15.12.0.
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v15.11.0...v15.12.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-10 06:14:56 +00:00
Trevor Buckner
2aec54748a Merge pull request #3871 from naturalcrit/dependabot/npm_and_yarn/eslint-9.14.0
Bump eslint from 9.13.0 to 9.14.0
2024-11-10 01:13:42 -05:00
dependabot[bot]
5585c27cb8 Bump eslint from 9.13.0 to 9.14.0
Bumps [eslint](https://github.com/eslint/eslint) from 9.13.0 to 9.14.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/v9.13.0...v9.14.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-10 06:11:39 +00:00
Trevor Buckner
52ae343309 Merge pull request #3881 from naturalcrit/dependabot/npm_and_yarn/eslint-plugin-jest-28.9.0
Bump eslint-plugin-jest from 28.8.3 to 28.9.0
2024-11-10 01:10:26 -05:00
dependabot[bot]
f8d60fc4da Bump eslint-plugin-jest from 28.8.3 to 28.9.0
Bumps [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) from 28.8.3 to 28.9.0.
- [Release notes](https://github.com/jest-community/eslint-plugin-jest/releases)
- [Changelog](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jest-community/eslint-plugin-jest/compare/v28.8.3...v28.9.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-10 06:08:20 +00:00
Trevor Buckner
69e827a663 Merge pull request #3882 from naturalcrit/dependabot/npm_and_yarn/react-router-dom-6.28.0
Bump react-router-dom from 6.27.0 to 6.28.0
2024-11-10 01:06:58 -05:00
Trevor Buckner
d1d73023a2 Merge branch 'master' into dependabot/npm_and_yarn/react-router-dom-6.28.0 2024-11-10 00:55:34 -05:00
Trevor Buckner
f4af19ed81 Merge pull request #3885 from Gazook89/Fix-dialog.jsx
Fix Dialog.jsx to prevent crashes
2024-11-10 00:06:39 -05:00
Gazook89
bc5a9c9039 lint 2024-11-08 21:57:13 -06:00
Gazook89
f7dfedcd44 give dismisskeys a default 2024-11-08 21:57:13 -06:00
Gazook89
b7b1981bde lint 2024-11-08 21:56:45 -06:00
Gazook89
2e8368d08c give dismisskeys a default 2024-11-08 21:56:35 -06:00
Gazook89
28a7f24989 add scrollToHash method back in
pretty much completely unchanged, was originally moved just to help with merging master in (ie it was erroneously removed)
2024-11-07 20:32:30 -06:00
Gazook89
28855d02a6 dynamic text input width to match characters 2024-11-07 19:46:07 -06:00
Gazook89
650ec04417 fix 'disabled' attribute on min/max of page range 2024-11-07 18:56:19 -06:00
Gazook89
9ef11bca99 lint and refactor 2024-11-07 10:40:44 -06:00
Gazook89
88b34a7ba3 Fix 'current page' input when zoomed in close
When the page is zoomed in very close, such that <30% of the page is in view, it doesn't register changes to the 'current page'.  This fixes that, passing in the 'centerPage' if 'visiblePages' is empty.

I don't love this fix, i think the visiblePages should always have *something* in it, but I can't quite figure out how to set that (since the normal update to visiblePages is happening in an observer that doesn't fire if nothing is in view).
2024-11-07 10:17:43 -06:00
G.Ambatte
c6b0b6a0ea Merge branch 'master' into addAdminFixScriptTool-#3801 2024-11-07 23:31:04 +13:00
Gazook89
9d86384032 refactor styles 2024-11-06 23:07:46 -06:00
Gazook89
a6bc87bcea apply displayOptions to legacy brews as well. 2024-11-06 23:07:03 -06:00
Gazook89
63add047b6 'fit page' zoom button fits two pages in "facing" spread
If the 'facing' spread is active, the 'fit to view' zoom button fits two pages side by side in the view, rather than setting only one page in view.
2024-11-06 23:03:24 -06:00
Gazook89
a0e88bb24f Add comment about future Popover API use 2024-11-06 21:55:30 -06:00
Gazook89
5b14e0e9b5 tweak alignment of spreads
the `safe` keyword for `justify-content`, in combo with `center`, means that the content will be centered in the viewport unless there is not enough space for it.  If there is not enough space, it aligns it to the *start*/left edge, rather than keeping it centered and clipping the left edge of the page.
2024-11-06 21:55:16 -06:00
Gazook89
274e734135 add displayOptions to dependency array for memo
The memoization of the renderPages() method prevents a re-render when something like pageShadows is updated, so displayOptions are added to the dependency array in the memo method.
2024-11-06 21:53:14 -06:00
dependabot[bot]
7c7326b42a Bump react-router-dom from 6.27.0 to 6.28.0
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.27.0 to 6.28.0.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/react-router-dom@6.28.0/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.28.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>
2024-11-07 03:42:03 +00:00
Gazook89
3818424251 Adjust "next page" button
Prior to fix, the "next page" button in the toolbar wouldn't work well if there were multiple pages in view that were in a single 'row'.  This is because the logic is to take the pages that are "visible", take the max of those pages, and then scroll to that page.  But the issue is that if the 'max' page is in the same row as other pages, the range of visible pages doesn't change....the max will always be the same.

So the change here basically runs the scroll function twice-- if the first run results in the same 'max' page as before the scroll, it runs it again but with the target page being "max + 1", which will bump the target to the next row.
2024-11-06 21:24:18 -06:00
Gazook89
2222550669 Merge branch 'master' into Observer-Master-merge 2024-11-06 21:19:35 -06:00
Trevor Buckner
d0cf6eebbb Merge pull request #3869 from 5e-Cleric/fix-splitpane-overflowing-page
Fix-splitpane-overflowing-page
2024-11-05 16:43:59 -05:00
Gazook89
93b9f1d1da Merge branch 'Intersection-Observer' into Observer-Master-merge 2024-11-05 14:03:09 -06:00
Trevor Buckner
0ba838f5ae Merge pull request #3880 from Gazook89/fix-memoization
Fix Memoization
2024-11-05 13:51:48 -05:00
Gazook89
172a3eaadf fix memoization on brewRenderer.jsx 2024-11-05 12:45:41 -06:00
Trevor Buckner
b868ba9406 Merge pull request #3799 from Gazook89/View-Modes
View Modes - Single / Facing Pages / "Flow" arrangements
2024-11-04 16:05:53 -05:00
Gazook89
89a16956b9 Merge branch 'master' into View-Modes 2024-11-04 14:22:54 -06:00
Gazook89
b098d28407 linting 2024-11-04 14:08:06 -06:00
Gazook89
1be1b3b747 small accessibility changes. 2024-11-04 13:55:18 -06:00
Trevor Buckner
f63d2de8f4 Refactor toolbar view options (#2)
* Refactor toolbar view options

* Remove a couple more unused states
2024-11-01 22:19:48 -05:00
Víctor Losada Hernández
626b602a61 last fix 2024-11-01 20:39:45 +01:00
Víctor Losada Hernández
3d7d90104b revert content deletion 2024-11-01 20:37:28 +01:00
Víctor Losada Hernández
2abc2b13f0 wrap encodeURI in try catch 2024-10-30 22:47:17 +01:00
G.Ambatte
422fd7bb57 Merge branch 'master' into addAdminFixScriptTool-#3801 2024-10-30 12:01:42 +13:00
Trevor Buckner
c7c8dafb18 Merge pull request #3816 from G-Ambatte/refactorVersionHistory
Refactor version history to use custom store wrapper
2024-10-29 17:10:22 -04:00
G.Ambatte
ea25ae625a Merge branch 'refactorVersionHistory' of https://github.com/G-Ambatte/homebrewery into refactorVersionHistory 2024-10-30 08:21:56 +13:00
G.Ambatte
ebf900ba24 Remove Proxy version 2024-10-30 08:21:51 +13:00
G.Ambatte
0037c91cc5 Merge branch 'master' into refactorVersionHistory 2024-10-30 08:10:47 +13:00
Trevor Buckner
8a8bf883e6 Merge pull request #3548 from G-Ambatte/fixLinks-#3547
Improve HTML sanitization
2024-10-29 14:20:50 -04:00
Trevor Buckner
17539cb80b Merge branch 'master' into fixLinks-#3547 2024-10-29 14:15:02 -04:00
Trevor Buckner
bb057ba057 Merge pull request #3861 from 5e-Cleric/vault-styles-quickfix
Vault styles quickfix
2024-10-29 14:01:57 -04:00
Trevor Buckner
99ad865311 Merge branch 'master' into vault-styles-quickfix 2024-10-29 13:45:30 -04:00
Víctor Losada Hernández
48baaa33e2 linting 2024-10-29 14:22:51 +01:00
Víctor Losada Hernández
6f07d25101 second fix 2024-10-29 14:20:49 +01:00
Víctor Losada Hernández
fec904b4c6 initial commit 2024-10-29 14:16:45 +01:00
G.Ambatte
a29aca32e7 Display createdAt time 2024-10-29 20:42:53 +13:00
G.Ambatte
6fed42198d Simplify initCustomStore 2024-10-29 19:30:22 +13:00
G.Ambatte
446406758f Merge branch 'master' into refactorVersionHistory 2024-10-29 19:12:59 +13:00
G.Ambatte
2d9da23c25 Merge branch 'master' into addAdminFixScriptTool-#3801 2024-10-29 19:08:49 +13:00
G.Ambatte
b24c9daa08 Update HTML test 2024-10-29 18:15:46 +13:00
G.Ambatte
f5bc490380 Remove type='submit' attribute 2024-10-29 18:10:25 +13:00
G.Ambatte
4673303bc2 Remove unused JSDom package 2024-10-29 17:41:16 +13:00
G.Ambatte
e550ab4046 Remove eslint override from HTML tests 2024-10-29 17:40:55 +13:00
G.Ambatte
be4ba06081 Removed unused themes.json import 2024-10-29 17:32:31 +13:00
G.Ambatte
0fda0673b2 Simplify logic & reduce nesting 2024-10-29 17:27:59 +13:00
G.Ambatte
9edf65c252 Shift to element.remove() 2024-10-29 16:50:44 +13:00
G.Ambatte
3f8ec30f89 Fix broken check for document existence 2024-10-29 16:50:33 +13:00
G.Ambatte
f1bebe3895 Move import to be adjacent to existing requires 2024-10-29 16:36:49 +13:00
G.Ambatte
f5954b03f2 Add comment to reference vue-html-secure pacakge 2024-10-29 16:34:50 +13:00
G.Ambatte
a265723c57 Merge branch 'master' into fixLinks-#3547 2024-10-29 16:32:23 +13:00
Trevor Buckner
ca90e1804a Merge branch 'master' into dependabot/npm_and_yarn/elliptic-6.6.0 2024-10-28 23:26:39 -04:00
Trevor Buckner
e7c0cdae3d Merge pull request #3858 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.7.3
Bump mongoose from 8.7.2 to 8.7.3
2024-10-28 23:26:25 -04:00
dependabot[bot]
db75e0dd66 Bump elliptic from 6.5.7 to 6.6.0
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.7 to 6.6.0.
- [Commits](https://github.com/indutny/elliptic/compare/v6.5.7...v6.6.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-29 03:25:59 +00:00
Trevor Buckner
56d024a2e6 Merge branch 'master' into dependabot/npm_and_yarn/mongoose-8.7.3 2024-10-28 23:25:45 -04:00
Trevor Buckner
f6ed348824 Merge pull request #3857 from naturalcrit/dependabot/npm_and_yarn/babel/preset-env-7.26.0
Bump @babel/preset-env from 7.25.9 to 7.26.0
2024-10-28 23:25:34 -04:00
Trevor Buckner
a4406d953a Merge branch 'master' into dependabot/npm_and_yarn/babel/preset-env-7.26.0 2024-10-28 23:25:05 -04:00
Trevor Buckner
1a41252d70 Merge pull request #3856 from naturalcrit/dependabot/npm_and_yarn/babel/core-7.26.0
Bump @babel/core from 7.25.9 to 7.26.0
2024-10-28 23:24:54 -04:00
Trevor Buckner
97371be26a Merge branch 'master' into dependabot/npm_and_yarn/babel/core-7.26.0 2024-10-28 23:23:08 -04:00
Trevor Buckner
994fbd197a Merge pull request #3855 from 5e-Cleric/refactor-splitpane
Refactor splitpane as a functional component
2024-10-28 15:00:39 -04:00
dependabot[bot]
4995aebb93 Bump mongoose from 8.7.2 to 8.7.3
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.7.2 to 8.7.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/8.7.2...8.7.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-28 03:24:31 +00:00
dependabot[bot]
782fa3a2a0 Bump @babel/preset-env from 7.25.9 to 7.26.0
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.25.9 to 7.26.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.26.0/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>
2024-10-28 03:24:06 +00:00
dependabot[bot]
5f71d2902b Bump @babel/core from 7.25.9 to 7.26.0
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.25.9 to 7.26.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.26.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>
2024-10-28 03:23:52 +00:00
Víctor Losada Hernández
391d0a0bfe remove flickering in divider 2024-10-27 10:20:49 +01:00
Víctor Losada Hernández
782ee7a4ad Merge branch 'master' of https://github.com/naturalcrit/homebrewery into refactor-splitpane 2024-10-27 10:14:30 +01:00
Víctor Losada Hernández
987063422d use storage instead of state to correctly save position while resizing 2024-10-27 10:13:59 +01:00
Trevor Buckner
26afb67f61 Merge pull request #3823 from 5e-Cleric/erase-unnecessary-divs
Clean up DOM
2024-10-26 23:06:17 -04:00
Trevor Buckner
d2f6bc03db Merge branch 'master' into erase-unnecessary-divs 2024-10-26 23:02:40 -04:00
Trevor Buckner
547bedb5f9 Merge pull request #3851 from 5e-Cleric/userpage-to-func-comp
Refactor UserPage as a functional component
2024-10-26 23:00:18 -04:00
Trevor Buckner
1b4d41fc19 Remove error prop
Userpage is never passed `Error` prop from anywhere. Thus we can rename the error state here from `currentError` to just `error`
2024-10-26 22:59:49 -04:00
Trevor Buckner
6f2252635a Fix crash; props need props.var to work 2024-10-26 22:56:29 -04:00
Víctor Losada Hernández
46eac41021 further formatting 2024-10-26 23:03:25 +02:00
Víctor Losada Hernández
43441f3185 last changes as suggested 2024-10-26 22:54:16 +02:00
Víctor Losada Hernández
f2765650f7 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into userpage-to-func-comp 2024-10-26 19:46:55 +02:00
Víctor Losada Hernández
a017c28b02 allow for null error instead of undefined 2024-10-26 19:45:55 +02:00
Víctor Losada Hernández
ef1e0f1faa destructure props as per usual 2024-10-26 19:45:26 +02:00
Víctor Losada Hernández
5dc961505b Merge branch 'userpage-to-func-comp' of https://github.com/5e-Cleric/homebrewery into userpage-to-func-comp 2024-10-26 19:44:08 +02:00
Víctor Losada Hernández
b129ec1469 linting 2024-10-26 19:43:27 +02:00
Víctor Losada Hernández
adcbd7c4c8 Merge branch 'master' into erase-unnecessary-divs 2024-10-26 18:18:49 +02:00
Víctor Losada Hernández
843aa6d769 linting and final pass 2024-10-26 16:45:33 +02:00
Víctor Losada Hernández
8ab9b842fc Merge branch 'master' of https://github.com/naturalcrit/homebrewery into refactor-splitpane 2024-10-26 16:29:08 +02:00
Víctor Losada Hernández
f8b5a8133e initial commit 2024-10-26 16:15:53 +02:00
G.Ambatte
478a541d62 Remove wrapper from file name 2024-10-26 09:58:09 +13:00
G.Ambatte
eb852b8045 Add IDB Proxy 2024-10-26 09:50:07 +13:00
G.Ambatte
07e7f3e70c Merge branch 'master' into refactorVersionHistory 2024-10-25 20:54:34 +13:00
G.Ambatte
fea8f157a7 Change script clean to use Homebrew API update 2024-10-25 17:45:12 +13:00
G.Ambatte
898be28af3 Fix Homebrew API parameter 2024-10-25 11:40:17 +13:00
G.Ambatte
63f6f6d3c6 Fix new getBrew access type 2024-10-25 11:27:28 +13:00
G.Ambatte
ac2de613c5 Change Admin lookup to use Homebrew.API getBrew instead 2024-10-25 11:19:55 +13:00
G.Ambatte
948f03b5b8 Add admin access type to getBrew 2024-10-25 11:18:36 +13:00
G.Ambatte
28894adeab Add error check for no brew found 2024-10-25 11:17:44 +13:00
Víctor Losada Hernández
9770fea3fd update navitems call as suggested
Co-authored-by: Trevor Buckner <calculuschild@gmail.com>
2024-10-24 21:13:49 +02:00
Víctor Losada Hernández
422257743e accept navitems suggestion
Co-authored-by: Trevor Buckner <calculuschild@gmail.com>
2024-10-24 20:39:59 +02:00
G.Ambatte
e3619bb1fc Add global flag to regex 2024-10-25 00:11:02 +13:00
G.Ambatte
db1fdca3ab Automatically check for SCRIPT tags 2024-10-24 20:45:12 +13:00
G.Ambatte
c2f56833f3 Merge branch 'addAdminFixScriptTool-#3801' of https://github.com/G-Ambatte/homebrewery into addAdminFixScriptTool-#3801 2024-10-24 17:21:00 +13:00
G.Ambatte
d3cc5c890b Display number of SCRIPT tags detected in brew 2024-10-24 17:20:55 +13:00
G.Ambatte
8eac8eff4b Merge branch 'master' into addAdminFixScriptTool-#3801 2024-10-24 16:22:29 +13:00
Trevor Buckner
8bede8f0ee Merge pull request #3853 from 5e-Cleric/fix-snippetbar-behaviour
fix snippetbar weirdness
2024-10-23 22:45:39 -04:00
Víctor Losada Hernández
c7894499b1 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into fix-snippetbar-behaviour 2024-10-24 01:25:15 +02:00
Víctor Losada Hernández
55a50ce261 always stretch 2024-10-24 01:23:26 +02:00
Víctor Losada Hernández
5b675918ad real fix for the meta tab 2024-10-24 01:10:47 +02:00
Víctor Losada Hernández
70046e00f8 fix min-width in meta tab 2024-10-24 01:07:52 +02:00
Víctor Losada Hernández
e129eb2f5d Merge branch 'fix-snippetbar-behaviour' of https://github.com/5e-Cleric/homebrewery into fix-snippetbar-behaviour 2024-10-24 01:04:23 +02:00
Víctor Losada Hernández
56c9413ab5 next iteration 2024-10-24 01:04:22 +02:00
Trevor Buckner
671044ca3a Merge pull request #3850 from naturalcrit/dependabot/npm_and_yarn/babel/plugin-transform-runtime-7.25.9
Bump @babel/plugin-transform-runtime from 7.25.7 to 7.25.9
2024-10-23 17:02:34 -04:00
Víctor Losada Hernández
04baabc27d Merge branch 'master' into addAdminFixScriptTool-#3801 2024-10-23 21:25:36 +02:00
dependabot[bot]
4add67086d Bump @babel/plugin-transform-runtime from 7.25.7 to 7.25.9
Bumps [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-runtime) from 7.25.7 to 7.25.9.
- [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.25.9/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>
2024-10-23 19:24:33 +00:00
Víctor Losada Hernández
66451a3b1e Merge branch 'master' into refactorVersionHistory 2024-10-23 21:24:21 +02:00
Trevor Buckner
785041dcd1 Merge pull request #3848 from naturalcrit/dependabot/npm_and_yarn/babel/preset-env-7.25.9
Bump @babel/preset-env from 7.25.8 to 7.25.9
2024-10-23 15:23:39 -04:00
Trevor Buckner
40bb823efa Merge branch 'master' into dependabot/npm_and_yarn/babel/preset-env-7.25.9 2024-10-23 15:22:51 -04:00
dependabot[bot]
0dd5b262f7 Bump @babel/preset-env from 7.25.8 to 7.25.9
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.25.8 to 7.25.9.
- [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.25.9/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>
2024-10-23 19:22:44 +00:00
Trevor Buckner
2ed6aad6f7 Merge pull request #3849 from naturalcrit/dependabot/npm_and_yarn/babel/core-7.25.9
Bump @babel/core from 7.25.8 to 7.25.9
2024-10-23 15:22:31 -04:00
Víctor Losada Hernández
41cbb67155 Merge branch 'master' into fix-snippetbar-behaviour 2024-10-23 21:21:45 +02:00
Trevor Buckner
1ab6ef078e Merge branch 'master' into dependabot/npm_and_yarn/babel/core-7.25.9 2024-10-23 15:21:40 -04:00
Trevor Buckner
25a7af5b70 Merge pull request #3847 from naturalcrit/dependabot/npm_and_yarn/babel/preset-react-7.25.9
Bump @babel/preset-react from 7.25.7 to 7.25.9
2024-10-23 15:21:27 -04:00
dependabot[bot]
5f41decdb6 Bump @babel/core from 7.25.8 to 7.25.9
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.25.8 to 7.25.9.
- [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.25.9/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>
2024-10-23 19:04:33 +00:00
Trevor Buckner
3a1053ad70 Merge branch 'master' into dependabot/npm_and_yarn/babel/preset-react-7.25.9 2024-10-23 15:03:23 -04:00
Trevor Buckner
d768a41746 Merge pull request #3846 from naturalcrit/dependabot/npm_and_yarn/eslint-plugin-react-7.37.2
Bump eslint-plugin-react from 7.37.1 to 7.37.2
2024-10-23 15:03:14 -04:00
Trevor Buckner
f5f22fe0e9 Merge pull request #3805 from 5e-Cleric/add-notification-client-side
Add notification client side
2024-10-23 15:01:14 -04:00
G.Ambatte
27c5f86205 Merge branch 'master' into addAdminFixScriptTool-#3801 2024-10-24 07:32:52 +13:00
G.Ambatte
361d1c1aff Merge branch 'master' into refactorVersionHistory 2024-10-24 07:32:09 +13:00
Víctor Losada Hernández
88e5f26dd8 not render snippets element if empty 2024-10-23 20:16:30 +02:00
Víctor Losada Hernández
ddfccba822 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into add-notification-client-side 2024-10-23 19:48:45 +02:00
Víctor Losada Hernández
069d054e30 remove console logs and lint 2024-10-23 19:47:12 +02:00
Víctor Losada Hernández
1f7ff4386b fix html in notifs 2024-10-23 19:45:47 +02:00
Trevor Buckner
6373c398bc Fix scroll PR when no hash 2024-10-23 13:45:10 -04:00
Víctor Losada Hernández
7a78408415 Merge branch 'add-notification-client-side' of https://github.com/5e-Cleric/homebrewery; branch 'master' of https://github.com/naturalcrit/homebrewery into add-notification-client-side 2024-10-23 19:33:14 +02:00
Víctor Losada Hernández
52311f989d Merge branch 'userpage-to-func-comp' of https://github.com/5e-Cleric/homebrewery into userpage-to-func-comp 2024-10-23 17:03:02 +02:00
Víctor Losada Hernández
b9bf9c7e70 "Refactor UserPage component: removed unnecessary import, updated function signature, and moved useState hook declaration" 2024-10-23 17:03:00 +02:00
Víctor Losada Hernández
49db31426c Merge branch 'master' into refactor-errorBar-to-functional-and-using-dialog 2024-10-23 12:48:42 +02:00
Víctor Losada Hernández
45ada35a11 Merge branch 'master' into userpage-to-func-comp 2024-10-23 12:48:17 +02:00
Víctor Losada Hernández
ce31d30ed7 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into refactor-brewItem-component 2024-10-23 12:48:01 +02:00
Víctor Losada Hernández
68831c759f initial commit 2024-10-23 12:45:13 +02:00
Víctor Losada Hernández
9d2a305f03 initial commit 2024-10-23 09:02:23 +02:00
dependabot[bot]
9cc7799d5c Bump @babel/preset-react from 7.25.7 to 7.25.9
Bumps [@babel/preset-react](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-react) from 7.25.7 to 7.25.9.
- [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.25.9/packages/babel-preset-react)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-23 03:42:08 +00:00
dependabot[bot]
c235695f04 Bump eslint-plugin-react from 7.37.1 to 7.37.2
Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.37.1 to 7.37.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.37.1...v7.37.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>
2024-10-23 03:41:54 +00:00
Gazook89
5ab867f21e adjust prev/next page buttons to meet expectations
i hope
2024-10-22 22:36:13 -05:00
Víctor Losada Hernández
999a96b5ce "Rename dismissKeys to dismisskeys in Dialog component and its usage" 2024-10-22 21:46:57 +02:00
Trevor Buckner
ef5e3ddf4c Merge pull request #3506 from naturalcrit/scroll-to-element
Get external link and scroll to element
2024-10-22 14:10:11 -04:00
Trevor Buckner
d5f498cbf9 Merge branch 'master' into scroll-to-element 2024-10-22 14:09:49 -04:00
Trevor Buckner
5040b9528f cleanup 2024-10-22 14:08:20 -04:00
Trevor Buckner
83a48b8d0c Simplify observer 2024-10-22 13:58:35 -04:00
Trevor Buckner
9fbdd24d01 Cleanup 2024-10-22 13:52:34 -04:00
Trevor Buckner
5b136f651c Call scrollToHash from our existing "frameDidMount`
`frameDidMount` is equivalent to using iframe.addEventListener('load');

Let's not add a new listener and just use the existing event we already have. Functionality still works.
2024-10-22 13:03:12 -04:00
Gazook89
4126188df1 linting 2024-10-21 22:29:58 -05:00
Gazook89
26050e2134 add comment 2024-10-21 22:20:52 -05:00
Gazook89
5c0d6e6012 move formatting of visible pages to toolbar
Doesn't need to be set in brewRenderer state and passed as a prop, when it can just do it's work directly in the toolbar.
2024-10-21 22:18:25 -05:00
Gazook89
de7b13bc15 Add some comments and cleanup
Little changes like removing console.logs and adding comments.
2024-10-21 22:13:12 -05:00
Gazook89
b6bd7ccf67 Merge branch 'master' into Intersection-Observer 2024-10-21 21:33:30 -05:00
Gazook89
822d0c7738 Fix NaN/undefined showing on first load
Removes currentPage as a variable since it's been replaced.
2024-10-21 21:27:06 -05:00
Gazook89
183dd63021 style change on page text input
Reduce the visual prominence of the page input by using a darker background and a text color that matches the rest of the toolbar icons.  Darker background still indicates this is an interactive item (is an input), hopefully.
2024-10-21 21:19:49 -05:00
Gazook89
0afc2ab2e6 modify effect to enable Jump Editor button
This fixes the "jump editor to preview position" button.
2024-10-21 20:43:32 -05:00
Trevor Buckner
effeef0d67 Merge pull request #3842 from naturalcrit/dependabot/npm_and_yarn/eslint-9.13.0
Bump eslint from 9.12.0 to 9.13.0
2024-10-21 13:28:22 -04:00
Trevor Buckner
cf3d5df582 Merge branch 'master' into dependabot/npm_and_yarn/eslint-9.13.0 2024-10-21 11:25:56 -04:00
Trevor Buckner
71cdbf1079 Merge pull request #3843 from naturalcrit/dependabot/npm_and_yarn/superagent-10.1.1
Bump superagent from 10.1.0 to 10.1.1
2024-10-21 11:25:41 -04:00
Trevor Buckner
712db7dfa7 Merge branch 'master' into dependabot/npm_and_yarn/superagent-10.1.1 2024-10-21 11:22:46 -04:00
Trevor Buckner
ed48c6664b Merge pull request #3844 from G-Ambatte/catchIDBErrors
Catch IndexedDB errors
2024-10-21 09:59:29 -04:00
Gazook89
119755e23a Merge branch 'master' into Intersection-Observer 2024-10-21 00:33:56 -05:00
Gazook89
41fdf48ad3 Setup Intersection Observers & more...
Bad commit here with too much stuff.  I apologize.

This sets up two Intersection Observers: the first captures every page that is at least 30% visible inside the `.pages` container, and the second captures every page that has at least one pixel on the horizontal center line of `.pages`.  Both can be arrays of integers (page index).

The "visiblePages" array is duplicated and formatted into a "formattedPages" state, which gets displayed in the toolbar.

The toolbar displays that, unless the user clicks into the page input and enters their own integer (only a single integer, no range), which can then jump the preview to that page on Enter or blur().

The Arrow 'change page' buttons jump the preview back and forth by a 'full set'.
 If one page is viewed at a time, this is moved on page a time, and if 10 pages are viewed at a time it jumps the pages by 10.

Left to do:  adapt the "jump editor to match preview" divider button to work with new "centerPage".
2024-10-21 00:30:45 -05:00
G.Ambatte
917f20cdd5 Merge branch 'master' into catchIDBErrors 2024-10-21 16:27:30 +13:00
G.Ambatte
0c98f832bb Add catch to await calls 2024-10-21 16:21:41 +13:00
dependabot[bot]
41a60e6312 Bump superagent from 10.1.0 to 10.1.1
Bumps [superagent](https://github.com/ladjs/superagent) from 10.1.0 to 10.1.1.
- [Release notes](https://github.com/ladjs/superagent/releases)
- [Changelog](https://github.com/ladjs/superagent/blob/master/HISTORY.md)
- [Commits](https://github.com/ladjs/superagent/compare/v10.1.0...v10.1.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-21 03:20:23 +00:00
dependabot[bot]
5994e0d0b3 Bump eslint from 9.12.0 to 9.13.0
Bumps [eslint](https://github.com/eslint/eslint) from 9.12.0 to 9.13.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/v9.12.0...v9.13.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-21 03:20:07 +00:00
Víctor Losada Hernández
ebdbb39f24 linting 2024-10-20 22:29:14 +02:00
Víctor Losada Hernández
976740dc8b make more concise 2024-10-20 22:21:07 +02:00
Víctor Losada Hernández
cac87b14c7 refactor to func comp and using dialog 2024-10-20 22:07:33 +02:00
Trevor Buckner
c723f820f7 Merge pull request #3635 from naturalcrit/snippet-bar-wrapping
Snippet bar wrapping
2024-10-20 13:04:48 -04:00
Trevor Buckner
0e9021049c lint 2024-10-20 13:00:05 -04:00
Víctor Losada Hernández
1d663ef38d last iteration 2024-10-20 12:19:38 +02:00
Víctor Losada Hernández
d3e11ead54 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into snippet-bar-wrapping 2024-10-20 12:19:26 +02:00
Trevor Buckner
79e1f4caf7 Merge pull request #3838 from naturalcrit/Allow-Markdown/styles-to-update-on-any-text-change
Allow Markdown/Style to update on any text change
2024-10-19 00:11:44 -04:00
Trevor Buckner
59e397a65a Merge branch 'master' into Allow-Markdown/styles-to-update-on-any-text-change 2024-10-19 00:10:35 -04:00
Trevor Buckner
6b066c3fd3 Merge pull request #3837 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.7.2
Bump mongoose from 8.7.1 to 8.7.2
2024-10-18 14:59:10 -04:00
Trevor Buckner
b7413714be Merge branch 'master' into dependabot/npm_and_yarn/mongoose-8.7.2 2024-10-18 12:58:04 -04:00
Trevor Buckner
ec49d5e526 Merge pull request #3836 from dbolack-ab/MigrateGlobaltocToggles
Migrate .tocGlobalH? toggles
2024-10-18 10:56:33 -04:00
Trevor Buckner
d53a271c9f Change to .page and tweak spacing/newlines to match other snippets
All of our "global" style snippets are just set at `.page`, not `.pages`. This still applies globally but is consistent with our current approach.
2024-10-18 10:53:16 -04:00
Trevor Buckner
9d81f50b60 Remove disabled = false
Don't need that tag at all when it's false.
2024-10-18 10:46:59 -04:00
Trevor Buckner
ac766f3b37 Update brewRenderer.jsx 2024-10-18 10:23:56 -04:00
dependabot[bot]
cd09408aa8 Bump mongoose from 8.7.1 to 8.7.2
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.7.1 to 8.7.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/8.7.1...8.7.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-18 03:37:53 +00:00
David Bolack
631ef795b7 Fix .tocGlobalH?
Based on OH DEAR GOD THE LAG! discoveries related to the global toggles, these are being moved from a markup tag to a styles tab insert.
2024-10-17 18:30:31 -05:00
David Bolack
01c4e3ec1f Merge branch 'master' of github.com:naturalcrit/homebrewery 2024-10-17 18:14:45 -05:00
Víctor Losada Hernández
5a75182aff changes as requested, wrapping of editor tools, and linting 2024-10-18 00:52:26 +02:00
Víctor Losada Hernández
8538ccabe6 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into snippet-bar-wrapping 2024-10-17 23:47:02 +02:00
Víctor Losada Hernández
8ef88a4799 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into scroll-to-element 2024-10-17 23:42:57 +02:00
Víctor Losada Hernández
189625c79b adding margin to scroll action to prevent toolbar overlapping 2024-10-17 23:38:27 +02:00
Víctor Losada Hernández
d872a496a7 fix mutation observer integration 2024-10-17 23:38:11 +02:00
Trevor Buckner
a1d2b5314b Merge pull request #3834 from naturalcrit/DisablePagesHasSelector
Disable Global ToC Snippet
2024-10-17 17:05:11 -04:00
Víctor Losada Hernández
9a4473526a move around 2 2024-10-17 22:59:29 +02:00
Víctor Losada Hernández
5077fda3f6 move stuff around for minimal changes 2024-10-17 22:58:14 +02:00
Víctor Losada Hernández
397ae31f56 remove stale changes 2024-10-17 22:56:58 +02:00
Trevor Buckner
f2f06b23fd Disable Global ToC Snippet 2024-10-17 16:42:57 -04:00
Víctor Losada Hernández
87915ef0ef remove unnecessary changes 2024-10-17 22:42:55 +02:00
Víctor Losada Hernández
c9240c7023 fix last line pack-lock 2024-10-17 22:41:24 +02:00
Víctor Losada Hernández
e54d237a19 fix pack-lock 2024-10-17 22:40:53 +02:00
Víctor Losada Hernández
ccfd5578cf Merge branch 'master' of https://github.com/naturalcrit/homebrewery into scroll-to-element 2024-10-17 22:39:28 +02:00
Víctor Losada Hernández
618e865e52 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into add-notification-client-side 2024-10-17 22:29:31 +02:00
Trevor Buckner
4dd07a3c11 Merge pull request #3815 from G-Ambatte/tweakBrewRendererBackgroundStyle
Tweak color of Brew Renderer background text
2024-10-16 16:25:11 -04:00
Trevor Buckner
7888bfa878 Merge branch 'master' into tweakBrewRendererBackgroundStyle 2024-10-16 16:23:47 -04:00
Trevor Buckner
17b77f5460 Merge pull request #3832 from naturalcrit/memoizeRenderPages 2024-10-15 22:41:55 -04:00
Trevor Buckner
d348d1e689 Merge branch 'master' into memoizeRenderPages 2024-10-15 22:41:27 -04:00
Trevor Buckner
2aa60f793d Fix /new
/new starts with no `text` so it will crash without `?.`
2024-10-15 22:39:13 -04:00
Trevor Buckner
72739f28e8 Merge pull request #3831 from naturalcrit/memoizeRenderPages 2024-10-15 22:18:46 -04:00
Trevor Buckner
f1aeea18d4 Only jump when on text panel 2024-10-15 22:07:55 -04:00
Trevor Buckner
321bbba4b8 Rearrange 2024-10-15 22:07:41 -04:00
Trevor Buckner
36af1cdb7f Update brewRenderer.jsx 2024-10-15 21:47:27 -04:00
Trevor Buckner
0813daf01f Merge pull request #3826 from naturalcrit/dependabot/npm_and_yarn/react-router-dom-6.27.0
Bump react-router-dom from 6.26.2 to 6.27.0
2024-10-15 10:39:10 -04:00
dependabot[bot]
6d137d9ca8 Bump react-router-dom from 6.26.2 to 6.27.0
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.26.2 to 6.27.0.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/react-router-dom@6.27.0/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.27.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>
2024-10-15 14:38:35 +00:00
Trevor Buckner
5490cc9fe6 Merge pull request #3825 from naturalcrit/dependabot/npm_and_yarn/stylelint-16.10.0
Bump stylelint from 16.9.0 to 16.10.0
2024-10-15 10:37:15 -04:00
dependabot[bot]
10283e6e45 Bump stylelint from 16.9.0 to 16.10.0
Bumps [stylelint](https://github.com/stylelint/stylelint) from 16.9.0 to 16.10.0.
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint/compare/16.9.0...16.10.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-14 03:49:21 +00:00
David Bolack
154ee06fc4 iMerge branch 'master' of github.com:naturalcrit/homebrewery 2024-10-13 21:27:11 -05:00
Gazook89
810c2140c9 move some toolbar specific styling to toolbar.less 2024-10-13 20:45:05 -05:00
Gazook89
c4fbc8d827 Merge branch 'master' into View-Modes 2024-10-13 09:40:05 -05:00
Gazook89
96ae07a456 Small style change on checkbox inputs 2024-10-13 09:39:41 -05:00
G.Ambatte
0d1291a713 Merge branch 'master' into addAdminFixScriptTool-#3801 2024-10-13 22:47:32 +13:00
Víctor Losada Hernández
3c66907a86 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into scroll-to-element 2024-10-13 11:15:15 +02:00
Víctor Losada Hernández
0663e82fa1 remove unnecessary space in homepage markdown 2024-10-13 10:58:24 +02:00
Víctor Losada Hernández
6e241c5bcd remove splitpane parent 2024-10-13 10:53:05 +02:00
Víctor Losada Hernández
ebe5dca7a9 remove unnecessary child in nav 2024-10-13 10:51:06 +02:00
Gazook89
b33d9264d3 unify terms to 'spreads'
This commit only renames things, changes no logic.  Any mention of "book", "view", or "mode" is renamed in relation to "spreads".

The AnchoredBox.jsx file is renamed to Anchored.jsx

Extra icons are deleted, and the remaining ones are renamed.
2024-10-12 23:25:14 -05:00
Gazook89
0855c5c181 remove errant console.log 2024-10-12 23:12:37 -05:00
Gazook89
1741abc3fe Refactor AnchoredBox for greater flexibility
Big change to how the AnchoredBox component is structured so that it can be used in more than just one spot.  Now composed of the wrapper Anchored, with two children AnchoredTrigger and AnchoredBox, each of which can have their own arbitrary children.

Next steps will involve renaming the component file to Anchored.jsx, moving most styling out of the attached stylesheet (and into brewRenderer.less), and adding props to pass in Anchor Positioning properties.
2024-10-12 23:12:27 -05:00
Trevor Buckner
f1af87ee7e Merge pull request #3821 from naturalcrit/v3.16.0 2024-10-12 23:21:01 -04:00
Trevor Buckner
7dcceb983e Update changelog to v3.16.0 2024-10-12 23:10:13 -04:00
G.Ambatte
63f4104f81 Add UI to Admin page 2024-10-13 13:45:24 +13:00
G.Ambatte
6bc865144a Add cleaning function to API 2024-10-13 13:45:11 +13:00
G.Ambatte
ccafee7a21 Get text from textBin in brew object 2024-10-13 13:44:33 +13:00
G.Ambatte
033a089fd8 Merge branch 'master' into refactorVersionHistory 2024-10-13 12:17:27 +13:00
Gazook89
27f471791d Small change in title phrasing 2024-10-12 13:28:25 -05:00
Gazook89
ae11da2bc7 Fix the styles overriding previous styles
If there were two inputs sending styles to the same target (ie row and column gap), they would override each other.

This change fixes that by deepening the merges.  Admittedly, I turned to cGPT to help me with this as the nesting was throwing me for a loop.  It works, though, and I understand it now that I can read it.
2024-10-12 11:53:52 -05:00
Gazook89
b58b9ca8f0 Merge branch 'View-Modes-Radio-Options' into View-Modes 2024-10-12 11:06:09 -05:00
Gazook89
ba0b3e7d93 Add toggle for Page Shadows
Reworks the pagesStyles to a broader object previewStyles.  This new object has this structure:

```
{
  targetElement : { cssProperty: value }
}
```
2024-10-12 11:05:23 -05:00
Trevor Buckner
6d4b1843ae Fix missed lines from 3.15.2 branch 2024-10-12 00:10:43 -04:00
Gazook89
6fca21b6ed set defaultValue of gap sliders
defaultValue matches the normal styled values of the gap property on the .pages element.

removed the "tooltip" that showed the current value from the range sliders inside the anchoredbox (the gap sliders).
2024-10-11 22:53:38 -05:00
Trevor Buckner
35856ad01e Merge branch 'master' into adress-small-accessibility-concerns 2024-10-11 23:50:39 -04:00
Trevor Buckner
76d6679002 Fix line endings on app.js 2024-10-11 23:50:08 -04:00
Trevor Buckner
4efa1b10f3 Merge pull request #3808 from naturalcrit/v3.15.2 2024-10-11 23:48:34 -04:00
Gazook89
a3dbaf9e6a refactor anchoredBox to handle focus
Refactoring the AnchoredBox component because I wanted to set focus on the trigger button when the expanded box was closed.  Wrapping the trigger into it's own component, with forwardRef, allows for passing the `ref` to the actual DOM node.  Then the `.focus()` method will work on it.
2024-10-11 22:34:40 -05:00
Gazook89
835305bcf6 Add a title to each button
add a role to the toolbr.
2024-10-11 22:32:53 -05:00
Gazook89
395f2d16fa change view mode toggles to indiv buttons
Rather than a single button with three states, it is three buttons.  Went with buttons with `role='radio'` rather than true radios mostly because that is what Radix does.
2024-10-11 22:06:41 -05:00
Gazook89
6cabdc0a67 add alternative icons in
the `-alt` icons have better sizing/readability than the originals.  The originals likely will be removed.

Also adds back in 'fit-width' icon which was mistakenly overwritten earlier.
2024-10-11 22:05:18 -05:00
G.Ambatte
f64e7d3fd7 Shift grabage collection to use delMany instead of a looped del 2024-10-12 10:57:01 +13:00
G.Ambatte
cdbb2fa26a Add IDB custom store wrapper 2024-10-12 10:55:02 +13:00
G.Ambatte
bec830c3b8 Tweak color of Brew Renderer background text 2024-10-12 08:09:51 +13:00
Gazook89
e80588b234 Add icons 2024-10-11 13:51:41 -05:00
Gazook89
73504a3386 Setting a padding-top to avoid pages hugging toolbar 2024-10-11 13:51:06 -05:00
Gazook89
9c4b936ddd bump node to avoid experimental flag issues from another merge 2024-10-11 13:50:40 -05:00
David Bolack
222d49bdca Merge branch 'master' of github.com:naturalcrit/homebrewery 2024-10-11 12:08:57 -05:00
David Bolack
f386be3494 Merge branch 'master' of github.com:naturalcrit/homebrewery 2024-10-11 09:07:15 -05:00
Gazook89
c4074d67f5 Merge branch 'master' into View-Modes 2024-10-10 23:34:26 -05:00
David Bolack
9506be6b65 Revert "Revert --experimental-vm-modules"
This reverts commit 1aabb84731.
2024-10-10 17:41:40 -05:00
David Bolack
1aabb84731 Revert --experimental-vm-modules
Code works but does not work with jest as expected.
2024-10-10 17:40:32 -05:00
Víctor Losada Hernández
766fd40b72 set cursor in code less for disabled elements 2024-10-11 00:35:43 +02:00
Víctor Losada Hernández
3e6884b506 dynamic input width 2024-10-11 00:32:28 +02:00
Víctor Losada Hernández
2118142faa not allowed cursor 2024-10-11 00:16:36 +02:00
Víctor Losada Hernández
2b270ccdb7 linting 2024-10-11 00:14:12 +02:00
Víctor Losada Hernández
08eabf8102 proper snippetbar styles 2024-10-11 00:12:52 +02:00
Víctor Losada Hernández
c1d85bc216 remove annoying class 2024-10-11 00:12:39 +02:00
Víctor Losada Hernández
3a2c213cf8 linting codeeditor.les 2024-10-11 00:02:00 +02:00
Víctor Losada Hernández
99dc0deb08 foldgutter styles 2024-10-11 00:00:57 +02:00
Víctor Losada Hernández
b2c3d620a4 Merge branch 'master' into add-notification-client-side 2024-10-10 13:30:36 +02:00
Víctor Losada Hernández
2d8874acaf move back to conditional showing instead of conditional rendering 2024-10-10 13:17:24 +02:00
Víctor Losada Hernández
001bf4a605 move dismisskeys into state for proper rerender 2024-10-10 12:56:37 +02:00
Víctor Losada Hernández
2b6e166e86 Revert "types react apparently needed?"
This reverts commit 55b5c1e713.
2024-10-10 02:09:52 +02:00
Víctor Losada Hernández
f8c995e59e remove comments 2024-10-10 02:09:11 +02:00
Víctor Losada Hernández
656c9399ef initial commit 2024-10-10 02:06:00 +02:00
Víctor Losada Hernández
55b5c1e713 types react apparently needed? 2024-10-10 01:16:50 +02:00
Víctor Losada Hernández
6456c22c61 testing mutation Observer, don't review this yet 2024-10-09 21:33:26 +02:00
Víctor Losada Hernández
e396a51ad5 Merge branch 'v3.15.2' of https://github.com/naturalcrit/homebrewery into scroll-to-element 2024-10-07 11:47:13 +02:00
Gazook89
68c75fbfd2 adjust CSS to support Firefox
Set's a non-ideal but functional css style for the box when using Firefox so the box is at least visible.
2024-10-06 22:16:46 -05:00
Gazook89
d6d6cc1e29 Add View Mode Options
Adds a new AnchoredBox component that is functionally a clone of the "saving error" notifications, but drops a lot of the JS in favor of the new (chrome-only!) CSS Anchor Positioning API.  In subsequent commits, either alternate styling or a polyfill will be added non-supported browsers.

The box contains a few inputs that modify the CSS applied to `.pages`, most critically a "start on right" toggle for the Facing Pages mode.
2024-10-06 21:51:44 -05:00
Gazook89
9fce94af63 Small CSS tweaks/display 'value' tooltip only if exists
The range slider should only display a tooltip for the value if the value attribute exists.  For example, the difference between controlled and uncontrolled inputs.

Update toolBar.less
2024-10-06 21:26:48 -05:00
Gazook89
41f390b305 Add a classname to recto configuration
Adding class name so that it can be toggled between 'recto' and 'verso'.  Verso being the normal left/right configuration, no styling is needed.  With recto, the first page is shifted to the second slot, or right side.
2024-10-06 21:24:50 -05:00
Gazook89
8115b1504e Add flex property to pages 2024-10-05 23:01:08 -05:00
Gazook89
34fa724fdd Change .pages margin to .brewRenderer padding
More consistent visuals since the zooming of the .pages element affects the spacing around the edges, and the brewRenderer padding isn't affected.
2024-10-05 22:43:13 -05:00
Gazook89
24544e713e Basically revert previous change
Adding the margin resets back in because otherwise each .page margin is set to "auto" on the sides, and that makes them zoom awkwardly when in facing and flow modes.
2024-10-05 22:35:42 -05:00
Gazook89
06a806e260 preserve margin around .pages
Keep margin around .pages element such that the pages are never bumped right against the divider.
2024-10-05 21:55:42 -05:00
Gazook89
4259931b67 Merge branch 'master' into View-Modes 2024-10-05 21:39:06 -05:00
Gazook89
a96ff6ecb3 Variable name changes for clarity
Followed suggestions on the PR.
2024-09-23 21:05:37 -05:00
Gazook89
5af45f16b0 remove tagInput-class
This file was just the old StringArrayEditor that I kept around for easy reference.  Can be deleted now.
2024-09-23 14:54:24 -05:00
Gazook89
a9b6d5ff38 Merge branch 'master' into Functional-Tag-Editor 2024-09-23 14:53:41 -05:00
Gazook89
433f016c25 rename tag container class to unify with fields 2024-09-19 15:57:40 -05:00
Gazook89
10a9bc2906 Merge branch 'master' into Functional-Tag-Editor 2024-09-19 15:54:08 -05:00
Gazook89
b585e85f0f Fix multiple duplicate tags updating at once
Fixes an issue where tags with duplicate values would all update to the same value after editing just one.

Also an adjustment to the parameters that are passed to handleInputKeyDown-- they are now one object.  This helps handle an "options" object where more optional features can be turned on and off.
2024-09-19 15:48:47 -05:00
Gazook89
8a67e1eccd Merge branch 'Functional-Tag-Editor' into Func-Tag-Editor-Features 2024-09-19 14:54:28 -05:00
Gazook89
7ea1696065 Adjust html structure to handle tags as list
Begin work on setting a better html structure for the component.

Create a .less file for the component, which I may not actually use.
2024-09-19 10:40:09 -05:00
Gazook89
5b4a7c168f Add comma to "submit" buttons
Now comma (`,`) submits a tag, like `Enter`
2024-09-18 23:54:12 -05:00
Gazook89
a54adc1e4b Set new tag input to clear itself after submission
Now whenever a new tag is submitted, the input element is cleared and ready for the next tag.

Whitespace cleanup.
2024-09-18 23:39:26 -05:00
Gazook89
c1288ce4bb Use index to find and remove tags
Fixes issue in last commit, so removing a tag that has duplicate value of other tags only removes the correct one, not the others as well.
2024-09-18 23:24:10 -05:00
Gazook89
c65210b3ed Add 'remove' button and method
New button that triggers `submitTag()` method directly (rather than throw onKeyDown event) and passes `null` as the newValue.  New `if` condition checks for null on newValue and if true, removes the tag that matches the originalValue.

This *does* currently delete all duplicate tags if they match the one you are deleting.  Not sure when you'd ever want duplicate tags, but regardless i'll likely switch this to work via Index, not value.
2024-09-18 23:13:46 -05:00
Gazook89
70a3cb9ef9 Add method for adding new tags
Component now accepts new tags entered in the always-present input field.  Entering a value and hitting Enter submits the tag, and it appears as a new tag.

Updated the tag list keys to be unique (via `index`).

To-Do: empty 'new tag' input after submitting.
2024-09-18 22:46:00 -05:00
Gazook89
d1686c4c8f Add in handlers for TagInput value changes
Now brew metadata is actually updated and preserved across reloads to match updated tag values.  useEffect calls the props.onChange event from the parent component on every change to the valueContext state of this component (right now, after hitting Enter in a tag input).
2024-09-18 22:18:18 -05:00
Gazook89
c5033db336 add editing of input functionality
Currently uses uncontrolled inputs with a `defaultValue` attribute set to the values passed in via props.  The input can then be edited, and when `Enter` is pressed, it updates the stored value state.  Later, this can be updated to be trigger with `Tab` or clicking outside the active input element.
2024-09-18 21:00:24 -05:00
Gazook89
36aa4ea508 Add click handler for readTags to open text input
Clicking on a readTag now converts that tag to a text input, and maintains the tag value.  It also closes any other open text inputs amongst the tags (but leaves the "new tag" input open).
2024-09-17 23:50:59 -05:00
Gazook89
d5c5b4315b Render tags as "write" or "read"
Tags are now either "readTag" or "writeTag", with the former being a div with the tag value and the latter a text input with the value.

Minor class name change in LESS.
2024-09-17 23:28:56 -05:00
Gazook89
d505e4e24c Render element for each value from props
Take an array of values from props, load it into valueContext state with an "editing" boolean for each value.  Then, when rendering the component, take each value in the valueContext array and create a div for each --

at this point, if the value is "being edited", it returns a div with text "editing".  If not being edited, it returns a div with the value as text.

Nothing is being edited at this point since that functionality doesn't exist yet.
2024-09-17 23:16:06 -05:00
Gazook89
ea7f18e3b0 Merge branch 'master' into Functional-Tag-Editor 2024-09-17 14:50:31 -05:00
Gazook89
e8e16f4d66 Initial commit: Rename component, set basic structure
No actual functionality implemented yet, just renames the component from "StringArrayEditor" to "TagInput", for brevity at the possible cost of clarity.  For now, the original StringArrayEditor is kept and named "TagInput-class.jsx" so that I can reference it as I work on the functional component.
2024-09-17 14:46:56 -05:00
Víctor Losada Hernández
2e5ebb861e simplify logic 2024-09-17 19:50:39 +02:00
Víctor Losada Hernández
1b577c4030 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into scroll-to-element 2024-09-17 13:20:32 +02:00
Víctor Losada Hernández
e92c169e71 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into scroll-to-element 2024-09-16 23:01:40 +02:00
Víctor Losada Hernández
e213eb0a78 "Refactor BrewRenderer: removed iframe load event listener, simplified page scrolling logic, and inlined getPageContainingElement functionality" 2024-09-15 18:37:27 +02:00
Víctor Losada Hernández
422829cbd8 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into scroll-to-element 2024-09-15 16:52:12 +02:00
Víctor Losada Hernández
3360b4e829 refctor logic 2024-09-07 19:12:59 +02:00
Víctor Losada Hernández
9e1a532105 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into scroll-to-element 2024-09-07 18:45:03 +02:00
G.Ambatte
df5ed5190a Merge branch 'master' into experimentalHeaderNavigation 2024-08-27 09:59:18 +12:00
G.Ambatte
30dac3a73c Revert toolBar.less change 2024-08-26 21:53:15 +12:00
G.Ambatte
ba4c9745a2 Tweak styling for recent changes 2024-08-26 21:27:41 +12:00
G.Ambatte
a1c275479f Change toolbar to relative positioning 2024-08-26 21:27:09 +12:00
G.Ambatte
708cbdc9e5 Change to list items 2024-08-26 21:26:30 +12:00
G.Ambatte
b0585e28ad Merge branch 'experimentalHeaderNavigation' of https://github.com/G-Ambatte/homebrewery into experimentalHeaderNavigation 2024-08-26 16:14:13 +12:00
G.Ambatte
575aa447e0 Merge branch 'master' into experimentalHeaderNavigation 2024-08-26 16:12:50 +12:00
G.Ambatte
e57b88a019 Limit max width of header navigation 2024-08-26 16:06:11 +12:00
G.Ambatte
380c1444ca Tweak position to account for new toolbar 2024-08-26 16:01:12 +12:00
G.Ambatte
a59135430c Fix missing comma 2024-08-26 15:30:58 +12:00
G.Ambatte
bdf2c97942 Merge branch 'master' into experimentalHeaderNavigation 2024-08-26 15:28:46 +12:00
Gazook89
2b79583e8c Merge branch 'pr/3499' into View-Modes 2024-08-24 22:03:06 -05:00
Gazook89
609b40e84c Merge branch 'pr/3499' into View-Modes 2024-08-24 21:28:39 -05:00
Gazook89
07c574fa42 Merge branch 'Fill-Pane-Buttons' into View-Modes 2024-08-23 23:26:24 -05:00
Gazook89
960ecae861 setup styles for different view modes
added styles for different modes-- basically a grid for 'facing' and flex for 'flow'.
2024-08-23 14:29:52 -05:00
Gazook89
49a4daa8f6 useEffect hook to update view after mode select
utilize useEffect hook to trigger render when the mode state is changed.

Move modes array to top level array, and change 'book-mode' to 'facing', and add 'flow' mode.

toggle modes as class names in .pages div, which are each styled as required.
2024-08-23 14:29:02 -05:00
Víctor Losada Hernández
1f41745d2b "Refactored Snippetbar component: updated JSX structure, added div wrapper for snippets, changed CSS styles for editors and snippets" 2024-08-23 13:37:12 +02:00
Víctor Losada Hernández
1602f0af37 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into snippet-bar-wrapping 2024-08-23 13:37:03 +02:00
Gazook89
375c54016c Get basic function worked out
Adds `setBookMode()` which toggles a className on `.pages`.  The `.book-mode` class sets display to grid, and the first child/page to start at the second slot of the book arrangement.
2024-08-23 00:32:30 -05:00
G.Ambatte
de20311299 Fix package-lock.json 2024-08-16 22:01:37 +12:00
G.Ambatte
5fede97fa5 Merge branch 'master' into fixLinks-#3547 2024-08-16 21:46:37 +12:00
Víctor Losada Hernández
cc76ff1478 relocated container query 2024-08-15 12:07:55 +02:00
Víctor Losada Hernández
bbe56bf443 linting 2024-08-14 20:39:15 +02:00
Víctor Losada Hernández
f449132b4c wrap correctly 2024-08-14 20:38:38 +02:00
G.Ambatte
b99c0382f6 Merge branch 'master' into fixLinks-#3547 2024-08-03 14:13:42 +12:00
G.Ambatte
177c90c8e9 Merge branch 'master' into experimentalHeaderNavigation 2024-08-02 18:30:28 +12:00
G.Ambatte
933451b1ec Merge branch 'master' into experimentalHeaderNavigation 2024-08-01 12:45:29 +12:00
G.Ambatte
e3586f0734 Fix errors introduced during merge conflict resolution 2024-07-31 22:17:31 +12:00
G.Ambatte
8d49422061 Link clean up 2024-07-31 21:43:49 +12:00
G.Ambatte
59790bd005 Merge branch 'master' into fixLinks-#3547 2024-07-31 21:42:42 +12:00
Víctor Losada Hernández
24c950227a Merge branch 'master' into scroll-to-element 2024-07-22 22:43:43 +02:00
G.Ambatte
effeffd906 Add styling to page links 2024-07-22 19:07:58 +12:00
G.Ambatte
c269d32247 Move headerNav to separate component 2024-07-22 18:45:36 +12:00
G.Ambatte
17b081b18b Added showHeaderNav prop to make nav menu conditional 2024-07-22 17:30:29 +12:00
G.Ambatte
7fc0cadb81 Initial functionality pass 2024-07-21 23:11:21 +12:00
G.Ambatte
b55db94822 Merge branch 'master' into fixLinks-#3547 2024-07-17 15:07:47 +12:00
G.Ambatte
c17f976385 Add HTML sanitization test step to CircleCI 2024-07-04 10:07:05 +12:00
G.Ambatte
e83e6567af Add tests via JSDOM-global 2024-07-04 10:02:45 +12:00
G.Ambatte
b638cca547 Stop evaluation tests as soon as one returns true 2024-07-04 09:32:29 +12:00
G.Ambatte
2fc5bcabb8 Merge branch 'master' into fixLinks-#3547 2024-07-04 09:13:32 +12:00
G.Ambatte
52658d6e44 Remove vue-html-secure package 2024-07-02 15:34:40 +12:00
G.Ambatte
9f3a4dc6bb Functional vue-html-secure version 2024-07-02 08:21:42 +12:00
G.Ambatte
acb10d7695 Exclude tags in FORBID_TAGS 2024-07-01 09:35:48 +12:00
G.Ambatte
fa4ced0592 Explicitly forbid script tags 2024-07-01 09:30:50 +12:00
G.Ambatte
3f1d6a5459 Re-enable DOMPurify cleaning 2024-07-01 09:30:26 +12:00
G.Ambatte
d60d902e27 Merge branch 'master' into fixLinks-#3547 2024-07-01 09:18:02 +12:00
G.Ambatte
e1c1e32a4b Return to official package; use custom addHook 2024-07-01 09:14:57 +12:00
G.Ambatte
5c2f603860 Probably terrible solution 2024-06-30 23:30:40 +12:00
G.Ambatte
47b78510df Change DOMPurify config 2024-06-29 15:35:37 +12:00
Víctor Losada Hernández
fdbec6d789 Merge branch 'master' into scroll-to-element 2024-06-12 18:08:26 +02:00
Víctor Losada Hernández
90b504d67d Oops 2024-05-31 20:26:12 +02:00
Víctor Losada Hernández
8efea112b4 "Updated scrollToPage argument to add 1 to pageNumber" 2024-05-31 20:22:14 +02:00
Víctor Losada Hernández
acbdd1b801 "Removed iframe parameter from scrollToPage and getPageContainingElement functions, instead getting iframe element by id 'BrewRenderer' inside the functions." 2024-05-31 17:13:29 +02:00
Víctor Losada Hernández
d012a09346 "Refactor BrewRenderer: updated iframe handling and scrolling logic in useEffect and scrollToPage function" 2024-05-31 17:06:47 +02:00
Víctor Losada Hernández
3cca38302a "Refactor BrewRenderer component: removed unnecessary code, reorganized useEffect hooks, and simplified getPageContainingElement function." 2024-05-31 17:00:03 +02:00
Víctor Losada Hernández
f9352a94c6 "Refactor BrewRenderer: simplify URL param extraction, remove iframe existence checks, and update scrollIntoView behavior" 2024-05-31 16:47:17 +02:00
Víctor Losada Hernández
1add97b1b2 scrolls to page 100 ms after page load 2024-05-31 16:38:08 +02:00
136 changed files with 6888 additions and 5376 deletions

View File

@@ -70,15 +70,27 @@ jobs:
- run:
name: Test - Hard Breaks
command: npm run test:hard-breaks
- run:
name: Test - Non-Breaking Spaces
command: npm run test:non-breaking-spaces
- run:
name: Test - Variables
command: npm run test:variables
- run:
name: Test - Emojis
command: npm run test:emojis
- run:
name: Test - Routes
command: npm run test:route
- run:
name: Test - HTML sanitization
command: npm run test:safehtml
- run:
name: Test - Coverage
command: npm run test:coverage
- run:
name: Test - Content Negotiation
command: npm run test:content-negotiation
workflows:
build_and_test:

View File

@@ -1,26 +1,29 @@
<!--
Before submitting a Pull Request, please consider the following to speed up reviews:
- 👷‍♀️ Create small PRs. Large PRs can usually be broken down into incremental PRs.
- 🚩 Do you already have several open PRs? Consider finishing or asking for help with existing PRs first.
- 🔧 Does your PR reference a discussed and approved issue, especially for personal or edge-case requests?
- 💡 Is the solution agreed upon? Save rework time by discussing strategy before coding.
-->
> [!TIP]
> Before submitting a Pull Request, please consider the following to speed up reviews:
> - 👷‍♀️ Create small PRs. Large PRs can usually be broken down into incremental PRs.
> - 🚩 Do you already have several open PRs? Consider finishing or asking for help with existing PRs first.
> - 🔧 Does your PR reference a discussed and approved issue, especially for personal or edge-case requests?
> - 💡 Is the solution agreed upon? Save rework time by discussing strategy before coding.
## Description
_Describe what your PR accomplishes. Consider walking through the main changes to aid reviewers in following your code, especially if it covers multiple files._
## Related Issues or Discussions
> [!CAUTION]
> If no issue exists yet, create it, and get agreement on the approach (or paste in a previous agreement from chat, etc.) before moving forward. (Experimental PRs are OK without prior discussion, but do not expect to get merged.)
- Closes #
## QA Instructions, Screenshots, Recordings
_Please replace this line with instructions on how to test or view your changes, as well as any before/after
images for UI changes._
_Replace this line with instructions on how to test or view your changes, as well as any before/after
screenshots or recordings for UI changes._
### Reviewer Checklist
_Please replace the list below with specific features you want reviewers to look at._
_Replace the list below with specific features you want reviewers to look at._
*Reviewers, refer to this list when testing features, or suggest new items *
- [ ] Verify new features are functional
@@ -32,5 +35,3 @@ _Please replace the list below with specific features you want reviewers to look
- [ ] Feature A handles negative numbers
- [ ] Identify opportunities for simplification and refactoring
- [ ] Check for code legibility and appropriate comments
<details><summary>Copy this list</summary>

View File

@@ -1,48 +1,48 @@
{
"extends": [
"stylelint-config-recess-order",
"stylelint-config-recommended"],
"plugins": [
"@stylistic/stylelint-plugin",
"./stylelint_plugins/declaration-colon-align.js",
"./stylelint_plugins/declaration-colon-min-space-before",
"./stylelint_plugins/declaration-block-multi-line-min-declarations"
],
"customSyntax": "postcss-less",
"rules": {
"no-descending-specificity" : null,
"at-rule-no-unknown" : null,
"function-no-unknown" : null,
"font-family-no-missing-generic-family-keyword" : null,
"font-weight-notation" : "named-where-possible",
"font-family-name-quotes" : "always-unless-keyword",
"@stylistic/indentation" : "tab",
"no-duplicate-selectors" : true,
"@stylistic/color-hex-case" : "upper",
"color-hex-length" : "long",
"@stylistic/selector-combinator-space-after" : "always",
"@stylistic/selector-combinator-space-before" : "always",
"@stylistic/selector-attribute-operator-space-before" : "never",
"@stylistic/selector-attribute-operator-space-after" : "never",
"@stylistic/selector-attribute-brackets-space-inside" : "never",
"selector-attribute-quotes" : "always",
"selector-pseudo-element-colon-notation" : "double",
"@stylistic/selector-pseudo-class-parentheses-space-inside" : "never",
"@stylistic/block-opening-brace-space-before" : "always",
"naturalcrit/declaration-colon-min-space-before" : 1,
"@stylistic/declaration-block-trailing-semicolon" : "always",
"@stylistic/declaration-colon-space-after" : "always",
"@stylistic/number-leading-zero" : "always",
"function-url-quotes" : ["always", { "except": ["empty"] }],
"function-url-scheme-disallowed-list" : ["data","http"],
"comment-whitespace-inside" : "always",
"@stylistic/string-quotes" : "single",
"@stylistic/media-feature-range-operator-space-before" : "always",
"@stylistic/media-feature-range-operator-space-after" : "always",
"@stylistic/media-feature-parentheses-space-inside" : "never",
"@stylistic/media-feature-colon-space-before" : "always",
"@stylistic/media-feature-colon-space-after" : "always",
"naturalcrit/declaration-colon-align" : true,
"naturalcrit/declaration-block-multi-line-min-declarations": 1
}
"extends": [
"stylelint-config-recess-order",
"stylelint-config-recommended"],
"plugins": [
"@stylistic/stylelint-plugin",
"./stylelint_plugins/declaration-colon-align.js",
"./stylelint_plugins/declaration-colon-min-space-before",
"./stylelint_plugins/declaration-block-multi-line-min-declarations"
],
"customSyntax": "postcss-less",
"rules": {
"no-descending-specificity" : null,
"at-rule-no-unknown" : null,
"function-no-unknown" : null,
"font-family-no-missing-generic-family-keyword" : null,
"font-weight-notation" : "named-where-possible",
"font-family-name-quotes" : "always-unless-keyword",
"@stylistic/indentation" : "tab",
"no-duplicate-selectors" : true,
"@stylistic/color-hex-case" : "upper",
"color-hex-length" : "long",
"@stylistic/selector-combinator-space-after" : "always",
"@stylistic/selector-combinator-space-before" : "always",
"@stylistic/selector-attribute-operator-space-before" : "never",
"@stylistic/selector-attribute-operator-space-after" : "never",
"@stylistic/selector-attribute-brackets-space-inside" : "never",
"selector-attribute-quotes" : "always",
"selector-pseudo-element-colon-notation" : "double",
"@stylistic/selector-pseudo-class-parentheses-space-inside" : "never",
"@stylistic/block-opening-brace-space-before" : "always",
"naturalcrit/declaration-colon-min-space-before" : 1,
"@stylistic/declaration-block-trailing-semicolon" : "always",
"@stylistic/declaration-colon-space-after" : "always",
"@stylistic/number-leading-zero" : "always",
"function-url-quotes" : ["always", { "except": ["empty"] }],
"function-url-scheme-disallowed-list" : ["data","http"],
"comment-whitespace-inside" : "always",
"@stylistic/string-quotes" : "single",
"@stylistic/media-feature-range-operator-space-before" : "always",
"@stylistic/media-feature-range-operator-space-after" : "always",
"@stylistic/media-feature-parentheses-space-inside" : "never",
"@stylistic/media-feature-colon-space-before" : "always",
"@stylistic/media-feature-colon-space-after" : "always",
"naturalcrit/declaration-colon-align" : true,
"naturalcrit/declaration-block-multi-line-min-declarations" : 1
}
}

View File

@@ -1,4 +1,4 @@
FROM node:20-alpine
FROM node:22-alpine
RUN apk --no-cache add git
ENV NODE_ENV=docker
@@ -9,7 +9,10 @@ WORKDIR /usr/src/app
# Copy package.json into the image, then run yarn install
# This improves caching so we don't have to download the dependencies every time the code changes
COPY package.json ./
COPY config/docker.json usr/src/app/config
# --ignore-scripts tells yarn not to run postbuild. We run it explicitly later
RUN node --version
RUN npm --version
RUN npm install --ignore-scripts
# Bundle app source and build application

View File

@@ -1,12 +1,119 @@
# Running Homebrewery via Docker
# Offline Install Instructions: Docker
The repo includes a Dockerfile and a docker-compose.yml file.
These instructions are for setting up a persistent instance of the Homebrewery application locally using Docker.
To run the application via docker-compose.yml:
`docker-compose up -d`
If you intend to develop with Homebrewery, following the Homebrewery application section of this guide is not recommended. Using docker to deploy MongoDB locally for development is not a bad idea at all, however.
To stop the application:
`docker-compose down`
# Install Docker
## Docker Desktop (MacOS/Windows)
Windows and Mac installs use Docker Desktop. Current install instructions are below.
* [Mac](https://docs.docker.com/desktop/mac/install/)
* [Windows](https://docs.docker.com/desktop/windows/install/)
You can set up the docker engine to start on boot via the Docker desktop UI.
## Docker Engine
Linux installs use Docker Engine. Docker provides installers and instructions for several of the most common distrubutions. If you do not see yours listed, it is very likely supported indirectly by your distribution.
* [Arch](https://docs.docker.com/desktop/setup/install/linux/archlinux/)
* [CentOS](https://docs.docker.com/engine/install/centos/)
* [Debian](https://docs.docker.com/engine/install/debian/)
* [Fedora](https://docs.docker.com/engine/install/fedora/)
* [RHEL](https://docs.docker.com/engine/install/rhel/)
* [Ubuntu](https://docs.docker.com/engine/install/ubuntu/)
### Post installation steps
[Manage Docker as a non-root user (highly recommended)](https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user)
[Enable Docker to start on boot (highly recommended)](https://docs.docker.com/engine/install/linux-postinstall/#configure-docker-to-start-on-boot)
# Build Homebrewery Image
Next we build the homebrewery docker image. Start by cloning the repository.
```shell
git clone https://github.com/naturalcrit/homebrewery.git
cd homebrewery
```
Make an changes you need to `config/docker.json` then build the image. If it does not exist,the below as a template.
```
{
"host" : "localhost:8000",
"naturalcrit_url" : "local.naturalcrit.com:8010",
"secret" : "secret",
"web_port" : 8000,
"enable_v3" : true,
"mongodb_uri": "mongodb://172.17.0.2/homebrewery",
"enable_themes" : true,
}
```
```shell
docker-compose build homebrewery
```
# Add Mongo container
Once docker is installed and running, it is time to set up the containers. First up, Mongo.
```shell
docker run --name homebrewery-mongodb -d --restart unless-stopped -v mongodata:/data/db -p 27017:27017 mongo:latest
```
Older CPUs may run into an issue with AVX support.
```
WARNING: MongoDB 5.0+ requires a CPU with AVX support, and your current system does not appear to have that!
see https://jira.mongodb.org/browse/SERVER-54407
see also https://www.mongodb.com/community/forums/t/mongodb-5-0-cpu-intel-g4650-compatibility/116610/2
see also https://github.com/docker-library/mongo/issues/485#issuecomment-891991814
```
If you see a message similar to this, try using the bitnami mongo instead.
```shell
docker run --name homebrewery-mongodb -d --restart unless-stopped -v mongodata:/data/db -p 27017:27017 bitnami/mongo:latest
```
If your distribution is running on an arm device such as a Raspberry Pi, you will need to run the arm-built MongoDB v4.4.
```shell
docker run --name homebrewery-mongodb -d --restart unless-stopped -v mongodata:/data/db -p 27017:27017 arm64v8/mongo:4.4
```
## Run the Homebrewery Image
```shell
# Make sure you run this in the homebrewery directory
docker run --name homebrewery-app -d --restart unless-stopped -e NODE_ENV=docker -v $(pwd)/config/docker.json:/usr/src/app/config/docker.json -p 8000:8000 docker.io/library/homebrewery:latest
```
## Updating the Image
When Homebrewery code updates, your docker container will not automatically follow the changes. To do so you will need to rebuild your homebrewery image.
First, return to your homebrewery clone (from Build Homebrewery Image above) or recreate the clone if you deleted your copy of the code.
First, delete the existing image.
```shell
docker rm -f homebrewery-app
```
Next, update the clone's code to the latest version.
```shell
cd homebrewery
git checkout master
git pull upstream master
```
Finally, rebuild and restart the homebrewery image.
```shell
docker-compose build homebrewery
docker run --name homebrewery-app -d --restart unless-stopped -e NODE_ENV=docker -v $(pwd)/config/docker.json:/usr/src/app/config/docker.json -p 8000:8000 docker.io/library/homebrewery:latest
```
To stop the application and remove all data:
`docker-compose down -v`

10
babel.config.json Normal file
View File

@@ -0,0 +1,10 @@
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
],
"plugins": [
"@babel/plugin-transform-runtime",
"babel-plugin-transform-import-meta"
]
}

View File

@@ -77,13 +77,285 @@ pre {
}
.varSyntaxTable th:first-of-type {
width:6cm;
width:6cm;
}
.page .exampleTable td,th {
border:1px dashed #00000030;
}
```
## changelog
For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery).
### Tuesday 03/18/2025 - v3.18.1
{{taskList
##### G-Ambatte
* [x] Revert colon rendering from br elements to blank divs
##### 5e-Cleric
* [x] Allow for local connections within a same network when running a local version
Fixes issue [#4094](https://github.com/naturalcrit/homebrewery/issues/4094)
* [x] Add US Letter size page snippet
Fixes issue [#3893](https://github.com/naturalcrit/homebrewery/issues/3893)
}}
### Monday 03/10/2025 - v3.18.0
{{taskList
##### dbolack
* [x] Add ability to paste in any Share ID/URL into a brew's {{openSans :fas_circle_info: **Properties** :fas_arrow_right: **THEMES**}} selection, as long as that brew has been tagged as `meta:theme`. You can now share your custom brew themes without needing to make a personal copy.
* [x] Begin migration of custom Markdown extensions into their own NPM packages, for easier adoption by other users or projects
* [x] Fix external HTML appearing in open codeblocks
Fixes issue [#3206](https://github.com/naturalcrit/homebrewery/issues/3206)
* [x] Fix tables not rendering when directly after text
##### G-Ambatte
* [x] Cleanup of "cover pages" in the {{openSans :fas_rectangle_list: **NAVIGATION**}} list
* [x] Fix autosave triggering when no changes are present
Fixes issue [#4051](https://github.com/naturalcrit/homebrewery/issues/4051)
* [x] Remove empty table rows resulting from rowspan
Fixes issue [#1729](https://github.com/naturalcrit/homebrewery/issues/1729)
##### 5e-Cleric
* [x] Style fixes for covers art and logos on A4 size pages
* [x] Fix crash when trying to open brews that don't exist
* [x] Tweaks and style update styling on {{openSans **VAULT** :fas_dungeon:}} page.
Fixes issue [#4079](https://github.com/naturalcrit/homebrewery/issues/4079)
##### Calculuschild
* [x] `` now produces `<br>` instead of a `<div>`
* [x] Fix typos in tables freezing the editor
Fixes issue [#4059](https://github.com/naturalcrit/homebrewery/issues/4059)
##### MollyMaclachlan (New Contributor!)
* [x] Fixed typos in the Monster Stat Block snippet
Fixes issue [#4073](https://github.com/naturalcrit/homebrewery/issues/4073)
##### All
* [x] Update dependencies and scripts
* [x] Refactor components and backend tools
}}
\column
### Thursday 01/30/2025 - v3.17.0
{{taskList
##### 5e-Cleric
* [x] Update FAQ
* [x] Fix styling for Vault buttons and checkboxes
* [x] Improve navigation bar styling
* [x] Add feature to change username at https://www.naturalcrit.com/account
* [x] Fix Reddit link crash when title has non-latin chars
##### dbolack
* [x] Fix page shadows toolbar option
Fixes issue [#3919](https://github.com/naturalcrit/homebrewery/issues/3919)
* [x] Add `:>>>` syntax for horizontal :>>>>> spaces
* [x] Update Docker install instructions
Fixes issue [#1930](https://github.com/naturalcrit/homebrewery/issues/1930)
* [x] Allow styling pages via `\page{myStyles}` (with calculuschild)
Fixes issue [#3901](https://github.com/naturalcrit/homebrewery/issues/3901)
* [x] Update Ubuntu install instructions
Fixes issue [#1952](https://github.com/naturalcrit/homebrewery/issues/1952)
* [x] Add `:-:` `:-` `-:` syntax for paragraph alignment, similar to table column alignment; for example:
-: -: Right-aligned
:-: :-: Centered
* [x] Add `:-- 50% --:` syntax to allow setting table column widths by percentage; for example:
```
| Narrow | Wide |
|:- 10% -:|:-90%--:|
| Cell | Cell |
```
| Narrow | Wide |
|:- 10% -:|:-90%--:|
|Cell | Cell |
{exampleTable}
##### G-Ambatte
* [x] Fix crash when opening brew Properties tab
Fixes issue [#3927](https://github.com/naturalcrit/homebrewery/issues/3927)
* [x] Update error pages with steps to refresh credentials
Fixes issue [#3955](https://github.com/naturalcrit/homebrewery/issues/3955)
* [x] Add {{openSans :fas_rectangle_list: **NAVIGATION**}} menu to the viewer toolbar
##### calculuschild
* [x] Reduce display lag on large brews
##### Gazook89
* [x] Smarter detection of current page number
Fixes issue [#3824](https://github.com/naturalcrit/homebrewery/issues/3824)
##### All
* [x] Update dependencies and scripts
* [x] Refactor components and fix various errors
}}
\page
### Wednesday 11/27/2024 - v3.16.1
{{taskList
##### 5e-Cleric
* [x] Allow linking to specific HTML IDs via `#ID` at the end of the URL, e.g.: `homebrewery.naturalcrit.com/share/share/a6RCXwaDS58i#p4` to link to Page 4 directly
Fixes issues [#2820](https://github.com/naturalcrit/homebrewery/issues/2820), [#3505](https://github.com/naturalcrit/homebrewery/issues/3505)
* [x] Fix generation of link to certain Google Drive brews
Fixes issue [#3776](https://github.com/naturalcrit/homebrewery/issues/3776)
##### abquintic
* [x] Fix blank pages appearing when pasting text
Fixes issue [#3718](https://github.com/naturalcrit/homebrewery/issues/3718)
##### Gazook89
* [x] Add new brew viewing options to the view toolbar
- {{fac,single-spread}} {{openSans **SINGLE PAGE**}}
- {{fac,facing-spread}} {{openSans **TWO PAGE**}}
- {{fac,flow-spread}} {{openSans **GRID**}}
Fixes issue [#1379](https://github.com/naturalcrit/homebrewery/issues/1379)
* [x] Updates to tag input boxes
##### G-Ambatte
* [x] Admin tools to fix certain corrupted documents
Fixes issue [#3801](https://github.com/naturalcrit/homebrewery/issues/3801)
* [x] Fix print window being affected by document zoom
Fixes issue [#3744](https://github.com/naturalcrit/homebrewery/issues/3744)
##### calculuschild, 5e-Cleric, G-Ambatte, Gazook89, abquintic
* [x] Multiple code refactors, cleanups, and security fixes
}}
### Saturday 10/12/2024 - v3.16.0
{{taskList
##### 5e-Cleric
* [x] Added a new API endpoint `/metadata/:shareId` to fetch metadata about individual brews
Fixes issue [#2638](https://github.com/naturalcrit/homebrewery/issues/2638)
* [x] Added A3, A5, and Card page size snippets under {{openSans **:fas_paintbrush: STYLE TAB :fas_arrow_right: :fas_print: PRINT**}}
* [x] Adjust navbar styling for very long titles
Fixes issue [#2071](https://github.com/naturalcrit/homebrewery/issues/2071)
* [x] Added some sorting options to the {{openSans **VAULT** {{fas,fa-dungeon}}}} page
* [x] Fix `language` property not working in share page
Fixes issue [#3776](https://github.com/naturalcrit/homebrewery/issues/3776)
##### abquintic
* [x] New {{openSans **:fas_pencil: TEXT EDITOR :fas_arrow_right: :fas_bookmark: PAGE NUMBER :fas_arrow_right:**}}
{{openSans **:fas_xmark: SKIP PAGE NUMBER**}} and {{openSans **:fas_arrow_rotate_left: RESTART PAGE NUMBER**}} snippets for more control over automatic page numbering.
Fixes issue [#513](https://github.com/naturalcrit/homebrewery/issues/513)
* [x] New Table of Contents control options via {{openSans **:fas_pencil: TEXT EDITOR :fas_arrow_right: :fas_book: TABLE OF CONTENTS**}} submenus. By default, H1-H3 is included in the ToC generation, but the new options allow marking `{{blocks}}` to include or exclude specific or ranges of contained headers. Also, a global option to increase the default range of H1-H3 to H1-H4/5/6. After applying these markers, you must regenerate the Table of Contents to see the changes.
* [x] Added a ":fas_lock: SYNC VIEWS" button onto the divider bar. When locked, scrolling on either panel will sync the other panel to the same page.
Fixes issue [#241](https://github.com/naturalcrit/homebrewery/issues/241)
##### Gazook89
* [x] Added a :fas_glasses: HIDE button to the page navigation bar
##### G-Ambatte
* [x] Automatic local backups of your files, in case of accidental data loss. Stores up to 5 snapshots of each brew edited in your browser, incrementing from a few minutes old to a maximum of several days. Restore a backup by clicking an entry in the new {{openSans **:fas_clock_rotate_left: HISTORY**}} button in the snippet bar.
Fixes issue [#3070](https://github.com/naturalcrit/homebrewery/issues/3070)
* [x] Fix issue with legacy brews breaking on Share page
Fixes issue [#3764](https://github.com/naturalcrit/homebrewery/issues/3764)
* [x] Fix print size when printing a zoomed document
Fixes issue [#3744](https://github.com/naturalcrit/homebrewery/issues/3744)
##### All
* [x] Background code cleanup, security fixes, dev tool improvements, dependency updates, prep for upcoming features, etc.
}}
### Wednesday 9/25/2024 - v3.15.1
{{taskList
##### calculuschild
* [x] Background fixes to handle Google Drive issues
* [x] Remove duplicate error logging
##### calculuschild, 5e-Cleric
* [x] Fix links in {{openSans **RECENT BREWS :fas_clock_rotate_left:**}} and user {{openSans **BREWS :fas_beer_mug_empty:**}} pointing to trashed Google Drive files after transferring from Google to Homebrewery storage
Fixes issue [#3776](https://github.com/naturalcrit/homebrewery/issues/3776)
}}
\page
### Wednesday 9/04/2024 - v3.15.0
{{taskList
@@ -1931,4 +2203,4 @@ Massive changelog incoming:
* Added `phb.standalone.css` plus a build system for creating it
* Added page numbers and footer text
* Page accent now flips each page
* Page accent now flips each page

View File

@@ -1,47 +1,48 @@
require('./admin.less');
const React = require('react');
const createClass = require('create-react-class');
import './admin.less';
import React, { useEffect, useState } from 'react';
const BrewUtils = require('./brewUtils/brewUtils.jsx');
const NotificationUtils = require('./notificationUtils/notificationUtils.jsx');
import AuthorUtils from './authorUtils/authorUtils.jsx';
const tabGroups = ['brew', 'notifications'];
const tabGroups = ['brew', 'notifications', 'authors'];
const Admin = createClass({
getDefaultProps : function() {
return {};
},
const Admin = ()=>{
const [currentTab, setCurrentTab] = useState('brew');
getInitialState : function(){
return ({
currentTab : 'brew'
});
},
useEffect(()=>{
setCurrentTab(localStorage.getItem('hbAdminTab'));
}, []);
handleClick : function(newTab){
if(this.state.currentTab === newTab) return;
this.setState({
currentTab : newTab
});
},
useEffect(()=>{
localStorage.setItem('hbAdminTab', currentTab);
}, [currentTab]);
render : function(){
return <div className='admin'>
return (
<div className='admin'>
<header>
<div className='container'>
<i className='fas fa-rocket' />
homebrewery admin
The Homebrewery Admin Page
<a href='/'>back to homepage</a>
</div>
</header>
<main className='container'>
<nav className='tabs'>
{tabGroups.map((tab, idx)=>{ return <button className={tab===this.state.currentTab ? 'active' : ''} key={idx} onClick={()=>{ return this.handleClick(tab); }}>{tab.toUpperCase()}</button>; })}
{tabGroups.map((tab, idx)=>(
<button
className={tab === currentTab ? 'active' : ''}
key={idx}
onClick={()=>setCurrentTab(tab)}>
{tab.toUpperCase()}
</button>
))}
</nav>
{this.state.currentTab==='brew' && <BrewUtils />}
{this.state.currentTab==='notifications' && <NotificationUtils />}
{currentTab === 'brew' && <BrewUtils />}
{currentTab === 'notifications' && <NotificationUtils />}
{currentTab === 'authors' && <AuthorUtils />}
</main>
</div>;
}
});
</div>
);
};
module.exports = Admin;

View File

@@ -22,7 +22,7 @@ body {
}
:where(.admin) {
padding-bottom : 50px;
header {
padding : 20px 0px;
margin-bottom : 30px;
@@ -30,6 +30,7 @@ body {
color : white;
background-color : @red;
i { margin-right : 30px; }
a { float : right; }
}
hr { margin : 30px 0px; }
@@ -48,21 +49,23 @@ body {
}
dl {
@maxItemWidth : 132px;
display : grid;
grid-template-columns : 120px 1fr;
row-gap : 10px;
align-items : center;
justify-items : start;
padding-top : 0.5em;
dt {
float : left;
width : @maxItemWidth;
clear : left;
text-align : right;
float : left;
clear : left;
height : fit-content;
font-weight : 900;
text-align : right;
&::after { content : ' : '; }
}
dd {
height : 1em;
padding : 0 0 0.5em 0;
margin-left : @maxItemWidth + 6px;
}
dd { height : fit-content; }
}
.tabs button {
margin-right : 3px;
margin-left : 3px;
@@ -90,11 +93,45 @@ body {
}
}
table {
padding : 10px;
tr {
border-bottom : 1px solid;
&:last-of-type { border : none; }
&:nth-child(even) { background : #DDDDDD; }
}
thead {
background : rgb(193,236,230);
border-bottom : 2px solid;
}
th, td {
padding : 5px 10px;
vertical-align : middle;
text-align : center;
border-right : 1px solid;
&:last-child { border-right : none; }
}
th { font-weight : 900; }
td {
&:first-child {
font-weight : 900;
text-align : left;
}
}
}
.error {
background: rgb(178, 54, 54);
color:white;
font-weight: 900;
margin-block:10px;
padding:10px;
float : right;
padding : 10px;
margin-block : 10px;
font-weight : 900;
color : white;
background : rgb(178, 54, 54);
}
}

View File

@@ -0,0 +1,87 @@
import './authorLookup.less';
import React from 'react';
import request from 'superagent';
const authorLookup = ()=>{
const [author, setAuthor] = React.useState('');
const [searching, setSearching] = React.useState(false);
const [results, setResults] = React.useState([]);
const lookup = async ()=>{
if(!author) return;
setSearching(true);
setResults([]);
const brews = await request.get(`/admin/user/list/${author}`);
setResults(brews.body);
setSearching(false);
};
const renderResults = ()=>{
if(results.length == 0) return <>
<h2>Results</h2>
<p>None found.</p>
</>;
return <>
<h2>{`Results - ${results.length} brews` }</h2>
<table className='resultsTable'>
<thead>
<tr>
<th>Title</th>
<th>Share</th>
<th>Edit</th>
<th>Last Update</th>
<th>Storage</th>
</tr>
</thead>
<tbody>
{results
.sort((a, b)=>{ // Sort brews from most recently updated
if(a.updatedAt > b.updatedAt) return -1;
return 1;
})
.map((brew, idx)=>{
return <tr key={idx}>
<td><strong>{brew.title}</strong></td>
<td><a href={`/share/${brew.shareId}`}>{brew.shareId}</a></td>
<td>{brew.editId}</td>
<td style={{ width: '200px' }}>{brew.updatedAt}</td>
<td>{brew.googleId ? 'Google' : 'Homebrewery'}</td>
</tr>;
})}
</tbody>
</table>
</>;
};
const handleKeyPress = (evt)=>{
if(evt.key === 'Enter') return lookup();
};
const handleChange = (evt)=>{
setAuthor(evt.target.value);
};
return (
<div className='authorLookup'>
<div className='authorLookupInputs'>
<h2>Author Lookup</h2>
<label className='field'>
Author Name:
<input className='fieldInput' value={author} onKeyDown={handleKeyPress} onChange={handleChange} />
<button onClick={lookup}>
<i className={`fas ${searching ? 'fa-spin fa-spinner' : 'fa-search'}`} />
</button>
</label>
</div>
<div className='authorLookupResults'>
{renderResults()}
</div>
</div>
);
};
module.exports = authorLookup;

View File

@@ -0,0 +1,29 @@
.authorLookup {
position : relative;
display : flex;
flex-direction : column;
.field {
display : flex;
gap : 5px;
align-items : center;
justify-items : stretch;
width : 100%;
margin-bottom : 20px;
input {
height : 33px;
padding : 0px 10px;
margin-bottom : unset;
font-family : monospace;
}
button {
width: 50px;
i { margin-right : 10px; }
}
}
}

View File

@@ -0,0 +1,13 @@
import React from 'react';
import AuthorLookup from './authorLookup/authorLookup.jsx';
const authorUtils = ()=>{
return (
<section className='authorUtils'>
<AuthorLookup />
</section>
);
};
module.exports = authorUtils;

View File

@@ -1,10 +1,8 @@
require('./brewCleanup.less');
const React = require('react');
const createClass = require('create-react-class');
const request = require('superagent');
const BrewCleanup = createClass({
displayName : 'BrewCleanup',
getDefaultProps(){
@@ -39,9 +37,9 @@ const BrewCleanup = createClass({
if(!this.state.primed) return;
if(!this.state.count){
return <div className='removeBox'>No Matching Brews found.</div>;
return <div className='result noBrews'>No Matching Brews found.</div>;
}
return <div className='removeBox'>
return <div className='result'>
<button onClick={this.cleanup} className='remove'>
{this.state.pending
? <i className='fas fa-spin fa-spinner' />
@@ -52,7 +50,7 @@ const BrewCleanup = createClass({
</div>;
},
render(){
return <div className='BrewCleanup'>
return <div className='brewUtil brewCleanup'>
<h2> Brew Cleanup </h2>
<p>Removes very short brews to tidy up the database</p>
@@ -65,7 +63,7 @@ const BrewCleanup = createClass({
{this.renderPrimed()}
{this.state.error
&& <div className='error'>{this.state.error.toString()}</div>
&& <div className='error noBrews'>{this.state.error.toString()}</div>
}
</div>;
}

View File

@@ -1,9 +0,0 @@
.BrewCleanup {
.removeBox {
margin-top : 20px;
button {
margin-right : 10px;
background-color : @red;
}
}
}

View File

@@ -1,10 +1,7 @@
require('./brewCompress.less');
const React = require('react');
const createClass = require('create-react-class');
const request = require('superagent');
const BrewCompress = createClass({
displayName : 'BrewCompress',
getDefaultProps(){
@@ -53,9 +50,9 @@ const BrewCompress = createClass({
if(!this.state.primed) return;
if(!this.state.count){
return <div className='removeBox'>No Matching Brews found.</div>;
return <div className='result noBrews'>No Matching Brews found.</div>;
}
return <div className='removeBox'>
return <div className='result'>
<button onClick={this.cleanup} className='remove'>
{this.state.pending
? <i className='fas fa-spin fa-spinner' />
@@ -69,7 +66,7 @@ const BrewCompress = createClass({
</div>;
},
render(){
return <div className='BrewCompress'>
return <div className='brewUtil brewCompress'>
<h2> Brew Compression </h2>
<p>Compresses the text in brews to binary</p>

View File

@@ -1,9 +0,0 @@
.BrewCompress {
.removeBox {
margin-top : 20px;
button {
margin-right : 10px;
background-color : @red;
}
}
}

View File

@@ -12,27 +12,48 @@ const BrewLookup = createClass({
},
getInitialState() {
return {
query : '',
foundBrew : null,
searching : false,
error : null
query : '',
foundBrew : null,
searching : false,
error : null,
scriptCount : 0
};
},
handleChange(e){
this.setState({ query: e.target.value });
},
lookup(){
this.setState({ searching: true, error: null });
this.setState({ searching: true, error: null, scriptCount: 0 });
request.get(`/admin/lookup/${this.state.query}`)
.then((res)=>this.setState({ foundBrew: res.body }))
.then((res)=>{
const foundBrew = res.body;
const scriptCheck = foundBrew?.text.match(/(<\/?s)cript/g);
this.setState({
foundBrew : foundBrew,
scriptCount : scriptCheck?.length || 0,
});
})
.catch((err)=>this.setState({ error: err }))
.finally(()=>this.setState({ searching: false }));
.finally(()=>{
this.setState({
searching : false
});
});
},
async cleanScript(){
if(!this.state.foundBrew?.shareId) return;
await request.put(`/admin/clean/script/${this.state.foundBrew.shareId}`)
.catch((err)=>{ this.setState({ error: err }); return; });
this.lookup();
},
renderFoundBrew(){
const brew = this.state.foundBrew;
return <div className='foundBrew'>
return <div className='result'>
<dl>
<dt>Title</dt>
<dd>{brew.title}</dd>
@@ -46,17 +67,28 @@ const BrewLookup = createClass({
<dt>Share Link</dt>
<dd><a href={`/share/${brew.shareId}`} target='_blank' rel='noopener noreferrer'>/share/{brew.shareId}</a></dd>
<dt>Created Time</dt>
<dd>{brew.createdAt ? Moment(brew.createdAt).toLocaleString() : 'No creation date'}</dd>
<dt>Last Updated</dt>
<dd>{Moment(brew.updatedAt).fromNow()}</dd>
<dt>Num of Views</dt>
<dd>{brew.views}</dd>
<dt>SCRIPT tags detected</dt>
<dd>{this.state.scriptCount}</dd>
</dl>
{this.state.scriptCount > 0 &&
<div className='cleanButton'>
<button onClick={this.cleanScript}>CLEAN BREW</button>
</div>
}
</div>;
},
render(){
return <div className='brewLookup'>
return <div className='brewUtil brewLookup'>
<h2>Brew Lookup</h2>
<input type='text' value={this.state.query} onChange={this.handleChange} placeholder='edit or share id' />
<button onClick={this.lookup}>
@@ -72,7 +104,7 @@ const BrewLookup = createClass({
{this.state.foundBrew
? this.renderFoundBrew()
: <div className='noBrew'>No brew found.</div>
: <div className='result noBrew'>No brew found.</div>
}
</div>;
}

View File

@@ -1,6 +1,6 @@
const React = require('react');
const createClass = require('create-react-class');
require('./brewUtils.less');
const BrewCleanup = require('./brewCleanup/brewCleanup.jsx');
const BrewLookup = require('./brewLookup/brewLookup.jsx');

View File

@@ -0,0 +1,29 @@
.brewUtil {
.result {
margin-top : 20px;
button {
margin-right : 10px;
background-color : @red;
}
}
.cleanButton {
display : inline-block;
width : 100%;
}
}
.stats {
position : relative;
.pending {
position : absolute;
top : 0.5em;
left : 100px;
width : 100%;
height : 100%;
}
&:has(.pending) { opacity : 0.5; }
dl { grid-template-columns : 200px 250px; }
}

View File

@@ -1,11 +1,8 @@
require('./stats.less');
const React = require('react');
const createClass = require('create-react-class');
const cx = require('classnames');
const request = require('superagent');
const Stats = createClass({
displayName : 'Stats',
getDefaultProps(){
@@ -14,7 +11,8 @@ const Stats = createClass({
getInitialState(){
return {
stats : {
totalBrews : 0
totalBrews : 0,
totalPublishedBrews : 0
},
fetching : false
};
@@ -29,11 +27,13 @@ const Stats = createClass({
.finally(()=>this.setState({ fetching: false }));
},
render(){
return <div className='Stats'>
return <div className='brewUtil stats'>
<h2> Stats </h2>
<dl>
<dt>Total Brew Count</dt>
<dd>{this.state.stats.totalBrews}</dd>
<dt>Total Brews Published</dt>
<dd>{this.state.stats.totalPublishedBrews}</dd>
</dl>
{this.state.fetching

View File

@@ -1,13 +0,0 @@
.Stats {
position : relative;
.pending {
position : absolute;
top : 0px;
left : 0px;
width : 100%;
height : 100%;
background-color : rgba(238,238,238, 0.5);
}
}

View File

@@ -66,7 +66,7 @@ const NotificationAdd = ()=>{
<label className='field'>
Dismiss Key:
<input className='fieldInput' type='text' ref={dismissKeyRef} required
placeholder='GOOGLEDRIVENOTIF'
placeholder='dismiss_notif_drive'
/>
</label>

View File

@@ -6,18 +6,21 @@
.field {
display : grid;
grid-template-columns : 120px 150px;
grid-template-columns : 120px 200px;
align-items : center;
justify-items : stretch;
width : 100%;
margin-bottom : 20px;
input {
height : 33px;
padding : 0px 10px;
margin-bottom : unset;
font-family : monospace;
&[type="date"] {
width:14ch;
}
}
textarea {

View File

@@ -14,9 +14,6 @@ const NotificationDetail = ({ notification, onDelete })=>(
<dt>Title</dt>
<dd>{notification.title || 'No Title'}</dd>
<dt>Text</dt>
<dd>{notification.text || 'No Text'}</dd>
<dt>Created</dt>
<dd>{Moment(notification.createdAt).format('LLLL')}</dd>
@@ -25,6 +22,9 @@ const NotificationDetail = ({ notification, onDelete })=>(
<dt>Stop</dt>
<dd>{Moment(notification.stopAt).format('LLLL') || 'No End Time'}</dd>
<dt>Text</dt>
<dd>{notification.text || 'No Text'}</dd>
</dl>
<button onClick={()=>onDelete(notification.dismissKey)}>DELETE</button>
</>

View File

@@ -1,8 +1,8 @@
.notificationLookup {
width : 450px;
height : fit-content;
.noNotification { margin-block : 20px; }
.notificationList {
display : flex;
flex-direction : column;
@@ -30,11 +30,6 @@
font-size : 20px;
font-weight : 900;
}
dl dt{
font-weight: 900;
}
}
}
.noNotification { margin-block : 20px; }
}

View File

@@ -0,0 +1,96 @@
import React, { useState, useRef, forwardRef, useEffect, cloneElement, Children } from 'react';
import './Anchored.less';
// Anchored is a wrapper component that must have as children an <AnchoredTrigger> and a <AnchoredBox> component.
// AnchoredTrigger must have a unique `id` prop, which is passed up to Anchored, saved in state on mount, and
// then passed down through props into AnchoredBox. The `id` is used for the CSS Anchor Positioning properties.
// **The Anchor Positioning API is not available in Firefox yet**
// So in Firefox the positioning isn't perfect but is likely sufficient, and FF team seems to be working on the API quickly.
// When Anchor Positioning is added to Firefox, this can also be rewritten using the Popover API-- add the `popover` attribute
// to the container div, which will render the container in the *top level* and give it better interactions like
// click outside to dismiss. **Do not** add without Anchor, though, because positioning is very limited with the `popover`
// attribute.
const Anchored = ({ children })=>{
const [visible, setVisible] = useState(false);
const [anchorId, setAnchorId] = useState(null);
const boxRef = useRef(null);
const triggerRef = useRef(null);
// promote trigger id to Anchored id (to pass it back down to the box as "anchorId")
useEffect(()=>{
if(triggerRef.current){
setAnchorId(triggerRef.current.id);
}
}, []);
// close box on outside click or Escape key
useEffect(()=>{
const handleClickOutside = (evt)=>{
if(
boxRef.current &&
!boxRef.current.contains(evt.target) &&
triggerRef.current &&
!triggerRef.current.contains(evt.target)
) {
setVisible(false);
}
};
const handleEscapeKey = (evt)=>{
if(evt.key === 'Escape') setVisible(false);
};
window.addEventListener('click', handleClickOutside);
window.addEventListener('keydown', handleEscapeKey);
return ()=>{
window.removeEventListener('click', handleClickOutside);
window.removeEventListener('keydown', handleEscapeKey);
};
}, []);
const toggleVisibility = ()=>setVisible((prev)=>!prev);
// Map children to inject necessary props
const mappedChildren = Children.map(children, (child)=>{
if(child.type === AnchoredTrigger) {
return cloneElement(child, { ref: triggerRef, toggleVisibility, visible });
}
if(child.type === AnchoredBox) {
return cloneElement(child, { ref: boxRef, visible, anchorId });
}
return child;
});
return <>{mappedChildren}</>;
};
// forward ref for AnchoredTrigger
const AnchoredTrigger = forwardRef(({ toggleVisibility, visible, children, className, ...props }, ref)=>(
<button
ref={ref}
className={`anchored-trigger${visible ? ' active' : ''} ${className}`}
onClick={toggleVisibility}
style={{ anchorName: `--${props.id}` }} // setting anchor properties here allows greater recyclability.
{...props}
>
{children}
</button>
));
// forward ref for AnchoredBox
const AnchoredBox = forwardRef(({ visible, children, className, anchorId, ...props }, ref)=>(
<div
ref={ref}
className={`anchored-box${visible ? ' active' : ''} ${className}`}
style={{ positionAnchor: `--${anchorId}` }} // setting anchor properties here allows greater recyclability.
{...props}
>
{children}
</div>
));
export { Anchored, AnchoredTrigger, AnchoredBox };

View File

@@ -0,0 +1,13 @@
.anchored-box {
position:absolute;
@supports (inset-block-start: anchor(bottom)){
inset-block-start: anchor(bottom);
}
justify-self: anchor-center;
visibility: hidden;
&.active {
visibility: visible;
}
}

View File

@@ -45,6 +45,7 @@ const Combobox = createClass({
},
handleDropdown : function(show){
this.setState({
value : show ? '' : this.props.default,
showDropdown : show,
inputFocused : this.props.autoSuggest.clearAutoSuggestOnClick ? show : false
});
@@ -58,10 +59,10 @@ const Combobox = createClass({
this.props.onEntry(e);
});
},
handleSelect : function(e){
handleSelect : function(value, data=value){
this.setState({
value : e.currentTarget.getAttribute('data-value')
}, ()=>{this.props.onSelect(this.state.value);});
value : value
}, ()=>{this.props.onSelect(data);});
;
},
renderTextInput : function(){
@@ -78,10 +79,11 @@ const Combobox = createClass({
if(!e.target.checkValidity()){
this.setState({
value : this.props.default
}, ()=>this.props.onEntry(e));
});
}
}}
/>
<i className='fas fa-caret-down'/>
</div>
);
},
@@ -92,11 +94,10 @@ const Combobox = createClass({
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'){
if(suggestMethod === 'includes')
return item.props[attr]?.toLowerCase().includes(this.state.value.toLowerCase());
} else if(suggestMethod === 'startsWith'){
if(suggestMethod === 'startsWith')
return item.props[attr]?.toLowerCase().startsWith(this.state.value.toLowerCase());
}
});
return children;
});
@@ -111,7 +112,7 @@ const Combobox = createClass({
},
render : function () {
const dropdownChildren = this.state.options.map((child, i)=>{
const clone = React.cloneElement(child, { onClick: (e)=>this.handleSelect(e) });
const clone = React.cloneElement(child, { onClick: ()=>this.handleSelect(child.props.value, child.props.data) });
return clone;
});
return (

View File

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

View File

@@ -1,22 +1,24 @@
// Dialog box, for popups and modal blocking messages
const React = require('react');
import React from 'react';
const { useRef, useEffect } = React;
function Dialog({ dismissKey, closeText = 'Close', blocking = false, ...rest }) {
function Dialog({ dismisskeys = [], closeText = 'Close', blocking = false, ...rest }) {
const dialogRef = useRef(null);
useEffect(()=>{
if(!dismissKey || !localStorage.getItem(dismissKey)) {
blocking ? dialogRef.current?.showModal() : dialogRef.current?.show();
}
blocking ? dialogRef.current?.showModal() : dialogRef.current?.show();
}, []);
const dismiss = ()=>{
dismissKey && localStorage.setItem(dismissKey, true);
dismisskeys.forEach((key)=>{
if(key) {
localStorage.setItem(key, 'true');
}
});
dialogRef.current?.close();
};
return (
return (
<dialog ref={dialogRef} onCancel={dismiss} {...rest}>
{rest.children}
<button className='dismiss' onClick={dismiss}>

View File

@@ -1,11 +1,11 @@
/*eslint max-lines: ["warn", {"max": 300, "skipBlankLines": true, "skipComments": true}]*/
require('./brewRenderer.less');
const React = require('react');
const { useState, useRef, useCallback } = React;
const { useState, useRef, useMemo, useEffect } = React;
const _ = require('lodash');
const MarkdownLegacy = require('naturalcrit/markdownLegacy.js');
const Markdown = require('naturalcrit/markdown.js');
import Markdown from 'naturalcrit/markdown.js';
const ErrorBar = require('./errorBar/errorBar.jsx');
const ToolBar = require('./toolBar/toolBar.jsx');
@@ -16,9 +16,10 @@ const Frame = require('react-frame-component').default;
const dedent = require('dedent-tabs').default;
const { printCurrentBrew } = require('../../../shared/helpers.js');
const DOMPurify = require('dompurify');
const purifyConfig = { FORCE_BODY: true, SANITIZE_DOM: false };
import HeaderNav from './headerNav/headerNav.jsx';
import { safeHTML } from './safeHTML.js';
const PAGEBREAK_REGEX_V3 = /^(?=\\page(?: *{[^\n{}]*})?$)/m;
const PAGE_HEIGHT = 1056;
const INITIAL_CONTENT = dedent`
@@ -29,6 +30,7 @@ const INITIAL_CONTENT = dedent`
<base target=_blank>
</head><body style='overflow: hidden'><div></div></body></html>`;
//v=====----------------------< Brew Page Component >---------------------=====v//
const BrewPage = (props)=>{
props = {
@@ -36,15 +38,53 @@ const BrewPage = (props)=>{
index : 0,
...props
};
const cleanText = props.contents; //DOMPurify.sanitize(props.contents, purifyConfig);
return <div className={props.className} id={`p${props.index + 1}`} >
const pageRef = useRef(null);
const cleanText = safeHTML(`${props.contents}\n<div class="columnSplit"></div>\n`);
useEffect(()=>{
if(!pageRef.current) return;
// Observer for tracking pages within the `.pages` div
const visibleObserver = new IntersectionObserver(
(entries)=>{
entries.forEach((entry)=>{
if(entry.isIntersecting)
props.onVisibilityChange(props.index + 1, true, false); // add page to array of visible pages.
else
props.onVisibilityChange(props.index + 1, false, false);
});
},
{ threshold: .3, rootMargin: '0px 0px 0px 0px' } // detect when >30% of page is within bounds.
);
// Observer for tracking the page at the center of the iframe.
const centerObserver = new IntersectionObserver(
(entries)=>{
entries.forEach((entry)=>{
if(entry.isIntersecting)
props.onVisibilityChange(props.index + 1, true, true); // Set this page as the center page
});
},
{ threshold: 0, rootMargin: '-50% 0px -50% 0px' } // Detect when the page is at the center
);
// attach observers to each `.page`
visibleObserver.observe(pageRef.current);
centerObserver.observe(pageRef.current);
return ()=>{
visibleObserver.disconnect();
centerObserver.disconnect();
};
}, []);
return <div className={props.className} id={`p${props.index + 1}`} data-index={props.index} ref={pageRef} style={props.style} {...props.attributes}>
<div className='columnWrapper' dangerouslySetInnerHTML={{ __html: cleanText }} />
</div>;
};
//v=====--------------------< Brew Renderer Component >-------------------=====v//
const renderedPages = [];
let renderedPages = [];
let rawPages = [];
const BrewRenderer = (props)=>{
@@ -64,26 +104,46 @@ const BrewRenderer = (props)=>{
};
const [state, setState] = useState({
isMounted : false,
visibility : 'hidden',
zoom : 100
isMounted : false,
visibility : 'hidden',
visiblePages : [],
centerPage : 1
});
const [displayOptions, setDisplayOptions] = useState({
zoomLevel : 100,
spread : 'single',
startOnRight : true,
pageShadows : true
});
const [headerState, setHeaderState] = useState(false);
const mainRef = useRef(null);
const pagesRef = useRef(null);
if(props.renderer == 'legacy') {
rawPages = props.text.split('\\page');
} else {
rawPages = props.text.split(/^\\page$/gm);
rawPages = props.text.split(PAGEBREAK_REGEX_V3);
}
const updateCurrentPage = useCallback(_.throttle((e)=>{
const { scrollTop, clientHeight, scrollHeight } = e.target;
const totalScrollableHeight = scrollHeight - clientHeight;
const currentPageNumber = Math.max(Math.ceil((scrollTop / totalScrollableHeight) * rawPages.length), 1);
const handlePageVisibilityChange = (pageNum, isVisible, isCenter)=>{
setState((prevState)=>{
const updatedVisiblePages = new Set(prevState.visiblePages);
if(!isCenter)
isVisible ? updatedVisiblePages.add(pageNum) : updatedVisiblePages.delete(pageNum);
props.onPageChange(currentPageNumber);
}, 200), []);
return {
...prevState,
visiblePages : [...updatedVisiblePages].sort((a, b)=>a - b),
centerPage : isCenter ? pageNum : prevState.centerPage
};
});
if(isCenter)
props.onPageChange(pageNum);
};
const isInView = (index)=>{
if(!state.isMounted)
@@ -105,19 +165,40 @@ const BrewRenderer = (props)=>{
};
const renderStyle = ()=>{
const cleanStyle = props.style; //DOMPurify.sanitize(props.style, purifyConfig);
const themeStyles = props.themeBundle?.joinedStyles ?? '<style>@import url("/themes/V3/Blank/style.css");</style>';
return <div style={{ display: 'none' }} dangerouslySetInnerHTML={{ __html: `${themeStyles} \n\n <style> ${cleanStyle} </style>` }} />;
const cleanStyle = safeHTML(`${themeStyles} \n\n <style> ${props.style} </style>`);
return <div style={{ display: 'none' }} dangerouslySetInnerHTML={{ __html: cleanStyle }} />;
};
const renderPage = (pageText, index)=>{
let styles = {
...(!displayOptions.pageShadows ? { boxShadow: 'none' } : {})
// Add more conditions as needed
};
let classes = 'page';
let attributes = {};
if(props.renderer == 'legacy') {
const html = MarkdownLegacy.render(pageText);
return <BrewPage className='page phb' index={index} key={index} contents={html} />;
return <BrewPage className='page phb' index={index} key={index} contents={html} style={styles} onVisibilityChange={handlePageVisibilityChange} />;
} else {
pageText += `\n\n&nbsp;\n\\column\n&nbsp;`; //Artificial column break at page end to emulate column-fill:auto (until `wide` is used, when column-fill:balance will reappear)
const html = Markdown.render(pageText, index);
return <BrewPage className='page' index={index} key={index} contents={html} />;
if(pageText.startsWith('\\page')) {
const firstLineTokens = Markdown.marked.lexer(pageText.split('\n', 1)[0])[0].tokens;
const injectedTags = firstLineTokens.find((obj)=>obj.injectedTags !== undefined)?.injectedTags;
if(injectedTags) {
styles = { ...styles, ...injectedTags.styles };
styles = _.mapKeys(styles, (v, k) => k.startsWith('--') ? k : _.camelCase(k)); // Convert CSS to camelCase for React
classes = [classes, injectedTags.classes].join(' ').trim();
attributes = injectedTags.attributes;
}
pageText = pageText.includes('\n') ? pageText.substring(pageText.indexOf('\n') + 1) : ''; // Remove the \page line
}
let html = Markdown.render(pageText, index);
return <BrewPage className={classes} index={index} key={index} contents={html} style={styles} attributes={attributes} onVisibilityChange={handlePageVisibilityChange} />;
}
};
@@ -129,7 +210,8 @@ const BrewRenderer = (props)=>{
renderedPages.length = 0;
// Render currently-edited page first so cross-page effects (variables, links) can propagate out first
renderedPages[props.currentEditorCursorPageNum - 1] = renderPage(rawPages[props.currentEditorCursorPageNum - 1], props.currentEditorCursorPageNum - 1);
if(rawPages.length > props.currentEditorCursorPageNum -1)
renderedPages[props.currentEditorCursorPageNum - 1] = renderPage(rawPages[props.currentEditorCursorPageNum - 1], props.currentEditorCursorPageNum - 1);
_.forEach(rawPages, (page, index)=>{
if((isInView(index) || !renderedPages[index]) && typeof window !== 'undefined'){
@@ -149,7 +231,29 @@ const BrewRenderer = (props)=>{
}
};
const scrollToHash = (hash)=>{
if(!hash) return;
const iframeDoc = document.getElementById('BrewRenderer').contentDocument;
let anchor = iframeDoc.querySelector(hash);
if(anchor) {
anchor.scrollIntoView({ behavior: 'smooth' });
} else {
// Use MutationObserver to wait for the element if it's not immediately available
new MutationObserver((mutations, obs)=>{
anchor = iframeDoc.querySelector(hash);
if(anchor) {
anchor.scrollIntoView({ behavior: 'smooth' });
obs.disconnect();
}
}).observe(iframeDoc, { childList: true, subtree: true });
}
};
const frameDidMount = ()=>{ //This triggers when iFrame finishes internal "componentDidMount"
scrollToHash(window.location.hash);
setTimeout(()=>{ //We still see a flicker where the style isn't applied yet, so wait 100ms before showing iFrame
renderPages(); //Make sure page is renderable before showing
setState((prevState)=>({
@@ -165,25 +269,30 @@ const BrewRenderer = (props)=>{
document.dispatchEvent(new MouseEvent('click'));
};
//Toolbar settings:
const handleZoom = (newZoom)=>{
setState((prevState)=>({
...prevState,
zoom : newZoom
}));
const handleDisplayOptionsChange = (newDisplayOptions)=>{
setDisplayOptions(newDisplayOptions);
};
const pagesStyle = {
zoom : `${displayOptions.zoomLevel}%`,
columnGap : `${displayOptions.columnGap}px`,
rowGap : `${displayOptions.rowGap}px`
};
const styleObject = {};
if(global.config.deployment) {
styleObject.backgroundImage = `url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' height='40px' width='200px'><text x='0' y='15' fill='white' font-size='20'>${global.config.deployment}</text></svg>")`;
styleObject.backgroundImage = `url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' height='40px' width='200px'><text x='0' y='15' fill='%23fff7' font-size='20'>${global.config.deployment}</text></svg>")`;
}
const renderedStyle = useMemo(()=>renderStyle(), [props.style, props.themeBundle]);
renderedPages = useMemo(()=>renderPages(), [props.text, displayOptions]);
return (
<>
{/*render dummy page while iFrame is mounting.*/}
{!state.isMounted
? <div className='brewRenderer' onScroll={updateCurrentPage}>
? <div className='brewRenderer'>
<div className='pages'>
{renderDummyPage(1)}
</div>
@@ -196,7 +305,7 @@ const BrewRenderer = (props)=>{
<NotificationPopup />
</div>
<ToolBar onZoomChange={handleZoom} currentPage={props.currentBrewRendererPageNum} totalPages={rawPages.length}/>
<ToolBar displayOptions={displayOptions} onDisplayOptionsChange={handleDisplayOptionsChange} visiblePages={state.visiblePages.length > 0 ? state.visiblePages : [state.centerPage]} totalPages={rawPages.length} headerState={headerState} setHeaderState={setHeaderState}/>
{/*render in iFrame so broken code doesn't crash the site.*/}
<Frame id='BrewRenderer' initialContent={INITIAL_CONTENT}
@@ -205,22 +314,23 @@ const BrewRenderer = (props)=>{
onClick={()=>{emitClick();}}
>
<div className={`brewRenderer ${global.config.deployment && 'deployment'}`}
onScroll={updateCurrentPage}
onKeyDown={handleControlKeys}
tabIndex={-1}
style={ styleObject }>
style={ styleObject }
>
{/* Apply CSS from Style tab and render pages from Markdown tab */}
{state.isMounted
&&
<>
{renderStyle()}
<div className='pages' lang={`${props.lang || 'en'}`} style={{ zoom: `${state.zoom}%` }}>
{renderPages()}
{renderedStyle}
<div className={`pages ${displayOptions.startOnRight ? 'recto' : 'verso'} ${displayOptions.spread}`} lang={`${props.lang || 'en'}`} style={pagesStyle} ref={pagesRef}>
{renderedPages}
</div>
</>
}
</div>
{headerState ? <HeaderNav ref={pagesRef} /> : <></>}
</Frame>
</>
);

View File

@@ -3,13 +3,45 @@
.brewRenderer {
overflow-y : scroll;
will-change : transform;
padding-top : 30px;
padding-top : 60px;
height : 100vh;
&:has(.facing, .flow) {
padding : 60px 30px;
}
&.deployment {
background-color: darkred;
}
:where(.pages) {
margin : 30px 0px;
&.facing {
display: grid;
grid-template-columns: repeat(2, auto);
grid-template-rows: repeat(3, auto);
gap: 10px 10px;
justify-content: safe center;
&.recto .page:first-child {
// sets first page on 'right' ('recto') of the preview, as if for a Cover page.
// todo: add a checkbox to toggle this setting
grid-column-start: 2;
}
& :where(.page) {
margin-left: unset !important;
margin-right: unset !important;
}
}
&.flow {
display: flex;
flex-wrap: wrap;
gap: 10px;
justify-content: safe center;
& :where(.page) {
flex: 0 0 auto;
margin-left: unset !important;
margin-right: unset !important;
}
}
& > :where(.page) {
width : 215.9mm;
height : 279.4mm;
@@ -18,6 +50,9 @@
margin-left : auto;
box-shadow : 1px 4px 14px #000000;
}
*[id] {
scroll-margin-top:100px;
}
}
&::-webkit-scrollbar {
width : 20px;
@@ -35,6 +70,7 @@
.pane { position : relative; }
@media print {
.toolBar { display : none; }
.brewRenderer {
@@ -47,4 +83,7 @@
& > .page { box-shadow : unset; }
}
}
.headerNav {
visibility: hidden;
}
}

View File

@@ -1,75 +1,53 @@
require('./errorBar.less');
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const ErrorBar = createClass({
displayName : 'ErrorBar',
getDefaultProps : function() {
return {
errors : []
};
},
import Dialog from '../../../components/dialog.jsx';
hasOpenError : false,
hasCloseError : false,
hasMatchError : false,
const DISMISS_BUTTON = <i className='fas fa-times dismiss' />;
renderErrors : function(){
this.hasOpenError = false;
this.hasCloseError = false;
this.hasMatchError = false;
const ErrorBar = (props)=>{
if(!props.errors.length) return null;
let hasOpenError = false, hasCloseError = false, hasMatchError = false;
props.errors.map((err)=>{
if(err.id === 'OPEN') hasOpenError = true;
if(err.id === 'CLOSE') hasCloseError = true;
if(err.id === 'MISMATCH') hasMatchError = true;
});
const errors = _.map(this.props.errors, (err, idx)=>{
if(err.id == 'OPEN') this.hasOpenError = true;
if(err.id == 'CLOSE') this.hasCloseError = true;
if(err.id == 'MISMATCH') this.hasMatchError = true;
return <li key={idx}>
Line {err.line} : {err.text}, '{err.type}' tag
</li>;
});
const renderErrors = ()=>(
<ul>
{props.errors.map((err, idx)=>{
return <li key={idx}>
Line {err.line} : {err.text}, '{err.type}' tag
</li>;
})}
</ul>
);
return <ul>{errors}</ul>;
},
renderProtip : function(){
const msg = [];
if(this.hasOpenError){
msg.push(<div>
An unmatched opening tag means there's an opened tag that isn't closed. You need to close your tags, like this {'</div>'}. Make sure to match types!
</div>);
}
if(this.hasCloseError){
msg.push(<div>
An unmatched closing tag means you closed a tag without opening it. Either remove it, or check to where you think you opened it.
</div>);
}
if(this.hasMatchError){
msg.push(<div>
A type mismatch means you closed a tag, but the last open tag was a different type.
</div>);
}
return <div className='protips'>
const renderProtip = ()=>(
<div className='protips'>
<h4>Protips!</h4>
{msg}
</div>;
},
{hasOpenError && <div>Unmatched opening tag. Close your tags, like this {'</div>'}. Match types!</div>}
{hasCloseError && <div>Unmatched closing tag. Either remove it or check where it was opened.</div>}
{hasMatchError && <div>Type mismatch. Closed a tag with a different type.</div>}
</div>
);
render : function(){
if(!this.props.errors.length) return null;
return <div className='errorBar'>
<i className='fas fa-exclamation-triangle' />
<h3> There are HTML errors in your markup</h3>
<small>If these aren't fixed your brew will not render properly when you print it to PDF or share it</small>
{this.renderErrors()}
return (
<Dialog className='errorBar' closeText={DISMISS_BUTTON} >
<div>
<i className='fas fa-exclamation-triangle' />
<h2> There are HTML errors in your markup</h2>
<small>
If these aren't fixed your brew will not render properly when you print it to PDF or share it
</small>
{renderErrors()}
</div>
<hr />
{this.renderProtip()}
</div>;
}
});
{renderProtip()}
</Dialog>
);
};
module.exports = ErrorBar;

View File

@@ -1,60 +1,58 @@
.errorBar{
.errorBar {
position : absolute;
z-index : 10000;
box-sizing : border-box;
top : 32px;
z-index : 1;
width : 100%;
margin-right : 13px;
padding : 20px;
padding-bottom : 10px;
padding-left : 100px;
background-color : @red;
color : white;
i{
position : absolute;
left : 30px;
opacity : 0.8;
font-size : 3em;
}
h3{
font-size : 1.1em;
font-weight : 800;
}
ul{
margin-top : 15px;
font-size : 0.8em;
list-style-position : inside;
list-style-type : disc;
li{
line-height : 1.6em;
background-color : @red;
border : unset;
div {
> i {
float : left;
margin-right : 10px;
margin-bottom : 20px;
font-size : 3em;
opacity : 0.8;
}
h2 { font-weight : 800; }
ul {
margin-top : 15px;
font-size : 0.8em;
list-style-position : inside;
list-style-type : disc;
li { line-height : 1.6em; }
}
}
hr{
box-sizing : border-box;
hr {
height : 2px;
width : 150%;
margin-top : 25px;
margin-bottom : 15px;
margin-left : -100px;
background-color : darken(@red, 8%);
border : none;
}
small{
font-size: 0.6em;
opacity: 0.7;
small {
font-size : 0.6em;
opacity : 0.7;
}
.protips{
margin-left : -80px;
font-size : 0.6em;
&>div{
margin-bottom : 10px;
line-height : 1.2em;
}
h4{
opacity : 0.8;
.protips {
font-size : 0.6em;
line-height : 1.2em;
h4 {
font-weight : 800;
line-height : 1.5em;
text-transform : uppercase;
}
}
button.dismiss {
position : absolute;
top : 20px;
right : 30px;
padding : unset;
font-size : 40px;
background-color : transparent;
opacity : 0.6;
&:hover { opacity : 1; }
}
}

View File

@@ -0,0 +1,115 @@
require('./headerNav.less');
import * as React from 'react';
import * as _ from 'lodash';
const MAX_TEXT_LENGTH = 40;
const HeaderNav = React.forwardRef(({}, pagesRef)=>{
const renderHeaderLinks = ()=>{
if(!pagesRef.current) return;
// Top Level Pages
// Pages that contain an element with a specified class (e.g. cover pages, table of contents)
// will NOT have its content scanned for navigation headers, instead displaying a custom label
// ---
// The property name is class that will be used for detecting the page is a top level page
// The property value is a function that returns the text to be used
const topLevelPages = {
'.frontCover' : (el, pageType)=>{ const text = getHeaderContent(el); return text ? `Cover: ${text}` : 'Cover Page'; },
'.insideCover' : (el, pageType)=>{ const text = getHeaderContent(el); return text ? `Interior: ${text}` : 'Interior Cover Page'; },
'.partCover' : (el, pageType)=>{ const text = getHeaderContent(el); return text ? `Section: ${text}` : 'Section Cover Page'; },
'.backCover' : (el, pageType)=>{ const text = getHeaderContent(el); return text ? `Back: ${text}` : 'Rear Cover Page'; },
'.toc' : ()=>{ return 'Table of Contents'; },
};
const getHeaderContent = el => el.querySelector('h1')?.textContent;
const topLevelPageSelector = Object.keys(topLevelPages).join(',');
const selector = [
'.pages > .page', // All page elements, which by definition have IDs
`.page:not(:has(${topLevelPageSelector})) > [id]`, // All direct children of non-excluded .pages with an ID (Legacy)
`.page:not(:has(${topLevelPageSelector})) > .columnWrapper > [id]`, // All direct children of non-excluded .page > .columnWrapper with an ID (V3)
`.page:not(:has(${topLevelPageSelector})) h2`, // All non-excluded H2 titles, like Monster frame titles
];
const elements = pagesRef.current.querySelectorAll(selector.join(','));
if(!elements) return;
const navList = [];
// navList is a list of objects which have the following structure:
// {
// depth : how deeply indented the item should be
// text : the text to display in the nav link
// link : the hyperlink to navigate to when clicked
// className : [optional] the class to apply to the nav link for styling
// }
elements.forEach((el)=>{
const navEntry = { // Default structure of a navList entry
depth : 7, // All unmatched elements with IDs are set to the maximum depth (7)
text : el.textContent, // Use `textContent` because `innerText` is affected by rendering, e.g. 'content-visibility: auto'
link : el.id
}
if(el.classList.contains('page')) {
let text = `Page ${el.id.slice(1)}`; // Get the page # by trimming off the 'p' from the ID
const pageType = Object.keys(topLevelPages).find(pageType => el.querySelector(pageType));
if (pageType)
text += ` - ${topLevelPages[pageType](el, pageType)}` // If a Top Level Page, add extra label
navEntry.depth = 0; // Pages are always at the least indented level
navEntry.text = text;
navEntry.className = 'pageLink';
}
else if(el.localName.match(/^h[1-6]/)){ // Header elements H1 through H6
navEntry.depth = el.localName[1]; // Depth is set by the header level
}
navList.push(navEntry);
});
return _.map(navList, (navItem, index)=>
<HeaderNavItem {...navItem} key={index} />
);
};
return <nav className='headerNav'>
<ul>
{renderHeaderLinks()}
</ul>
</nav>;
});
const HeaderNavItem = ({ link, text, depth, className })=>{
const trimString = (text, prefixLength = 0)=>{
// Sanity check nav link strings
let output = text;
// If the string has a line break, only use the first line
if(text.indexOf('\n')){
output = text.split('\n')[0];
}
// Trim unecessary spaces from string
output = output.trim();
// Reduce excessively long strings
const maxLength = MAX_TEXT_LENGTH - prefixLength;
if(output.length > maxLength){
return `${output.slice(0, maxLength).trim()}...`;
}
return output;
};
if(!link || !text) return;
return <li>
<a href={`#${link}`} target='_self' className={`depth-${depth} ${className ?? ''}`}>
{trimString(text, depth)}
</a>
</li>;
};
export default HeaderNav;

View File

@@ -0,0 +1,47 @@
.headerNav {
position: fixed;
top: 32px;
left: 0px;
padding: 5px 10px;
background-color: #ccc;
border-radius: 5px;
max-height: calc(100vh - 32px);
max-width: 40vw;
overflow-y: auto;
&.active {
padding-bottom: 10px;
.navIcon {
padding-bottom: 10px;
}
}
.navIcon {
cursor: pointer;
}
li {
list-style-type: none;
a {
display: inline-block;
width: 100%;
font-family: 'Open Sans';
font-size: 12px;
padding: 2px;
color: inherit;
text-decoration: none;
cursor: pointer;
&:hover {
text-decoration: underline;
}
&.pageLink {
font-weight: 900;
}
@depths: 0,1,2,3,4,5,6,7;
each(@depths, {
&.depth-@{value} {
padding-left: ((@value) * 0.5em);
}
});
}
}
}

View File

@@ -1,44 +1,63 @@
require('./notificationPopup.less');
const React = require('react');
const _ = require('lodash');
import React, { useEffect, useState } from 'react';
import request from '../../utils/request-middleware.js';
import Markdown from 'naturalcrit/markdown.js';
import Dialog from '../../../components/dialog.jsx';
const DISMISS_KEY = 'dismiss_notification01-10-24';
const DISMISS_BUTTON = <i className='fas fa-times dismiss' />;
const NotificationPopup = ()=>{
return <Dialog className='notificationPopup' dismissKey={DISMISS_KEY} closeText={DISMISS_BUTTON} >
const [notifications, setNotifications] = useState([]);
const [dissmissKeyList, setDismissKeyList] = useState([]);
const [error, setError] = useState(null);
useEffect(()=>{
getNotifications();
}, []);
const getNotifications = async ()=>{
setError(null);
try {
const res = await request.get('/admin/notification/all');
pickActiveNotifications(res.body || []);
} catch (err) {
console.log(err);
setError(`Error looking up notifications: ${err?.response?.body?.message || err.message}`);
}
};
const pickActiveNotifications = (notifs)=>{
const now = new Date();
const filteredNotifications = notifs.filter((notification)=>{
const startDate = new Date(notification.startAt);
const stopDate = new Date(notification.stopAt);
const dismissed = localStorage.getItem(notification.dismissKey) ? true : false;
return now >= startDate && now <= stopDate && !dismissed;
});
setNotifications(filteredNotifications);
setDismissKeyList(filteredNotifications.map((notif)=>notif.dismissKey));
};
const renderNotificationsList = ()=>{
if(error) return <div className='error'>{error}</div>;
return notifications.map((notification)=>(
<li key={notification.dismissKey} >
<em>{notification.title}</em><br />
<p dangerouslySetInnerHTML={{ __html: Markdown.render(notification.text) }}></p>
</li>
));
};
if(!notifications.length) return;
return <Dialog className='notificationPopup' dismisskeys={dissmissKeyList} closeText={DISMISS_BUTTON} >
<div className='header'>
<i className='fas fa-info-circle info'></i>
<h3>Notice</h3>
<small>This website is always improving and we are still adding new features and squashing bugs. Keep the following in mind:</small>
</div>
<ul>
<li key='Vault'>
<em>Search brews with our new page!</em><br />
We have been working very hard in making this possible, now you can share your work and look at it in the new <a href='/vault'>Vault</a> page!
All PUBLISHED brews will be available to anyone searching there, by title or author, and filtering by renderer.
More features will be coming.
</li>
<li key='googleDriveFolder'>
<em>Don't delete your Homebrewery folder on Google Drive!</em> <br />
We have had several reports of users losing their brews, not realizing
that they had deleted the files on their Google Drive. If you have a Homebrewery folder
on your Google Drive with *.txt files inside, <em>do not delete it</em>!
We cannot help you recover files that you have deleted from your own
Google Drive.
</li>
<li key='faq'>
<em>Protect your work! </em> <br />
If you opt not to use your Google Drive, keep in mind that we do not save a history of your projects. Please make frequent backups of your brews!&nbsp;
<a target='_blank' href='https://www.reddit.com/r/homebrewery/comments/adh6lh/faqs_psas_announcements/'>
See the FAQ
</a> to learn how to avoid losing your work!
</li>
{renderNotificationsList()}
</ul>
</Dialog>;
};

View File

@@ -48,14 +48,46 @@
}
ul {
margin-top : 15px;
font-size : 0.8em;
font-size : 0.9em;
list-style-position : outside;
list-style-type : disc;
li {
margin-top : 1.4em;
font-size : 0.8em;
line-height : 1.4em;
em { font-weight : 800; }
padding-left : 1em;
margin-top : 1.5em;
font-size : 0.9em;
line-height : 1.5em;
em {
font-weight : 800;
text-transform : capitalize;
}
li {
margin-top : 0;
line-height : 1.2em;
list-style-type : square;
}
}
ul ul,ol ol,ul ol,ol ul {
margin-bottom : 0px;
margin-left : 1.5em;
}
}
}
/* Markdown styling */
code {
padding : 0.1em 0.5em;
font-family : 'Courier New', 'Courier', monospace;
overflow-wrap : break-word;
white-space : pre-wrap;
background : #08115A;
border-radius : 2px;
}
pre code {
display : inline-block;
width : 100%;
}
.blank {
height : 1em;
margin-top: 0;
& + * { margin-top: 0; }
}
}

View File

@@ -0,0 +1,46 @@
// Derived from the vue-html-secure package, customized for Homebrewery
let doc = null;
let div = null;
function safeHTML(htmlString) {
// If the Document interface doesn't exist, exit
if(typeof document == 'undefined') return null;
// If the test document and div don't exist, create them
if(!doc) doc = document.implementation.createHTMLDocument('');
if(!div) div = doc.createElement('div');
// Set the test div contents to the evaluation string
div.innerHTML = htmlString;
// Grab all nodes from the test div
const elements = div.querySelectorAll('*');
// Blacklisted tags
const blacklistTags = ['script', 'noscript', 'noembed'];
// Tests to remove attributes
const blacklistAttrs = [
(test)=>{return test.localName.indexOf('on') == 0;},
(test)=>{return test.localName.indexOf('type') == 0 && test.value.match(/submit/i);},
(test)=>{return test.value.replace(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205f\u3000]/g, '').toLowerCase().trim().indexOf('javascript:') == 0;}
];
elements.forEach((element)=>{
// Check each element for blacklisted type
if(blacklistTags.includes(element?.localName?.toLowerCase())) {
element.remove();
return;
}
// Check remaining elements for blacklisted attributes
for (const attribute of element.attributes){
if(blacklistAttrs.some((test)=>{return test(attribute);})) {
element.removeAttribute(attribute.localName);
break;
};
};
});
return div.innerHTML;
};
module.exports.safeHTML = safeHTML;

View File

@@ -1,28 +1,31 @@
/* eslint-disable max-lines */
require('./toolBar.less');
const React = require('react');
const { useState, useEffect } = React;
const _ = require('lodash');
import { Anchored, AnchoredBox, AnchoredTrigger } from '../../../components/Anchored.jsx';
const MAX_ZOOM = 300;
const MIN_ZOOM = 10;
const ToolBar = ({ onZoomChange, currentPage, onPageChange, totalPages })=>{
const ToolBar = ({ displayOptions, onDisplayOptionsChange, visiblePages, totalPages, headerState, setHeaderState })=>{
const [zoomLevel, setZoomLevel] = useState(100);
const [pageNum, setPageNum] = useState(currentPage);
const [pageNum, setPageNum] = useState(1);
const [toolsVisible, setToolsVisible] = useState(true);
useEffect(()=>{
onZoomChange(zoomLevel);
}, [zoomLevel]);
useEffect(()=>{
setPageNum(currentPage);
}, [currentPage]);
// format multiple visible pages as a range (e.g. "150-153")
const pageRange = visiblePages.length === 1 ? `${visiblePages[0]}` : `${visiblePages[0]} - ${visiblePages.at(-1)}`;
setPageNum(pageRange);
}, [visiblePages]);
const handleZoomButton = (zoom)=>{
setZoomLevel(_.round(_.clamp(zoom, MIN_ZOOM, MAX_ZOOM)));
handleOptionChange('zoomLevel', _.round(_.clamp(zoom, MIN_ZOOM, MAX_ZOOM)));
};
const handleOptionChange = (optionKey, newValue)=>{
onDisplayOptionsChange({ ...displayOptions, [optionKey]: newValue });
};
const handlePageInput = (pageInput)=>{
@@ -30,16 +33,16 @@ const ToolBar = ({ onZoomChange, currentPage, onPageChange, totalPages })=>{
setPageNum(parseInt(pageInput)); // input type is 'text', so `page` comes in as a string, not number.
};
// scroll to a page, used in the Prev/Next Page buttons.
const scrollToPage = (pageNumber)=>{
if(typeof pageNumber !== 'number') return;
pageNumber = _.clamp(pageNumber, 1, totalPages);
const iframe = document.getElementById('BrewRenderer');
const brewRenderer = iframe?.contentWindow?.document.querySelector('.brewRenderer');
const page = brewRenderer?.querySelector(`#p${pageNumber}`);
page?.scrollIntoView({ block: 'start' });
setPageNum(pageNumber);
};
const calculateChange = (mode)=>{
const iframe = document.getElementById('BrewRenderer');
const iframeWidth = iframe.getBoundingClientRect().width;
@@ -55,55 +58,66 @@ const ToolBar = ({ onZoomChange, currentPage, onPageChange, totalPages })=>{
desiredZoom = (iframeWidth / widestPage) * 100;
} else if(mode == 'fit'){
let minDimRatio;
// find the page with the largest single dim (height or width) so that zoom can be adapted to fit it.
const minDimRatio = [...pages].reduce((minRatio, page)=>Math.min(minRatio, iframeWidth / page.offsetWidth, iframeHeight / page.offsetHeight), Infinity);
if(displayOptions.spread === 'facing')
minDimRatio = [...pages].reduce((minRatio, page)=>Math.min(minRatio, iframeWidth / page.offsetWidth / 2), Infinity); // if 'facing' spread, fit two pages in view
else
minDimRatio = [...pages].reduce((minRatio, page)=>Math.min(minRatio, iframeWidth / page.offsetWidth, iframeHeight / page.offsetHeight), Infinity);
desiredZoom = minDimRatio * 100;
}
const margin = 5; // extra space so page isn't edge to edge (not truly "to fill")
const deltaZoom = (desiredZoom - zoomLevel) - margin;
const deltaZoom = (desiredZoom - displayOptions.zoomLevel) - margin;
return deltaZoom;
};
return (
<div className={`toolBar ${toolsVisible ? 'visible' : 'hidden'}`}>
<button className='toggleButton' title={`${toolsVisible ? 'Hide' : 'Show'} Preview Toolbar`} onClick={()=>{setToolsVisible(!toolsVisible);}}><i className='fas fa-glasses' /></button>
<div id='preview-toolbar' className={`toolBar ${toolsVisible ? 'visible' : 'hidden'}`} role='toolbar'>
<div className='toggleButton'>
<button title={`${toolsVisible ? 'Hide' : 'Show'} Preview Toolbar`} onClick={()=>{setToolsVisible(!toolsVisible);}}><i className='fas fa-glasses' /></button>
<button title={`${headerState ? 'Hide' : 'Show'} Header Navigation`} onClick={()=>{setHeaderState(!headerState);}}><i className='fas fa-rectangle-list' /></button>
</div>
{/*v=====----------------------< Zoom Controls >---------------------=====v*/}
<div className='group'>
<div className='group' role='group' aria-label='Zoom' aria-hidden={!toolsVisible}>
<button
id='fill-width'
className='tool'
onClick={()=>handleZoomButton(zoomLevel + calculateChange('fill'))}
title='Set zoom to fill preview with one page'
onClick={()=>handleZoomButton(displayOptions.zoomLevel + calculateChange('fill'))}
>
<i className='fac fit-width' />
</button>
<button
id='zoom-to-fit'
className='tool'
onClick={()=>handleZoomButton(zoomLevel + calculateChange('fit'))}
title='Set zoom to fit entire page in preview'
onClick={()=>handleZoomButton(displayOptions.zoomLevel + calculateChange('fit'))}
>
<i className='fac zoom-to-fit' />
</button>
<button
id='zoom-out'
className='tool'
onClick={()=>handleZoomButton(zoomLevel - 20)}
disabled={zoomLevel <= MIN_ZOOM}
onClick={()=>handleZoomButton(displayOptions.zoomLevel - 20)}
disabled={displayOptions.zoomLevel <= MIN_ZOOM}
title='Zoom Out'
>
<i className='fas fa-magnifying-glass-minus' />
</button>
<input
id='zoom-slider'
className='range-input tool'
className='range-input tool hover-tooltip'
type='range'
name='zoom'
title='Set Zoom'
list='zoomLevels'
min={MIN_ZOOM}
max={MAX_ZOOM}
step='1'
value={zoomLevel}
value={displayOptions.zoomLevel}
onChange={(e)=>handleZoomButton(parseInt(e.target.value))}
/>
<datalist id='zoomLevels'>
@@ -113,20 +127,74 @@ const ToolBar = ({ onZoomChange, currentPage, onPageChange, totalPages })=>{
<button
id='zoom-in'
className='tool'
onClick={()=>handleZoomButton(zoomLevel + 20)}
disabled={zoomLevel >= MAX_ZOOM}
onClick={()=>handleZoomButton(displayOptions.zoomLevel + 20)}
disabled={displayOptions.zoomLevel >= MAX_ZOOM}
title='Zoom In'
>
<i className='fas fa-magnifying-glass-plus' />
</button>
</div>
{/*v=====----------------------< Spread Controls >---------------------=====v*/}
<div className='group' role='group' aria-label='Spread' aria-hidden={!toolsVisible}>
<div className='radio-group' role='radiogroup'>
<button role='radio'
id='single-spread'
className='tool'
title='Single Page'
onClick={()=>{handleOptionChange('spread', 'active');}}
aria-checked={displayOptions.spread === 'single'}
><i className='fac single-spread' /></button>
<button role='radio'
id='facing-spread'
className='tool'
title='Facing Pages'
onClick={()=>{handleOptionChange('spread', 'facing');}}
aria-checked={displayOptions.spread === 'facing'}
><i className='fac facing-spread' /></button>
<button role='radio'
id='flow-spread'
className='tool'
title='Flow Pages'
onClick={()=>{handleOptionChange('spread', 'flow');}}
aria-checked={displayOptions.spread === 'flow'}
><i className='fac flow-spread' /></button>
</div>
<Anchored>
<AnchoredTrigger id='spread-settings' className='tool' title='Spread options'><i className='fas fa-gear' /></AnchoredTrigger>
<AnchoredBox title='Options'>
<h1>Options</h1>
<label title='Modify the horizontal space between pages.'>
Column gap
<input type='range' min={0} max={200} defaultValue={10} className='range-input' onChange={(evt)=>handleOptionChange('columnGap', evt.target.value)} />
</label>
<label title='Modify the vertical space between rows of pages.'>
Row gap
<input type='range' min={0} max={200} defaultValue={10} className='range-input' onChange={(evt)=>handleOptionChange('rowGap', evt.target.value)} />
</label>
<label title='Start 1st page on the right side, such as if you have cover page.'>
Start on right
<input type='checkbox' checked={displayOptions.startOnRight} onChange={()=>{handleOptionChange('startOnRight', !displayOptions.startOnRight);}}
title={displayOptions.spread !== 'facing' ? 'Switch to Facing to enable toggle.' : null} />
</label>
<label title='Toggle the page shadow on every page.'>
Page shadows
<input type='checkbox' checked={displayOptions.pageShadows} onChange={()=>{handleOptionChange('pageShadows', !displayOptions.pageShadows);}} />
</label>
</AnchoredBox>
</Anchored>
</div>
{/*v=====----------------------< Page Controls >---------------------=====v*/}
<div className='group'>
<div className='group' role='group' aria-label='Pages' aria-hidden={!toolsVisible}>
<button
id='previous-page'
className='previousPage tool'
onClick={()=>scrollToPage(pageNum - 1)}
disabled={pageNum <= 1}
type='button'
title='Previous Page(s)'
onClick={()=>scrollToPage(_.min(visiblePages) - visiblePages.length)}
disabled={visiblePages.includes(1)}
>
<i className='fas fa-arrow-left'></i>
</button>
@@ -137,6 +205,7 @@ const ToolBar = ({ onZoomChange, currentPage, onPageChange, totalPages })=>{
className='text-input'
type='text'
name='page'
title='Current page(s) in view'
inputMode='numeric'
pattern='[0-9]'
value={pageNum}
@@ -144,15 +213,18 @@ const ToolBar = ({ onZoomChange, currentPage, onPageChange, totalPages })=>{
onChange={(e)=>handlePageInput(e.target.value)}
onBlur={()=>scrollToPage(pageNum)}
onKeyDown={(e)=>e.key == 'Enter' && scrollToPage(pageNum)}
style={{ width: `${pageNum.length}ch` }}
/>
<span id='page-count'>/ {totalPages}</span>
<span id='page-count' title='Total Page Count'>/ {totalPages}</span>
</div>
<button
id='next-page'
className='tool'
onClick={()=>scrollToPage(pageNum + 1)}
disabled={pageNum >= totalPages}
type='button'
title='Next Page(s)'
onClick={()=>scrollToPage(_.max(visiblePages) + 1)}
disabled={visiblePages.includes(totalPages)}
>
<i className='fas fa-arrow-right'></i>
</button>

View File

@@ -13,11 +13,12 @@
height : auto;
padding : 2px 0;
font-family : 'Open Sans', sans-serif;
font-size : 13px;
color : #CCCCCC;
background-color : #555555;
& > *:not(.toggleButton) {
opacity: 1;
transition: all .2s ease;
opacity : 1;
transition : all 0.2s ease;
}
.group {
@@ -34,14 +35,78 @@
align-items : center;
}
.active, [aria-checked='true'] { background-color : #444444; }
.anchored-trigger {
&.active { background-color : #444444; }
}
.anchored-box {
--box-color : #555555;
top : 30px;
display : flex;
flex-direction : column;
gap : 5px;
padding : 15px;
margin-top : 10px;
font-size : 0.8em;
color : #CCCCCC;
background-color : var(--box-color);
border-radius : 5px;
h1 {
padding-bottom : 0.3em;
margin-bottom : 0.5em;
border-bottom : 1px solid currentColor;
}
h2 {
padding-bottom : 0.3em;
margin : 1em 0 0.5em 0;
color : lightgray;
border-bottom : 1px solid currentColor;
}
label {
display : flex;
gap : 6px;
align-items : center;
justify-content : space-between;
}
input {
height : unset;
&[type='range'] { padding : 0; }
}
&::before {
position : absolute;
top : -20px;
left : 50%;
width : 0px;
height : 0px;
pointer-events : none;
content : '';
border : 10px solid transparent;
border-bottom : 10px solid var(--box-color);
transform : translateX(-50%);
}
}
.radio-group:has(button[role='radio']) {
display : flex;
height : 100%;
border : 1px solid #333333;
}
input {
position : relative;
height : 1.5em;
padding : 2px 5px;
font-family : 'Open Sans', sans-serif;
color : #000000;
background : #EEEEEE;
border : 1px solid gray;
color : inherit;
background : #3B3B3B;
border : none;
&:focus { outline : 1px solid #D3D3D3; }
// `.range-input` if generic to all range inputs, or `#zoom-slider` if only for zoom slider
@@ -50,14 +115,14 @@
color : #D3D3D3;
accent-color : #D3D3D3;
&::-webkit-slider-thumb, &::-moz-slider-thumb {
&::-webkit-slider-thumb, &::-moz-range-thumb {
width : 5px;
height : 5px;
cursor : pointer;
cursor : ew-resize;
outline : none;
}
&:hover::after {
&.hover-tooltip[value]:hover::after {
position : absolute;
bottom : -30px;
left : 50%;
@@ -76,53 +141,49 @@
// `.text-input` if generic to all range inputs, or `#page-input` if only for current page input
&#page-input {
width : 4ch;
min-width : 5ch;
margin-right : 1ch;
text-align : center;
}
}
button {
box-sizing : content-box;
box-sizing : border-box;
display : flex;
align-items : center;
justify-content : center;
width : auto;
min-width : 46px;
height : 100%;
padding : 0 0px;
font-weight : unset;
color : inherit;
background-color : unset;
&:hover { background-color : #444444; }
&:focus { outline : 1px solid #D3D3D3; }
&:focus { border : 1px solid #D3D3D3;outline : none;}
&:disabled {
color : #777777;
background-color : unset !important;
}
i {
font-size:1.2em;
}
i { font-size : 1.2em; }
}
&.hidden {
width: 32px;
transition: all .3s ease;
flex-wrap:nowrap;
overflow: hidden;
background-color: unset;
opacity: .5;
flex-wrap : nowrap;
width : 92px;
overflow : hidden;
background-color : unset;
opacity : 0.5;
transition : all 0.3s ease;
& > *:not(.toggleButton) {
opacity: 0;
transition: all .2s ease;
opacity : 0;
transition : all 0.2s ease;
}
}
}
button.toggleButton {
z-index : 5;
position:absolute;
left: 0;
width: 32px;
min-width: unset;
.toggleButton {
position : absolute;
left : 0;
z-index : 5;
width : 32px;
min-width : unset;
height : 100%;
display : flex;
}

View File

@@ -4,7 +4,7 @@ const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const dedent = require('dedent-tabs').default;
const Markdown = require('../../../shared/naturalcrit/markdown.js');
import Markdown from '../../../shared/naturalcrit/markdown.js';
const CodeEditor = require('naturalcrit/codeEditor/codeEditor.jsx');
const SnippetBar = require('./snippetbar/snippetbar.jsx');
@@ -12,7 +12,8 @@ const MetadataEditor = require('./metadataEditor/metadataEditor.jsx');
const EDITOR_THEME_KEY = 'HOMEBREWERY-EDITOR-THEME';
const SNIPPETBAR_HEIGHT = 25;
const PAGEBREAK_REGEX_V3 = /^(?=\\page(?: *{[^\n{}]*})?$)/m;
const SNIPPETBAR_HEIGHT = 25;
const DEFAULT_STYLE_TEXT = dedent`
/*=======--- Example CSS styling ---=======*/
/* Any CSS here will apply to your document! */
@@ -126,15 +127,15 @@ const Editor = createClass({
},
updateCurrentCursorPage : function(cursor) {
const lines = this.props.brew.text.split('\n').slice(0, cursor.line + 1);
const pageRegex = this.props.brew.renderer == 'V3' ? /^\\page$/ : /\\page/;
const lines = this.props.brew.text.split('\n').slice(1, cursor.line + 1);
const pageRegex = this.props.brew.renderer == 'V3' ? PAGEBREAK_REGEX_V3 : /\\page/;
const currentPage = lines.reduce((count, line)=>count + (pageRegex.test(line) ? 1 : 0), 1);
this.props.onCursorPageChange(currentPage);
},
updateCurrentViewPage : function(topScrollLine) {
const lines = this.props.brew.text.split('\n').slice(0, topScrollLine + 1);
const pageRegex = this.props.brew.renderer == 'V3' ? /^\\page$/ : /\\page/;
const lines = this.props.brew.text.split('\n').slice(1, topScrollLine + 1);
const pageRegex = this.props.brew.renderer == 'V3' ? PAGEBREAK_REGEX_V3 : /\\page/;
const currentPage = lines.reduce((count, line)=>count + (pageRegex.test(line) ? 1 : 0), 1);
this.props.onViewPageChange(currentPage);
},
@@ -174,7 +175,7 @@ const Editor = createClass({
for (let i=customHighlights.length - 1;i>=0;i--) customHighlights[i].clear();
let editorPageCount = 2; // start page count from page 2
let editorPageCount = 1; // start page count from page 1
_.forEach(this.props.brew.text.split('\n'), (line, lineNumber)=>{
@@ -190,7 +191,10 @@ const Editor = createClass({
// Styling for \page breaks
if((this.props.renderer == 'legacy' && line.includes('\\page')) ||
(this.props.renderer == 'V3' && line.match(/^\\page$/))) {
(this.props.renderer == 'V3' && line.match(PAGEBREAK_REGEX_V3))) {
if(lineNumber > 0) // Since \page is optional on first line of document,
editorPageCount += 1; // don't use it to increment page count; stay at 1
// add back the original class 'background' but also add the new class '.pageline'
codeMirror.addLineClass(lineNumber, 'background', 'pageLine');
@@ -199,8 +203,6 @@ const Editor = createClass({
textContent : editorPageCount
});
codeMirror.setBookmark({ line: lineNumber, ch: line.length }, pageCountElement);
editorPageCount += 1;
};
// New Codemirror styling for V3 renderer
@@ -314,7 +316,7 @@ const Editor = createClass({
},
brewJump : function(targetPage=this.props.currentEditorCursorPageNum, smooth=true){
if(!window || isJumping)
if(!window || !this.isText() || isJumping)
return;
// Get current brewRenderer scroll position and calculate target position
@@ -355,10 +357,10 @@ const Editor = createClass({
},
sourceJump : function(targetPage=this.props.currentBrewRendererPageNum, smooth=true){
if(!this.isText || isJumping)
if(!this.isText() || isJumping)
return;
const textSplit = this.props.renderer == 'V3' ? /^\\page$/gm : /\\page/;
const textSplit = this.props.renderer == 'V3' ? PAGEBREAK_REGEX_V3 : /\\page/;
const textString = this.props.brew.text.split(textSplit).slice(0, targetPage-1).join(textSplit);
const targetLine = textString.match('\n') ? textString.split('\n').length - 1 : -1;
@@ -454,6 +456,7 @@ const Editor = createClass({
rerenderParent={this.rerenderParent} />
<MetadataEditor
metadata={this.props.brew}
themeBundle={this.props.themeBundle}
onChange={this.props.onMetaChange}
reportError={this.props.reportError}
userThemes={this.props.userThemes}/>

View File

@@ -2,6 +2,7 @@
.editor {
position : relative;
width : 100%;
container: editor / inline-size;
.codeEditor {
height : 100%;

View File

@@ -3,10 +3,10 @@ require('./metadataEditor.less');
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const request = require('../../utils/request-middleware.js');
import request from '../../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 TagInput = require('../tagInput/tagInput.jsx');
const Themes = require('themes/themes.json');
@@ -40,6 +40,7 @@ const MetadataEditor = createClass({
theme : '5ePHB',
lang : 'en'
},
onChange : ()=>{},
reportError : ()=>{}
};
@@ -47,7 +48,7 @@ const MetadataEditor = createClass({
getInitialState : function(){
return {
showThumbnail : true
showThumbnail : true
};
},
@@ -67,6 +68,11 @@ const MetadataEditor = createClass({
const inputRules = validations[name] ?? [];
const validationErr = inputRules.map((rule)=>rule(e.target.value)).filter(Boolean);
const debouncedReportValidity = _.debounce((target, errMessage) => {
callIfExists(target, 'setCustomValidity', errMessage);
callIfExists(target, 'reportValidity');
}, 300); // 300ms debounce delay, adjust as needed
// if no validation rules, save to props
if(validationErr.length === 0){
callIfExists(e.target, 'setCustomValidity', '');
@@ -74,14 +80,16 @@ const MetadataEditor = createClass({
...this.props.metadata,
[name] : e.target.value
});
return true;
} else {
// if validation issues, display built-in browser error popup with each error.
const errMessage = validationErr.map((err)=>{
return `- ${err}`;
}).join('\n');
callIfExists(e.target, 'setCustomValidity', errMessage);
callIfExists(e.target, 'reportValidity');
debouncedReportValidity(e.target, errMessage);
return false;
}
},
@@ -112,6 +120,14 @@ const MetadataEditor = createClass({
handleTheme : function(theme){
this.props.metadata.renderer = theme.renderer;
this.props.metadata.theme = theme.path;
this.props.onChange(this.props.metadata, 'theme');
},
handleThemeWritein : function(e) {
const shareId = e.target.value.split('/').pop(); //Extract just the ID if a URL was pasted in
this.props.metadata.theme = shareId;
this.props.onChange(this.props.metadata, 'theme');
},
@@ -200,7 +216,7 @@ const MetadataEditor = createClass({
if(theme.path == this.props.metadata.shareId) return;
const preview = theme.thumbnail || `/themes/${theme.renderer}/${theme.path}/dropdownPreview.png`;
const texture = theme.thumbnail || `/themes/${theme.renderer}/${theme.path}/dropdownTexture.png`;
return <div className='item' key={`${renderer}_${theme.name}`} onClick={()=>this.handleTheme(theme)} title={''}>
return <div className='item' key={`${renderer}_${theme.name}`} value={`${theme.author ?? renderer} : ${theme.name}`} data={theme} title={''}>
{theme.author ?? renderer} : {theme.name}
<div className='texture-container'>
<img src={texture}/>
@@ -210,26 +226,40 @@ const MetadataEditor = createClass({
<img src={preview}/>
</div>
</div>;
});
}).filter(Boolean);
};
const currentRenderer = this.props.metadata.renderer;
const currentTheme = mergedThemes[`${_.upperFirst(this.props.metadata.renderer)}`][this.props.metadata.theme]
?? { name: `!!! THEME MISSING !!! ID=${this.props.metadata.theme}` };
const currentThemeDisplay = this.props.themeBundle?.name ? `${this.props.themeBundle.author ?? currentRenderer} : ${this.props.themeBundle.name}` : 'No Theme Selected';
let dropdown;
if(currentRenderer == 'legacy') {
dropdown =
<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>;
<div className='disabled value' trigger='disabled'>
<div> Themes are not supported in the Legacy Renderer </div>
</div>;
} else {
dropdown =
<Nav.dropdown className='value' trigger='click'>
<div> {currentTheme.author ?? _.upperFirst(currentRenderer)} : {currentTheme.name} <i className='fas fa-caret-down'></i> </div>
{listThemes(currentRenderer)}
</Nav.dropdown>;
<div className='value'>
<Combobox trigger='click'
className='themes-dropdown'
default={currentThemeDisplay}
placeholder='Select from below, or enter the Share URL or ID of a brew with the meta:theme tag'
onSelect={(value)=>this.handleTheme(value)}
onEntry={(e)=>{
e.target.setCustomValidity(''); //Clear the validation popup while typing
if(this.handleFieldChange('theme', e))
this.handleThemeWritein(e);
}}
options={listThemes(currentRenderer)}
autoSuggest={{
suggestMethod : 'includes',
clearAutoSuggestOnClick : true,
filterOn : ['value', 'title']
}}
/>
<small>Select from the list below (built-in themes and brews you have tagged "meta:theme"), or paste in the Share URL or Share ID of any brew.</small>
</div>;
}
return <div className='field themes'>
@@ -244,15 +274,13 @@ const MetadataEditor = createClass({
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>
return <div className='item' title={englishName.of(code)} key={`${index}`} value={code} 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'>
@@ -263,16 +291,15 @@ const MetadataEditor = createClass({
onSelect={(value)=>this.handleLanguage(value)}
onEntry={(e)=>{
e.target.setCustomValidity(''); //Clear the validation popup while typing
debouncedHandleFieldChange('lang', e);
this.handleFieldChange('lang', e);
}}
options={listLanguages()}
autoSuggest={{
suggestMethod : 'startsWith',
clearAutoSuggestOnClick : true,
filterOn : ['data-value', 'data-detail', 'title']
filterOn : ['value', 'detail', 'title']
}}
>
</Combobox>
/>
<small>Sets the HTML Lang property for your brew. May affect hyphenation or spellcheck.</small>
</div>
@@ -341,10 +368,11 @@ const MetadataEditor = createClass({
{this.renderThumbnail()}
</div>
<StringArrayEditor label='tags' valuePatterns={[/^(?:(?:group|meta|system|type):)?[A-Za-z0-9][A-Za-z0-9 \/.\-]{0,40}$/]}
<TagInput label='tags' valuePatterns={[/^(?:(?:group|meta|system|type):)?[A-Za-z0-9][A-Za-z0-9 \/.\-]{0,40}$/]}
placeholder='add tag' unique={true}
values={this.props.metadata.tags}
onChange={(e)=>this.handleFieldChange('tags', e)}/>
onChange={(e)=>this.handleFieldChange('tags', e)}
/>
<div className='field systems'>
<label>systems</label>
@@ -363,12 +391,13 @@ const MetadataEditor = createClass({
{this.renderAuthors()}
<StringArrayEditor label='invited authors' valuePatterns={[/.+/]}
<TagInput label='invited authors' valuePatterns={[/.+/]}
validators={[(v)=>!this.props.metadata.authors?.includes(v)]}
placeholder='invite author' unique={true}
values={this.props.metadata.invitedAuthors}
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)}/>
onChange={(e)=>this.handleFieldChange('invitedAuthors', e)}
/>
<h2>Privacy</h2>

View File

@@ -1,9 +1,12 @@
@import 'naturalcrit/styles/colors.less';
.userThemeName {
padding-left: 10px;
padding-right: 10px;
}
.metadataEditor {
position : absolute;
z-index : 5;
box-sizing : border-box;
width : 100%;
height : calc(100vh - 54px); // 54px is the height of the navbar + snippet bar. probably a better way to dynamic get this.
@@ -71,14 +74,14 @@
border : 1px solid gray;
&:focus { outline : 1px solid #444444; }
}
&.thumbnail {
height : 1.4em;
&.thumbnail, &.themes{
label { line-height : 2.0em; }
.value {
overflow : hidden;
text-overflow : ellipsis;
}
button {
.colorButton();
padding : 0px 5px;
color : white;
background-color : black;
@@ -87,6 +90,17 @@
}
}
&.themes{
.value {
overflow : visible;
text-overflow : auto;
}
button {
padding-left: 5px;
padding-right: 5px;
}
}
&.description {
flex : 1;
textarea.value {
@@ -138,16 +152,16 @@
margin-bottom : 15px;
button { width : 100%; }
button.publish {
.button(@blueLight);
.colorButton(@blueLight);
}
button.unpublish {
.button(@silver);
.colorButton(@silver);
}
}
.delete.field .value {
button {
.button(@red);
.colorButton(@red);
}
}
.authors.field .value {
@@ -155,89 +169,73 @@
}
.themes.field {
.navDropdownContainer {
& .dropdown-container {
position : relative;
z-index : 100;
background-color : white;
&.disabled {
font-style : italic;
color : dimgray;
background-color : darkgray;
}
& > div:first-child {
padding : 3px 3px;
background-color : inherit;
border : 1px solid gray;
i { float : right; }
&:hover {
color : white;
background-color : @blue;
}
& .dropdown-options {
overflow-y : visible;
}
.disabled {
font-style : italic;
color : dimgray;
background-color : darkgray;
}
.item {
position : relative;
padding : 3px 3px;
overflow : visible;
background-color : white;
border-top : 1px solid rgb(118, 118, 118);
.preview {
position : absolute;
top : 0;
right : 0;
z-index : 1;
display : flex;
flex-direction : column;
width : 200px;
overflow : hidden;
color : black;
background : #CCCCCC;
border-radius : 5px;
box-shadow : 0 0 5px black;
opacity : 0;
transition : opacity 250ms ease;
h6 {
padding-block : 0.5em;
padding-inline : 1em;
font-weight : 900;
border-bottom : 2px solid hsl(0,0%,40%);
}
}
.navDropdown .item > p {
width : 45%;
height : 1.1em;
overflow : hidden;
text-overflow : ellipsis;
white-space : nowrap;
}
.navDropdown {
position : absolute;
width : 100%;
box-shadow : 0px 5px 10px rgba(0, 0, 0, 0.3);
.item {
position : relative;
padding : 3px 3px;
overflow : visible;
background-color : white;
border-top : 1px solid rgb(118, 118, 118);
.preview {
position : absolute;
top : 0;
right : 0;
z-index : 1;
display : flex;
flex-direction : column;
width : 200px;
overflow : hidden;
color : black;
background : #CCCCCC;
border-radius : 5px;
box-shadow : 0 0 5px black;
opacity : 0;
transition : opacity 250ms ease;
h6 {
padding-block : 0.5em;
padding-inline : 1em;
font-weight : 900;
border-bottom : 2px solid hsl(0,0%,40%);
}
}
&:hover {
color : white;
background-color : @blue;
}
&:hover > .preview { opacity : 1; }
.texture-container {
position : absolute;
top : 0;
left : 0;
width : 100%;
height : 100%;
min-height : 100%;
overflow : hidden;
> img {
position : absolute;
top : 0px;
right : 0;
width : 50%;
min-height : 100%;
-webkit-mask-image : linear-gradient(90deg, transparent, black 20%);
mask-image : linear-gradient(90deg, transparent, black 20%);
}
}
.texture-container {
position : absolute;
top : 0;
left : 0;
width : 100%;
height : 100%;
min-height : 100%;
overflow : hidden;
> img {
position : absolute;
top : 0;
right : 0;
width : 50%;
min-height : 100%;
-webkit-mask-image : linear-gradient(90deg, transparent, black 20%);
mask-image : linear-gradient(90deg, transparent, black 20%);
}
}
&:hover {
color : white;
background-color : @blue;
filter : unset;
}
&:hover > .preview { opacity : 1; }
}
}
@@ -271,7 +269,7 @@
&:last-child { border-radius : 0 0.5em 0.5em 0; }
}
.badge {
.tag {
padding : 0.3em;
margin : 2px;
font-size : 0.9em;

View File

@@ -27,6 +27,19 @@ module.exports = {
(value)=>{
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;
}
],
theme: [
(value) => {
const URL = global.config.baseUrl.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); //Escape any regex characters
const shareIDPattern = '[a-zA-Z0-9-_]{12}';
const shareURLRegex = new RegExp(`^${URL}\\/share\\/${shareIDPattern}$`);
const shareIDRegex = new RegExp(`^${shareIDPattern}$`);
if (value?.length === 0) return null;
if (shareURLRegex.test(value)) return null;
if (shareIDRegex.test(value)) return null;
return 'Must be a valid Share URL or a 12-character ID.';
}
]
};

View File

@@ -150,18 +150,22 @@ const Snippetbar = createClass({
renderSnippetGroups : function(){
const snippets = this.state.snippets.filter((snippetGroup)=>snippetGroup.view === this.props.view);
if(snippets.length === 0) return null;
return _.map(snippets, (snippetGroup)=>{
return <SnippetGroup
brew={this.props.brew}
groupName={snippetGroup.groupName}
icon={snippetGroup.icon}
snippets={snippetGroup.snippets}
key={snippetGroup.groupName}
onSnippetClick={this.handleSnippetClick}
cursorPos={this.props.cursorPos}
/>;
});
return <div className='snippets'>
{_.map(snippets, (snippetGroup)=>{
return <SnippetGroup
brew={this.props.brew}
groupName={snippetGroup.groupName}
icon={snippetGroup.icon}
snippets={snippetGroup.snippets}
key={snippetGroup.groupName}
onSnippetClick={this.handleSnippetClick}
cursorPos={this.props.cursorPos}
/>;
})
}
</div>;
},
replaceContent : function(item){
@@ -203,58 +207,59 @@ const Snippetbar = createClass({
renderEditorButtons : function(){
if(!this.props.showEditButtons) return;
let foldButtons;
if(this.props.view == 'text'){
foldButtons =
<>
<div className={`editorTool foldAll ${this.props.foldCode ? 'active' : ''}`}
onClick={this.props.foldCode} >
<i className='fas fa-compress-alt' />
</div>
<div className={`editorTool unfoldAll ${this.props.unfoldCode ? 'active' : ''}`}
onClick={this.props.unfoldCode} >
<i className='fas fa-expand-alt' />
</div>
</>;
}
return (
<div className='editors'>
{this.props.view !== 'meta' && <><div className='historyTools'>
<div className={`editorTool snippetGroup history ${this.state.historyExists ? 'active' : ''}`}
onClick={this.toggleHistoryMenu} >
<i className='fas fa-clock-rotate-left' />
{ this.state.showHistory && this.renderHistoryItems() }
</div>
<div className={`editorTool undo ${this.props.historySize.undo ? 'active' : ''}`}
onClick={this.props.undo} >
<i className='fas fa-undo' />
</div>
<div className={`editorTool redo ${this.props.historySize.redo ? 'active' : ''}`}
onClick={this.props.redo} >
<i className='fas fa-redo' />
</div>
</div>
<div className='codeTools'>
<div className={`editorTool foldAll ${this.props.foldCode ? 'active' : ''}`}
onClick={this.props.foldCode} >
<i className='fas fa-compress-alt' />
</div>
<div className={`editorTool unfoldAll ${this.props.unfoldCode ? 'active' : ''}`}
onClick={this.props.unfoldCode} >
<i className='fas fa-expand-alt' />
</div>
<div className={`editorTheme ${this.state.themeSelector ? 'active' : ''}`}
onClick={this.toggleThemeSelector} >
<i className='fas fa-palette' />
{this.state.themeSelector && this.renderThemeSelector()}
</div>
</div></>}
return <div className='editors'>
<div className={`editorTool snippetGroup history ${this.state.historyExists ? 'active' : ''}`}
onClick={this.toggleHistoryMenu} >
<i className='fas fa-clock-rotate-left' />
{ this.state.showHistory && this.renderHistoryItems() }
</div>
<div className={`editorTool undo ${this.props.historySize.undo ? 'active' : ''}`}
onClick={this.props.undo} >
<i className='fas fa-undo' />
</div>
<div className={`editorTool redo ${this.props.historySize.redo ? 'active' : ''}`}
onClick={this.props.redo} >
<i className='fas fa-redo' />
</div>
<div className='divider'></div>
{foldButtons}
<div className={`editorTool editorTheme ${this.state.themeSelector ? 'active' : ''}`}
onClick={this.toggleThemeSelector} >
<i className='fas fa-palette' />
{this.state.themeSelector && this.renderThemeSelector()}
<div className='tabs'>
<div className={cx('text', { selected: this.props.view === 'text' })}
onClick={()=>this.props.onViewChange('text')}>
<i className='fa fa-beer' />
</div>
<div className={cx('style', { selected: this.props.view === 'style' })}
onClick={()=>this.props.onViewChange('style')}>
<i className='fa fa-paint-brush' />
</div>
<div className={cx('meta', { selected: this.props.view === 'meta' })}
onClick={()=>this.props.onViewChange('meta')}>
<i className='fas fa-info-circle' />
</div>
</div>
<div className='divider'></div>
<div className={cx('text', { selected: this.props.view === 'text' })}
onClick={()=>this.props.onViewChange('text')}>
<i className='fa fa-beer' />
</div>
<div className={cx('style', { selected: this.props.view === 'style' })}
onClick={()=>this.props.onViewChange('style')}>
<i className='fa fa-paint-brush' />
</div>
<div className={cx('meta', { selected: this.props.view === 'meta' })}
onClick={()=>this.props.onViewChange('meta')}>
<i className='fas fa-info-circle' />
</div>
</div>;
</div>
)
},
render : function(){
@@ -291,8 +296,9 @@ const SnippetGroup = createClass({
return _.map(snippets, (snippet)=>{
return <div className='snippet' key={snippet.name} onClick={(e)=>this.handleSnippetClick(e, snippet)}>
<i className={snippet.icon} />
<span className='name'title={snippet.name}>{snippet.name}</span>
<span className={`name${snippet.disabled ? ' disabled' : ''}`} title={snippet.name}>{snippet.name}</span>
{snippet.experimental && <span className='beta'>beta</span>}
{snippet.disabled && <span className='beta' title='temporarily disabled due to large slowdown; under re-design'>disabled</span>}
{snippet.subsnippets && <>
<i className='fas fa-caret-right'></i>
<div className='dropdown side'>

View File

@@ -4,97 +4,119 @@
.snippetBar {
@menuHeight : 25px;
position : relative;
height : @menuHeight;
display : flex;
flex-wrap : wrap-reverse;
justify-content : space-between;
height : auto;
color : black;
background-color : #DDDDDD;
.editors {
position : absolute;
top : 0px;
right : 0px;
.snippets {
display : flex;
justify-content : space-between;
height : @menuHeight;
& > div {
width : @menuHeight;
height : @menuHeight;
line-height : @menuHeight;
text-align : center;
cursor : pointer;
&:hover,&.selected { background-color : #999999; }
&.text {
.tooltipLeft('Brew Editor');
}
&.style {
.tooltipLeft('Style Editor');
}
&.meta {
.tooltipLeft('Properties');
}
&.undo {
.tooltipLeft('Undo');
font-size : 0.75em;
color : grey;
&.active { color : inherit; }
}
&.redo {
.tooltipLeft('Redo');
font-size : 0.75em;
color : grey;
&.active { color : inherit; }
}
&.foldAll {
.tooltipLeft('Fold All');
font-size : 0.75em;
color : inherit;
}
&.unfoldAll {
.tooltipLeft('Unfold All');
font-size : 0.75em;
color : inherit;
}
&.history {
.tooltipLeft('History');
font-size : 0.75em;
color : grey;
position : relative;
&.active {
color : inherit;
justify-content : flex-start;
min-width : 327.58px;
}
.editors {
display : flex;
justify-content : flex-end;
min-width : 225px;
&:only-child { margin-left : auto;min-width:unset;}
>div {
display : flex;
flex : 1;
justify-content : space-around;
&:first-child { border-left : none; }
& > div {
position : relative;
width : @menuHeight;
height : @menuHeight;
line-height : @menuHeight;
text-align : center;
cursor : pointer;
&.editorTool:not(.active) {
cursor:not-allowed;
}
&>.dropdown{
right : -1px;
&>.snippet{
padding-right : 10px;
&:hover,&.selected { background-color : #999999; }
&.text {
.tooltipLeft('Brew Editor');
}
&.style {
.tooltipLeft('Style Editor');
}
&.meta {
.tooltipLeft('Properties');
}
&.undo {
.tooltipLeft('Undo');
font-size : 0.75em;
color : grey;
&.active { color : inherit; }
}
&.redo {
.tooltipLeft('Redo');
font-size : 0.75em;
color : grey;
&.active { color : inherit; }
}
&.foldAll {
.tooltipLeft('Fold All');
font-size : 0.75em;
color : grey;
&.active { color : inherit; }
}
&.unfoldAll {
.tooltipLeft('Unfold All');
font-size : 0.75em;
color : grey;
&.active { color : inherit; }
}
&.history {
.tooltipLeft('History');
position : relative;
font-size : 0.75em;
color : grey;
border : none;
&.active { color : inherit; }
& > .dropdown {
right : -1px;
& > .snippet { padding-right : 10px; }
}
}
}
&.editorTheme {
.tooltipLeft('Editor Themes');
font-size : 0.75em;
color : black;
&.active {
position : relative;
background-color : #999999;
&.editorTheme {
.tooltipLeft('Editor Themes');
font-size : 0.75em;
color : black;
&.active {
position : relative;
background-color : #999999;
}
}
&.divider {
width : 5px;
background : linear-gradient(currentColor, currentColor) no-repeat center/1px 100%;
&:hover { background-color : inherit; }
}
}
&.divider {
width : 5px;
background : linear-gradient(currentColor, currentColor) no-repeat center/1px 100%;
&:hover { background-color : inherit; }
.themeSelector {
position : absolute;
top : 25px;
right : 0;
z-index : 10;
display : flex;
align-items : center;
justify-content : center;
width : 170px;
height : inherit;
background-color : inherit;
}
}
.themeSelector {
position : absolute;
top : 25px;
right : 0;
z-index : 10;
display : flex;
align-items : center;
justify-content : center;
width : 170px;
height : inherit;
background-color : inherit;
}
}
}
.snippetBarButton {
display : inline-block;
@@ -104,6 +126,7 @@
font-weight : 800;
line-height : @menuHeight;
text-transform : uppercase;
text-wrap : nowrap;
cursor : pointer;
&:hover, &.selected { background-color : #999999; }
i {
@@ -120,7 +143,7 @@
.tooltipLeft('Edit Brew Properties');
}
.snippetGroup {
border-right : 1px solid currentColor;
&:hover {
& > .dropdown { visibility : visible; }
}
@@ -142,11 +165,11 @@
cursor : pointer;
.animate(background-color);
i {
min-width : 25px;
height : 1.2em;
margin-right : 8px;
font-size : 1.2em;
min-width: 25px;
text-align: center;
text-align : center;
& ~ i {
margin-right : 0;
margin-left : 5px;
@@ -179,6 +202,7 @@
}
}
.name { margin-right : auto; }
.disabled { text-decoration : line-through; }
.beta {
align-self : center;
padding : 4px 6px;
@@ -204,4 +228,19 @@
}
}
}
}
}
@container editor (width < 553px) {
.snippetBar {
.editors {
flex : 1;
justify-content : space-between;
border-bottom : 1px solid;
}
.snippets {
flex : 1;
justify-content : space-evenly;
}
.editors > div.history > .dropdown { right : unset; }
}
}

View File

@@ -1,149 +0,0 @@
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const StringArrayEditor = createClass({
displayName : 'StringArrayEditor',
getDefaultProps : function() {
return {
label : '',
values : [],
valuePatterns : null,
validators : [],
placeholder : '',
notes : [],
unique : false,
cannotEdit : [],
onChange : ()=>{}
};
},
getInitialState : function() {
return {
valueContext : !!this.props.values ? this.props.values.map((value)=>({
value,
editing : false
})) : [],
temporaryValue : '',
updateValue : ''
};
},
componentDidUpdate : function(prevProps) {
if(!_.eq(this.props.values, prevProps.values)) {
this.setState({
valueContext : this.props.values ? this.props.values.map((newValue)=>({
value : newValue,
editing : this.state.valueContext.find(({ value })=>value === newValue)?.editing || false
})) : []
});
}
},
handleChange : function(value) {
this.props.onChange({
target : {
value
}
});
},
addValue : function(value){
this.handleChange(_.uniq([...this.props.values, value]));
this.setState({
temporaryValue : ''
});
},
removeValue : function(index){
this.handleChange(this.props.values.filter((_, i)=>i !== index));
},
updateValue : function(value, index){
const valueContext = this.state.valueContext;
valueContext[index].value = value;
valueContext[index].editing = false;
this.handleChange(valueContext.map((context)=>context.value));
this.setState({ valueContext, updateValue: '' });
},
editValue : function(index){
if(!!this.props.cannotEdit && this.props.cannotEdit.includes(this.props.values[index])) {
return;
}
const valueContext = this.state.valueContext.map((context, i)=>{
context.editing = index === i;
return context;
});
this.setState({ valueContext, updateValue: this.props.values[index] });
},
valueIsValid : function(value, index) {
const values = _.clone(this.props.values);
if(index !== undefined) {
values.splice(index, 1);
}
const matchesPatterns = !this.props.valuePatterns || this.props.valuePatterns.some((pattern)=>!!(value || '').match(pattern));
const uniqueIfSet = !this.props.unique || !values.includes(value);
const passesValidators = !this.props.validators || this.props.validators.every((validator)=>validator(value));
return matchesPatterns && uniqueIfSet && passesValidators;
},
handleValueInputKeyDown : function(event, index) {
if(event.key === 'Enter') {
if(this.valueIsValid(event.target.value, index)) {
if(index !== undefined) {
this.updateValue(event.target.value, index);
} else {
this.addValue(event.target.value);
}
}
} else if(event.key === 'Escape') {
this.closeEditInput(index);
}
},
closeEditInput : function(index) {
const valueContext = this.state.valueContext;
valueContext[index].editing = false;
this.setState({ valueContext, updateValue: '' });
},
render : function() {
const valueElements = Object.values(this.state.valueContext).map((context, i)=>context.editing
? <React.Fragment key={i}>
<div className='input-group'>
<input type='text' className={`value ${this.valueIsValid(this.state.updateValue, i) ? '' : 'invalid'}`} autoFocus placeholder={this.props.placeholder}
value={this.state.updateValue}
onKeyDown={(e)=>this.handleValueInputKeyDown(e, i)}
onChange={(e)=>this.setState({ updateValue: e.target.value })}/>
{<div className='icon steel' onClick={(e)=>{ e.stopPropagation(); this.closeEditInput(i); }}><i className='fa fa-undo fa-fw'/></div>}
{this.valueIsValid(this.state.updateValue, i) ? <div className='icon steel' onClick={(e)=>{ e.stopPropagation(); this.updateValue(this.state.updateValue, i); }}><i className='fa fa-check fa-fw'/></div> : null}
</div>
</React.Fragment>
: <div className='badge' key={i} onClick={()=>this.editValue(i)}>{context.value}
{!!this.props.cannotEdit && this.props.cannotEdit.includes(context.value) ? null : <div className='icon steel' onClick={(e)=>{ e.stopPropagation(); this.removeValue(i); }}><i className='fa fa-times fa-fw'/></div>}
</div>
);
return <div className='field'>
<label>{this.props.label}</label>
<div style={{ flex: '1 0' }} className='value'>
<div className='list'>
{valueElements}
<div className='input-group'>
<input type='text' className={`value ${this.valueIsValid(this.state.temporaryValue) ? '' : 'invalid'}`} placeholder={this.props.placeholder}
value={this.state.temporaryValue}
onKeyDown={(e)=>this.handleValueInputKeyDown(e)}
onChange={(e)=>this.setState({ temporaryValue: e.target.value })}/>
{this.valueIsValid(this.state.temporaryValue) ? <div className='icon steel' onClick={(e)=>{ e.stopPropagation(); this.addValue(this.state.temporaryValue); }}><i className='fa fa-check fa-fw'/></div> : null}
</div>
</div>
{this.props.notes ? this.props.notes.map((n, index)=><p key={index}><small>{n}</small></p>) : null}
</div>
</div>;
}
});
module.exports = StringArrayEditor;

View File

@@ -0,0 +1,105 @@
require('./tagInput.less');
const React = require('react');
const { useState, useEffect } = React;
const _ = require('lodash');
const TagInput = ({ unique = true, values = [], ...props }) => {
const [tempInputText, setTempInputText] = useState('');
const [tagList, setTagList] = useState(values.map((value) => ({ value, editing: false })));
useEffect(()=>{
handleChange(tagList.map((context)=>context.value))
}, [tagList])
const handleChange = (value)=>{
props.onChange({
target : { value }
})
};
const handleInputKeyDown = ({ evt, value, index, options = {} }) => {
if (_.includes(['Enter', ','], evt.key)) {
evt.preventDefault();
submitTag(evt.target.value, value, index);
if (options.clear) {
setTempInputText('');
}
}
};
const submitTag = (newValue, originalValue, index) => {
setTagList((prevContext) => {
// remove existing tag
if(newValue === null){
return [...prevContext].filter((context, i)=>i !== index);
}
// add new tag
if(originalValue === null){
return [...prevContext, { value: newValue, editing: false }]
}
// update existing tag
return prevContext.map((context, i) => {
if (i === index) {
return { ...context, value: newValue, editing: false };
}
return context;
});
});
};
const editTag = (index) => {
setTagList((prevContext) => {
return prevContext.map((context, i) => {
if (i === index) {
return { ...context, editing: true };
}
return { ...context, editing: false };
});
});
};
const renderReadTag = (context, index) => {
return (
<li key={index}
data-value={context.value}
className='tag'
onClick={() => editTag(index)}>
{context.value}
<button onClick={(evt)=>{evt.stopPropagation(); submitTag(null, context.value, index)}}><i className='fa fa-times fa-fw'/></button>
</li>
);
};
const renderWriteTag = (context, index) => {
return (
<input type='text'
key={index}
defaultValue={context.value}
onKeyDown={(evt) => handleInputKeyDown({evt, value: context.value, index: index})}
autoFocus
/>
);
};
return (
<div className='field'>
<label>{props.label}</label>
<div className='value'>
<ul className='list'>
{tagList.map((context, index) => { return context.editing ? renderWriteTag(context, index) : renderReadTag(context, index); })}
</ul>
<input
type='text'
className='value'
placeholder={props.placeholder}
value={tempInputText}
onChange={(e) => setTempInputText(e.target.value)}
onKeyDown={(evt) => handleInputKeyDown({ evt, value: null, options: { clear: true } })}
/>
</div>
</div>
);
};
module.exports = TagInput;

View File

@@ -1,8 +1,12 @@
//╔===--------------- Polyfills --------------===╗//
import 'core-js/es/string/to-well-formed.js';
//╚===--------------- ---------------===╝//
require('./homebrew.less');
const React = require('react');
const createClass = require('create-react-class');
const { StaticRouter:Router } = require('react-router-dom/server');
const { Route, Routes, useParams, useSearchParams } = require('react-router-dom');
const { StaticRouter:Router } = require('react-router');
const { Route, Routes, useParams, useSearchParams } = require('react-router');
const HomePage = require('./pages/homePage/homePage.jsx');
const EditPage = require('./pages/editPage/editPage.jsx');

View File

@@ -116,6 +116,19 @@ const ErrorNavItem = createClass({
</Nav.item>;
}
if(HBErrorCode === '10') {
return <Nav.item className='save error' icon='fas fa-exclamation-triangle'>
Oops!
<div className='errorContainer' onClick={clearError}>
Looks like the brew you have selected
as a theme is not tagged for use as a
theme. Verify that
brew <a className='lowercase' target='_blank' rel='noopener noreferrer' href={`/share/${response.body.brewId}`}>
{response.body.brewId}</a> has the <span className='lowercase'>meta:theme</span> tag!
</div>
</Nav.item>;
}
return <Nav.item className='save error' icon='fas fa-exclamation-triangle'>
Oops!
<div className='errorContainer'>

View File

@@ -25,12 +25,11 @@
.homebrew nav {
background-color : #333333;
.navContent {
position : relative;
z-index : 2;
display : flex;
justify-content : space-between;
}
position : relative;
z-index : 2;
display : flex;
justify-content : space-between;
.navSection {
display : flex;
align-items : center;

View File

@@ -1,183 +1,179 @@
require('./brewItem.less');
const React = require('react');
const createClass = require('create-react-class');
const { useCallback } = React;
const moment = require('moment');
const request = require('../../../../utils/request-middleware.js');
import request from '../../../../utils/request-middleware.js';
const googleDriveIcon = require('../../../../googleDrive.svg');
const homebreweryIcon = require('../../../../thumbnail.png');
const dedent = require('dedent-tabs').default;
const BrewItem = createClass({
displayName : 'BrewItem',
getDefaultProps : function() {
return {
brew : {
title : '',
description : '',
authors : [],
stubbed : true
},
updateListFilter : ()=>{},
reportError : ()=>{},
renderStorage : true
};
const BrewItem = ({
brew = {
title : '',
description : '',
authors : [],
stubbed : true,
},
updateListFilter = ()=>{},
reportError = ()=>{},
renderStorage = true,
})=>{
deleteBrew : function(){
if(this.props.brew.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;
if(!confirm('Are you REALLY sure? You will not be able to recover the document.')) return;
const deleteBrew = useCallback(()=>{
if(brew.authors.length <= 1) {
if(!window.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;
if(!window.confirm('Are you REALLY sure? You will not be able to recover the document.')) return;
} else {
if(!confirm('Are you sure you want to remove this brew from your collection? This will remove you as an editor, but other owners will still be able to access the document.')) return;
if(!confirm('Are you REALLY sure? You will lose editor access to this document.')) return;
if(!window.confirm('Are you sure you want to remove this brew from your collection? This will remove you as an editor, but other owners will still be able to access the document.')) return;
if(!window.confirm('Are you REALLY sure? You will lose editor access to this document.')) return;
}
request.delete(`/api/${this.props.brew.googleId ?? ''}${this.props.brew.editId}`)
.send()
.end((err, res)=>{
if(err) {
this.props.reportError(err);
} else {
location.reload();
}
});
},
request.delete(`/api/${brew.googleId ?? ''}${brew.editId}`).send().end((err, res)=>{
if (err) reportError(err); else window.location.reload();
});
}, [brew, reportError]);
updateFilter : function(type, term){
this.props.updateListFilter(type, term);
},
const updateFilter = useCallback((type, term)=> updateListFilter(type, term), [updateListFilter]);
renderDeleteBrewLink : function(){
if(!this.props.brew.editId) return;
const renderDeleteBrewLink = ()=>{
if(!brew.editId) return null;
return <a className='deleteLink' onClick={this.deleteBrew}>
<i className='fas fa-trash-alt' title='Delete' />
</a>;
},
return (
<a className='deleteLink' onClick={deleteBrew}>
<i className='fas fa-trash-alt' title='Delete' />
</a>
);
};
renderEditLink : function(){
if(!this.props.brew.editId) return;
const renderEditLink = ()=>{
if(!brew.editId) return null;
let editLink = this.props.brew.editId;
if(this.props.brew.googleId && !this.props.brew.stubbed) {
editLink = this.props.brew.googleId + editLink;
let editLink = brew.editId;
if(brew.googleId && !brew.stubbed) editLink = brew.googleId + editLink;
return (
<a className='editLink' href={`/edit/${editLink}`} target='_blank' rel='noopener noreferrer'>
<i className='fas fa-pencil-alt' title='Edit' />
</a>
);
};
const renderShareLink = ()=>{
if(!brew.shareId) return null;
let shareLink = brew.shareId;
if(brew.googleId && !brew.stubbed) {
shareLink = brew.googleId + shareLink;
}
return <a className='editLink' href={`/edit/${editLink}`} target='_blank' rel='noopener noreferrer'>
<i className='fas fa-pencil-alt' title='Edit' />
</a>;
},
return (
<a className='shareLink' href={`/share/${shareLink}`} target='_blank' rel='noopener noreferrer'>
<i className='fas fa-share-alt' title='Share' />
</a>
);
};
renderShareLink : function(){
if(!this.props.brew.shareId) return;
const renderDownloadLink = ()=>{
if(!brew.shareId) return null;
let shareLink = this.props.brew.shareId;
if(this.props.brew.googleId && !this.props.brew.stubbed) {
shareLink = this.props.brew.googleId + shareLink;
let shareLink = brew.shareId;
if(brew.googleId && !brew.stubbed) {
shareLink = brew.googleId + shareLink;
}
return <a className='shareLink' href={`/share/${shareLink}`} target='_blank' rel='noopener noreferrer'>
<i className='fas fa-share-alt' title='Share' />
</a>;
},
return (
<a className='downloadLink' href={`/download/${shareLink}`}>
<i className='fas fa-download' title='Download' />
</a>
);
};
renderDownloadLink : function(){
if(!this.props.brew.shareId) return;
let shareLink = this.props.brew.shareId;
if(this.props.brew.googleId && !this.props.brew.stubbed) {
shareLink = this.props.brew.googleId + shareLink;
const renderStorageIcon = ()=>{
if(!renderStorage) return null;
if(brew.googleId) {
return (
<span title={brew.webViewLink ? 'Your Google Drive Storage' : 'Another User\'s Google Drive Storage'}>
<a href={brew.webViewLink} target='_blank'>
<img className='googleDriveIcon' src={googleDriveIcon} alt='googleDriveIcon' />
</a>
</span>
);
}
return <a className='downloadLink' href={`/download/${shareLink}`}>
<i className='fas fa-download' title='Download' />
</a>;
},
return (
<span title='Homebrewery Storage'>
<img className='homebreweryIcon' src={homebreweryIcon} alt='homebreweryIcon' />
</span>
);
};
renderStorageIcon : function(){
if(!this.props.renderStorage) return;
if(this.props.brew.googleId) {
return <span title={this.props.brew.webViewLink ? 'Your Google Drive Storage': 'Another User\'s Google Drive Storage'}>
<a href={this.props.brew.webViewLink} target='_blank'>
<img className='googleDriveIcon' src={googleDriveIcon} alt='googleDriveIcon' />
</a>
</span>;
}
if(Array.isArray(brew.tags)) {
brew.tags = brew.tags?.filter((tag)=>tag); // remove tags that are empty strings
brew.tags.sort((a, b)=>{
return a.indexOf(':') - b.indexOf(':') !== 0 ? a.indexOf(':') - b.indexOf(':') : a.toLowerCase().localeCompare(b.toLowerCase());
});
}
return <span title='Homebrewery Storage'>
<img className='homebreweryIcon' src={homebreweryIcon} alt='homebreweryIcon' />
</span>;
},
const dateFormatString = 'YYYY-MM-DD HH:mm:ss';
render : function(){
const brew = this.props.brew;
if(Array.isArray(brew.tags)) { // temporary fix until dud tags are cleaned
brew.tags = brew.tags?.filter((tag)=>tag); //remove tags that are empty strings
brew.tags.sort((a, b)=>{
return a.indexOf(':') - b.indexOf(':') != 0 ? a.indexOf(':') - b.indexOf(':') : a.toLowerCase().localeCompare(b.toLowerCase());
});
}
const dateFormatString = 'YYYY-MM-DD HH:mm:ss';
return <div className='brewItem'>
{brew.thumbnail &&
<div className='thumbnail' style={{ backgroundImage: `url(${brew.thumbnail})` }} >
</div>
}
return (
<div className='brewItem'>
{brew.thumbnail && <div className='thumbnail' style={{ backgroundImage: `url(${brew.thumbnail})` }}></div>}
<div className='text'>
<h2>{brew.title}</h2>
<p className='description'>{brew.description}</p>
</div>
<hr />
<div className='info'>
{brew.tags?.length ? <>
{brew.tags?.length ? (
<div className='brewTags' title={`${brew.tags.length} tags:\n${brew.tags.join('\n')}`}>
<i className='fas fa-tags'/>
<i className='fas fa-tags' />
{brew.tags.map((tag, idx)=>{
const matches = tag.match(/^(?:([^:]+):)?([^:]+)$/);
return <span key={idx} className={matches[1]} onClick={()=>{this.updateFilter(tag);}}>{matches[2]}</span>;
return <span key={idx} className={matches[1]} onClick={()=>updateFilter(tag)}>{matches[2]}</span>;
})}
</div>
</> : <></>
}
) : null}
<span title={`Authors:\n${brew.authors?.join('\n')}`}>
<i className='fas fa-user'/> {brew.authors?.map((author, index)=>(
<i className='fas fa-user' />{' '}
{brew.authors?.map((author, index)=>(
<React.Fragment key={index}>
{author === 'hidden'
? <span title="Username contained an email address; hidden to protect user's privacy">{author}</span>
: <a href={`/user/${author}`}>{author}</a>
}
{author === 'hidden' ? (
<span title="Username contained an email address; hidden to protect user's privacy">
{author}
</span>
) : (<a href={`/user/${author}`}>{author}</a>)}
{index < brew.authors.length - 1 && ', '}
</React.Fragment>
))}
</span>
<br />
<span title={`Last viewed: ${moment(brew.lastViewed).local().format(dateFormatString)}`}>
<i className='fas fa-eye'/> {brew.views}
<i className='fas fa-eye' /> {brew.views}
</span>
{brew.pageCount &&
{brew.pageCount && (
<span title={`Page count: ${brew.pageCount}`}>
<i className='far fa-file' /> {brew.pageCount}
</span>
}
<span title={dedent`
Created: ${moment(brew.createdAt).local().format(dateFormatString)}
Last updated: ${moment(brew.updatedAt).local().format(dateFormatString)}`}>
)}
<span
title={dedent` Created: ${moment(brew.createdAt).local().format(dateFormatString)}
Last updated: ${moment(brew.updatedAt).local().format(dateFormatString)}`}
>
<i className='fas fa-sync-alt' /> {moment(brew.updatedAt).fromNow()}
</span>
{this.renderStorageIcon()}
{renderStorageIcon()}
</div>
<div className='links'>
{this.renderShareLink()}
{this.renderEditLink()}
{this.renderDownloadLink()}
{this.renderDeleteBrewLink()}
{renderShareLink()}
{renderEditLink()}
{renderDownloadLink()}
{renderDeleteBrewLink()}
</div>
</div>;
}
});
</div>
);
};
module.exports = BrewItem;

View File

@@ -60,9 +60,11 @@
list-style : square;
}
.blank {
height : 1em;
margin-top : 0;
& + * { margin-top : 0; }
height: 1em;
margin-top: 0;
& + * {
margin-top: 0;
}
}
}
}

View File

@@ -4,7 +4,7 @@ const React = require('react');
const _ = require('lodash');
const createClass = require('create-react-class');
const request = require('../../utils/request-middleware.js');
import request from '../../utils/request-middleware.js';
const { Meta } = require('vitreum/headtags');
const Nav = require('naturalcrit/nav/nav.jsx');
@@ -16,6 +16,7 @@ const PrintNavItem = 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;
const VaultNavItem = require('../../navbar/vault.navitem.jsx');
const SplitPane = require('naturalcrit/splitPane/splitPane.jsx');
const Editor = require('../../editor/editor.jsx');
@@ -23,7 +24,7 @@ const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
const LockNotification = require('./lockNotification/lockNotification.jsx');
const Markdown = require('naturalcrit/markdown.js');
import Markdown from 'naturalcrit/markdown.js';
const { DEFAULT_BREW_LOAD } = require('../../../../server/brewDefaults.js');
const { printCurrentBrew, fetchThemeBundle } = require('../../../../shared/helpers.js');
@@ -101,6 +102,14 @@ const EditPage = createClass({
window.onbeforeunload = function(){};
document.removeEventListener('keydown', this.handleControlKeys);
},
componentDidUpdate : function(){
const hasChange = this.hasChanges();
if(this.state.isPending != hasChange){
this.setState({
isPending : hasChange
});
}
},
handleControlKeys : function(e){
if(!(e.ctrlKey || e.metaKey)) return;
@@ -137,15 +146,13 @@ const EditPage = createClass({
this.setState((prevState)=>({
brew : { ...prevState.brew, text: text },
isPending : true,
htmlErrors : htmlErrors,
}), ()=>{if(this.state.autoSave) this.trySave();});
},
handleStyleChange : function(style){
this.setState((prevState)=>({
brew : { ...prevState.brew, style: style },
isPending : true
brew : { ...prevState.brew, style: style }
}), ()=>{if(this.state.autoSave) this.trySave();});
},
@@ -157,8 +164,7 @@ const EditPage = createClass({
brew : {
...prevState.brew,
...metadata
},
isPending : true,
}
}), ()=>{if(this.state.autoSave) this.trySave();});
},
@@ -228,8 +234,8 @@ const EditPage = createClass({
htmlErrors : Markdown.validate(prevState.brew.text)
}));
await updateHistory(this.state.brew);
await versionHistoryGarbageCollection();
await updateHistory(this.state.brew).catch(console.error);
await versionHistoryGarbageCollection().catch(console.error);
const transfer = this.state.saveGoogle == _.isNil(this.state.brew.googleId);
@@ -246,16 +252,17 @@ const EditPage = createClass({
});
if(!res) return;
this.savedBrew = res.body;
this.savedBrew = {
...this.state.brew,
googleId : res.body.googleId ? res.body.googleId : null,
editId : res.body.editId,
shareId : res.body.shareId,
version : res.body.version
};
history.replaceState(null, null, `/edit/${this.savedBrew.editId}`);
this.setState((prevState)=>({
brew : { ...prevState.brew,
googleId : this.savedBrew.googleId ? this.savedBrew.googleId : null,
editId : this.savedBrew.editId,
shareId : this.savedBrew.shareId,
version : this.savedBrew.version
},
this.setState(()=>({
brew : this.savedBrew,
isPending : false,
isSaving : false,
unsavedTime : new Date()
@@ -310,7 +317,14 @@ const EditPage = createClass({
},
renderSaveButton : function(){
if(this.state.autoSaveWarning && this.hasChanges()){
// #1 - Currently saving, show SAVING
if(this.state.isSaving){
return <Nav.item className='save' icon='fas fa-spinner fa-spin'>saving...</Nav.item>;
}
// #2 - Unsaved changes exist, autosave is OFF and warning timer has expired, show AUTOSAVE WARNING
if(this.state.isPending && this.state.autoSaveWarning){
this.setAutosaveWarning();
const elapsedTime = Math.round((new Date() - this.state.unsavedTime) / 1000 / 60);
const text = elapsedTime == 0 ? 'Autosave is OFF.' : `Autosave is OFF, and you haven't saved for ${elapsedTime} minutes.`;
@@ -323,18 +337,17 @@ const EditPage = createClass({
</Nav.item>;
}
if(this.state.isSaving){
return <Nav.item className='save' icon='fas fa-spinner fa-spin'>saving...</Nav.item>;
// #3 - Unsaved changes exist, click to save, show SAVE NOW
// Use trySave(true) instead of save() to use debounced save function
if(this.state.isPending){
return <Nav.item className='save' onClick={()=>this.trySave(true)} color='blue' icon='fas fa-save'>Save Now</Nav.item>;
}
if(this.state.isPending && this.hasChanges()){
return <Nav.item className='save' onClick={this.save} color='blue' icon='fas fa-save'>Save Now</Nav.item>;
}
if(!this.state.isPending && !this.state.isSaving && this.state.autoSave){
// #4 - No unsaved changes, autosave is ON, show AUTO-SAVED
if(this.state.autoSave){
return <Nav.item className='save saved'>auto-saved.</Nav.item>;
}
if(!this.state.isPending && !this.state.isSaving){
return <Nav.item className='save saved'>saved.</Nav.item>;
}
// DEFAULT - No unsaved changes, show SAVED
return <Nav.item className='save saved'>saved.</Nav.item>;
},
handleAutoSave : function(){
@@ -378,9 +391,9 @@ const EditPage = createClass({
const title = `${this.props.brew.title} ${systems}`;
const text = `Hey guys! I've been working on this homebrew. I'd love your feedback. Check it out.
**[Homebrewery Link](${global.config.publicUrl}/share/${shareLink})**`;
**[Homebrewery Link](${global.config.baseUrl}/share/${shareLink})**`;
return `https://www.reddit.com/r/UnearthedArcana/submit?title=${encodeURIComponent(title)}&text=${encodeURIComponent(text)}`;
return `https://www.reddit.com/r/UnearthedArcana/submit?title=${encodeURIComponent(title.toWellFormed())}&text=${encodeURIComponent(text)}`;
},
renderNavbar : function(){
@@ -409,7 +422,7 @@ const EditPage = createClass({
<Nav.item color='blue' href={`/share/${shareLink}`}>
view
</Nav.item>
<Nav.item color='blue' onClick={()=>{navigator.clipboard.writeText(`${global.config.publicUrl}/share/${shareLink}`);}}>
<Nav.item color='blue' onClick={()=>{navigator.clipboard.writeText(`${global.config.baseUrl}/share/${shareLink}`);}}>
copy url
</Nav.item>
<Nav.item color='blue' href={this.getRedditLink()} newTab={true} rel='noopener noreferrer'>
@@ -417,6 +430,7 @@ const EditPage = createClass({
</Nav.item>
</Nav.dropdown>
<PrintNavItem />
<VaultNavItem />
<RecentNavItem brew={this.state.brew} storageKey='edit' />
<Account />
</Nav.section>
@@ -429,8 +443,8 @@ const EditPage = createClass({
<Meta name='robots' content='noindex, nofollow' />
{this.renderNavbar()}
{this.props.brew.lock && <LockNotification shareId={this.props.brew.shareId} message={this.props.brew.lock.editMessage} />}
<div className='content'>
{this.props.brew.lock && <LockNotification shareId={this.props.brew.shareId} message={this.props.brew.lock.editMessage} />}
<SplitPane onDragFinish={this.handleSplitMove}>
<Editor
ref={this.editor}
@@ -441,6 +455,7 @@ const EditPage = createClass({
reportError={this.errorReported}
renderer={this.state.brew.renderer}
userThemes={this.props.userThemes}
themeBundle={this.state.themeBundle}
snippetBundle={this.state.themeBundle.snippets}
updateBrew={this.updateBrew}
onCursorPageChange={this.handleEditorCursorPageChange}

View File

@@ -1,7 +1,7 @@
require('./errorPage.less');
const React = require('react');
const UIPage = require('../basePages/uiPage/uiPage.jsx');
const Markdown = require('../../../../shared/naturalcrit/markdown.js');
import Markdown from '../../../../shared/naturalcrit/markdown.js';
const ErrorIndex = require('./errors/errorIndex.js');
const ErrorPage = ({ brew })=>{

View File

@@ -2,6 +2,11 @@ const dedent = require('dedent-tabs').default;
const loginUrl = 'https://www.naturalcrit.com/login';
// Prevent parsing text (e.g. document titles) as markdown
const escape = (text = '')=>{
return text.split('').map((char)=>`&#${char.charCodeAt(0)};`).join('');
};
//001-050 : Brew errors
//050-100 : Other pages errors
@@ -18,7 +23,18 @@ const errorIndex = (props)=>{
'01' : dedent`
## An error occurred while retrieving this brew from Google Drive!
Google reported an error while attempting to retrieve a brew from this link.`,
Google is able to see the brew at this link, but reported an error while attempting to retrieve it.
### Refreshing your Google Credentials
This issue is likely caused by an issue with your Google credentials; if you are the owner of this file, the following steps may resolve the issue:
- Go to https://www.naturalcrit.com/login and click logout if present (in small text at the bottom of the page).
- Click "Sign In with Google", which will refresh your Google credentials.
- After completing the sign in process, return to Homebrewery and refresh/reload the page so that it can pick up the updated credentials.
- If this was the source of the issue, it should now be resolved.
If following these steps does not resolve the issue, please let us know!`,
// Google Drive - 404 : brew deleted or access denied
'02' : dedent`
@@ -50,7 +66,7 @@ const errorIndex = (props)=>{
- **The Google Account may be closed.** Google may have removed the account
due to inactivity or violating a Google policy. Make sure the owner can
still access Google Drive normally and upload/download files to it.
:
If the file isn't found, Google Drive usually puts your file in your Trash folder for
30 days. Assuming the trash hasn't been emptied yet, it might be worth checking.
You can also find the Activity tab on the right side of the Google Drive page, which
@@ -78,7 +94,7 @@ const errorIndex = (props)=>{
:
**Brew Title:** ${props.brew.brewTitle || 'Unable to show title'}
**Brew Title:** ${escape(props.brew.brewTitle) || 'Unable to show title'}
**Current Authors:** ${props.brew.authors?.map((author)=>{return `[${author}](/user/${author})`;}).join(', ') || 'Unable to list authors'}
@@ -93,7 +109,7 @@ const errorIndex = (props)=>{
:
**Brew Title:** ${props.brew.brewTitle || 'Unable to show title'}
**Brew Title:** ${escape(props.brew.brewTitle) || 'Unable to show title'}
**Current Authors:** ${props.brew.authors?.map((author)=>{return `[${author}](/user/${author})`;}).join(', ') || 'Unable to list authors'}
@@ -151,6 +167,14 @@ const errorIndex = (props)=>{
**Requested access:** ${props.brew.accessType}
**Brew ID:** ${props.brew.brewId}`,
// Theme Not Valid
'10' : dedent`
## The selected theme is not tagged as a theme.
The brew selected as a theme exists, but has not been marked for use as a theme with the \`theme:meta\` tag.
If the selected brew is your document, you may designate it as a theme by adding the \`theme:meta\` tag.`,
//account page when account is not defined
'50' : dedent`
@@ -170,10 +194,10 @@ const errorIndex = (props)=>{
**Brew ID:** ${props.brew.brewId}
**Brew Title:** ${props.brew.brewTitle}`,
**Brew Title:** ${escape(props.brew.brewTitle)}`,
// ####### Admin page error #######
'52': dedent`
// ####### Admin page error #######
'52' : dedent`
## Access Denied
You need to provide correct administrator credentials to access this page.`,

View File

@@ -2,7 +2,7 @@ require('./homePage.less');
const React = require('react');
const createClass = require('create-react-class');
const cx = require('classnames');
const request = require('../../utils/request-middleware.js');
import request from '../../utils/request-middleware.js';
const { Meta } = require('vitreum/headtags');
const Nav = require('naturalcrit/nav/nav.jsx');
@@ -100,35 +100,33 @@ const HomePage = createClass({
return <div className='homePage sitePage'>
<Meta name='google-site-verification' content='NwnAQSSJZzAT7N-p5MY6ydQ7Njm67dtbu73ZSyE5Fy4' />
{this.renderNavbar()}
<div className='content'>
<SplitPane onDragFinish={this.handleSplitMove}>
<Editor
ref={this.editor}
brew={this.state.brew}
onTextChange={this.handleTextChange}
renderer={this.state.brew.renderer}
showEditButtons={false}
snippetBundle={this.state.themeBundle.snippets}
onCursorPageChange={this.handleEditorCursorPageChange}
onViewPageChange={this.handleEditorViewPageChange}
currentEditorViewPageNum={this.state.currentEditorViewPageNum}
currentEditorCursorPageNum={this.state.currentEditorCursorPageNum}
currentBrewRendererPageNum={this.state.currentBrewRendererPageNum}
/>
<BrewRenderer
text={this.state.brew.text}
style={this.state.brew.style}
renderer={this.state.brew.renderer}
onPageChange={this.handleBrewRendererPageChange}
currentEditorViewPageNum={this.state.currentEditorViewPageNum}
currentEditorCursorPageNum={this.state.currentEditorCursorPageNum}
currentBrewRendererPageNum={this.state.currentBrewRendererPageNum}
themeBundle={this.state.themeBundle}
/>
</SplitPane>
<div className="content">
<SplitPane onDragFinish={this.handleSplitMove}>
<Editor
ref={this.editor}
brew={this.state.brew}
onTextChange={this.handleTextChange}
renderer={this.state.brew.renderer}
showEditButtons={false}
snippetBundle={this.state.themeBundle.snippets}
onCursorPageChange={this.handleEditorCursorPageChange}
onViewPageChange={this.handleEditorViewPageChange}
currentEditorViewPageNum={this.state.currentEditorViewPageNum}
currentEditorCursorPageNum={this.state.currentEditorCursorPageNum}
currentBrewRendererPageNum={this.state.currentBrewRendererPageNum}
/>
<BrewRenderer
text={this.state.brew.text}
style={this.state.brew.style}
renderer={this.state.brew.renderer}
onPageChange={this.handleBrewRendererPageChange}
currentEditorViewPageNum={this.state.currentEditorViewPageNum}
currentEditorCursorPageNum={this.state.currentEditorCursorPageNum}
currentBrewRendererPageNum={this.state.currentBrewRendererPageNum}
themeBundle={this.state.themeBundle}
/>
</SplitPane>
</div>
<div className={cx('floatingSaveButton', { show: this.state.welcomeText != this.state.brew.text })} onClick={this.handleSave}>
Save current <i className='fas fa-save' />
</div>

View File

@@ -91,13 +91,6 @@ If you are looking for more 5e Homebrew resources check out [r/UnearthedArcana](
\page
## Markdown+
The Homebrewery aims to make homebrewing as simple as possible, providing a live editor with Markdown syntax that is more human-readable and faster to write with than raw HTML.

View File

@@ -2,9 +2,9 @@
require('./newPage.less');
const React = require('react');
const createClass = require('create-react-class');
const request = require('../../utils/request-middleware.js');
import request from '../../utils/request-middleware.js';
const Markdown = require('naturalcrit/markdown.js');
import Markdown from 'naturalcrit/markdown.js';
const Nav = require('naturalcrit/nav/nav.jsx');
const PrintNavItem = require('../../navbar/print.navitem.jsx');
@@ -223,38 +223,39 @@ const NewPage = createClass({
render : function(){
return <div className='newPage sitePage'>
{this.renderNavbar()}
<div className='content'>
<SplitPane onDragFinish={this.handleSplitMove}>
<Editor
ref={this.editor}
brew={this.state.brew}
onTextChange={this.handleTextChange}
onStyleChange={this.handleStyleChange}
onMetaChange={this.handleMetaChange}
renderer={this.state.brew.renderer}
userThemes={this.props.userThemes}
snippetBundle={this.state.themeBundle.snippets}
onCursorPageChange={this.handleEditorCursorPageChange}
onViewPageChange={this.handleEditorViewPageChange}
currentEditorViewPageNum={this.state.currentEditorViewPageNum}
currentEditorCursorPageNum={this.state.currentEditorCursorPageNum}
currentBrewRendererPageNum={this.state.currentBrewRendererPageNum}
/>
<BrewRenderer
text={this.state.brew.text}
style={this.state.brew.style}
renderer={this.state.brew.renderer}
theme={this.state.brew.theme}
themeBundle={this.state.themeBundle}
errors={this.state.htmlErrors}
lang={this.state.brew.lang}
onPageChange={this.handleBrewRendererPageChange}
currentEditorViewPageNum={this.state.currentEditorViewPageNum}
currentEditorCursorPageNum={this.state.currentEditorCursorPageNum}
currentBrewRendererPageNum={this.state.currentBrewRendererPageNum}
allowPrint={true}
/>
</SplitPane>
<div className="content">
<SplitPane onDragFinish={this.handleSplitMove}>
<Editor
ref={this.editor}
brew={this.state.brew}
onTextChange={this.handleTextChange}
onStyleChange={this.handleStyleChange}
onMetaChange={this.handleMetaChange}
renderer={this.state.brew.renderer}
userThemes={this.props.userThemes}
themeBundle={this.state.themeBundle}
snippetBundle={this.state.themeBundle.snippets}
onCursorPageChange={this.handleEditorCursorPageChange}
onViewPageChange={this.handleEditorViewPageChange}
currentEditorViewPageNum={this.state.currentEditorViewPageNum}
currentEditorCursorPageNum={this.state.currentEditorCursorPageNum}
currentBrewRendererPageNum={this.state.currentBrewRendererPageNum}
/>
<BrewRenderer
text={this.state.brew.text}
style={this.state.brew.style}
renderer={this.state.brew.renderer}
theme={this.state.brew.theme}
themeBundle={this.state.themeBundle}
errors={this.state.htmlErrors}
lang={this.state.brew.lang}
onPageChange={this.handleBrewRendererPageChange}
currentEditorViewPageNum={this.state.currentEditorViewPageNum}
currentEditorCursorPageNum={this.state.currentEditorCursorPageNum}
currentBrewRendererPageNum={this.state.currentBrewRendererPageNum}
allowPrint={true}
/>
</SplitPane>
</div>
</div>;
}

View File

@@ -1,6 +1,6 @@
require('./sharePage.less');
const React = require('react');
const createClass = require('create-react-class');
const { useState, useEffect, useCallback } = React;
const { Meta } = require('vitreum/headtags');
const Nav = require('naturalcrit/nav/nav.jsx');
@@ -14,122 +14,114 @@ const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
const { DEFAULT_BREW_LOAD } = require('../../../../server/brewDefaults.js');
const { printCurrentBrew, fetchThemeBundle } = require('../../../../shared/helpers.js');
const SharePage = createClass({
displayName : 'SharePage',
getDefaultProps : function() {
return {
brew : DEFAULT_BREW_LOAD,
disableMeta : false
};
},
const SharePage = (props)=>{
const { brew = DEFAULT_BREW_LOAD, disableMeta = false } = props;
getInitialState : function() {
return {
themeBundle : {},
currentBrewRendererPageNum : 1
};
},
const [state, setState] = useState({
themeBundle : {},
currentBrewRendererPageNum : 1,
});
componentDidMount : function() {
document.addEventListener('keydown', this.handleControlKeys);
const handleBrewRendererPageChange = useCallback((pageNumber)=>{
setState((prevState)=>({
currentBrewRendererPageNum : pageNumber,
...prevState }));
}, []);
fetchThemeBundle(this, this.props.brew.renderer, this.props.brew.theme);
},
componentWillUnmount : function() {
document.removeEventListener('keydown', this.handleControlKeys);
},
handleBrewRendererPageChange : function(pageNumber){
this.setState({ currentBrewRendererPageNum: pageNumber });
},
handleControlKeys : function(e){
const handleControlKeys = (e)=>{
if(!(e.ctrlKey || e.metaKey)) return;
const P_KEY = 80;
if(e.keyCode == P_KEY){
if(e.keyCode == P_KEY) printCurrentBrew();
if(e.keyCode === P_KEY) {
printCurrentBrew();
e.stopPropagation();
e.preventDefault();
}
},
};
processShareId : function() {
return this.props.brew.googleId && !this.props.brew.stubbed ?
this.props.brew.googleId + this.props.brew.shareId :
this.props.brew.shareId;
},
useEffect(()=>{
document.addEventListener('keydown', handleControlKeys);
fetchThemeBundle(
{ setState },
brew.renderer,
brew.theme
);
renderEditLink : function(){
if(!this.props.brew.editId) return;
return ()=>{
document.removeEventListener('keydown', handleControlKeys);
};
}, []);
let editLink = this.props.brew.editId;
if(this.props.brew.googleId && !this.props.brew.stubbed) {
editLink = this.props.brew.googleId + editLink;
}
const processShareId = ()=>{
return brew.googleId && !brew.stubbed ? brew.googleId + brew.shareId : brew.shareId;
};
return <Nav.item color='orange' icon='fas fa-pencil-alt' href={`/edit/${editLink}`}>
edit
</Nav.item>;
},
const renderEditLink = ()=>{
if(!brew.editId) return null;
render : function(){
const titleStyle = this.props.disableMeta ? { cursor: 'default' } : {};
const titleEl = <Nav.item className='brewTitle' style={titleStyle}>{this.props.brew.title}</Nav.item>;
const editLink = brew.googleId && ! brew.stubbed ? brew.googleId + brew.editId : brew.editId;
return <div className='sharePage sitePage'>
return (
<Nav.item color='orange' icon='fas fa-pencil-alt' href={`/edit/${editLink}`}>
edit
</Nav.item>
);
};
const titleEl = (
<Nav.item className='brewTitle' style={disableMeta ? { cursor: 'default' } : {}}>
{brew.title}
</Nav.item>
);
return (
<div className='sharePage sitePage'>
<Meta name='robots' content='noindex, nofollow' />
<Navbar>
<Nav.section className='titleSection'>
{
this.props.disableMeta ?
titleEl
:
<MetadataNav brew={this.props.brew}>
{titleEl}
</MetadataNav>
}
{disableMeta ? titleEl : <MetadataNav brew={brew}>{titleEl}</MetadataNav>}
</Nav.section>
<Nav.section>
{this.props.brew.shareId && <>
<PrintNavItem/>
<Nav.dropdown>
<Nav.item color='red' icon='fas fa-code'>
source
</Nav.item>
<Nav.item color='blue' icon='fas fa-eye' href={`/source/${this.processShareId()}`}>
view
</Nav.item>
{this.renderEditLink()}
<Nav.item color='blue' icon='fas fa-download' href={`/download/${this.processShareId()}`}>
download
</Nav.item>
<Nav.item color='blue' icon='fas fa-clone' href={`/new/${this.processShareId()}`}>
clone to new
</Nav.item>
</Nav.dropdown>
</>}
<RecentNavItem brew={this.props.brew} storageKey='view' />
{brew.shareId && (
<>
<PrintNavItem />
<Nav.dropdown>
<Nav.item color='red' icon='fas fa-code'>
source
</Nav.item>
<Nav.item color='blue' icon='fas fa-eye' href={`/source/${processShareId()}`}>
view
</Nav.item>
{renderEditLink()}
<Nav.item color='blue' icon='fas fa-download' href={`/download/${processShareId()}`}>
download
</Nav.item>
<Nav.item color='blue' icon='fas fa-clone' href={`/new/${processShareId()}`}>
clone to new
</Nav.item>
</Nav.dropdown>
</>
)}
<RecentNavItem brew={brew} storageKey='view' />
<Account />
</Nav.section>
</Navbar>
<div className='content'>
<BrewRenderer
text={this.props.brew.text}
style={this.props.brew.style}
lang={this.props.brew.lang}
renderer={this.props.brew.renderer}
theme={this.props.brew.theme}
themeBundle={this.state.themeBundle}
onPageChange={this.handleBrewRendererPageChange}
currentBrewRendererPageNum={this.state.currentBrewRendererPageNum}
text={brew.text}
style={brew.style}
lang={brew.lang}
renderer={brew.renderer}
theme={brew.theme}
themeBundle={state.themeBundle}
onPageChange={handleBrewRendererPageChange}
currentBrewRendererPageNum={state.currentBrewRendererPageNum}
allowPrint={true}
/>
</div>
</div>;
}
});
</div>
);
};
module.exports = SharePage;

View File

@@ -1,5 +1,5 @@
.sharePage{
.navContent .navSection.titleSection {
nav .navSection.titleSection {
flex-grow: 1;
justify-content: center;
}

View File

@@ -1,12 +1,11 @@
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const { useState } = React;
const _ = require('lodash');
const ListPage = require('../basePages/listPage/listPage.jsx');
const Nav = require('naturalcrit/nav/nav.jsx');
const Navbar = require('../../navbar/navbar.jsx');
const RecentNavItem = require('../../navbar/recent.navitem.jsx').both;
const Account = require('../../navbar/account.navitem.jsx');
const NewBrew = require('../../navbar/newbrew.navitem.jsx');
@@ -14,69 +13,48 @@ const HelpNavItem = require('../../navbar/help.navitem.jsx');
const ErrorNavItem = require('../../navbar/error-navitem.jsx');
const VaultNavitem = require('../../navbar/vault.navitem.jsx');
const UserPage = createClass({
displayName : 'UserPage',
getDefaultProps : function() {
return {
username : '',
brews : [],
query : '',
error : null
};
},
getInitialState : function() {
const usernameWithS = this.props.username + (this.props.username.endsWith('s') ? `` : `s`);
const UserPage = (props)=>{
props = {
username : '',
brews : [],
query : '',
...props
};
const brews = _.groupBy(this.props.brews, (brew)=>{
return (brew.published ? 'published' : 'private');
});
const [error, setError] = useState(null);
const brewCollection = [
{
title : `${usernameWithS} published brews`,
class : 'published',
brews : brews.published
}
];
if(this.props.username == global.account?.username){
brewCollection.push(
{
title : `${usernameWithS} unpublished brews`,
class : 'unpublished',
brews : brews.private
}
);
}
const usernameWithS = props.username + (props.username.endsWith('s') ? `` : `s`);
const groupedBrews = _.groupBy(props.brews, (brew)=>brew.published ? 'published' : 'private');
return {
brewCollection : brewCollection
};
},
errorReported : function(error) {
this.setState({
error
});
},
const brewCollection = [
{
title : `${usernameWithS} published brews`,
class : 'published',
brews : groupedBrews.published || []
},
...(props.username === global.account?.username ? [{
title : `${usernameWithS} unpublished brews`,
class : 'unpublished',
brews : groupedBrews.private || []
}] : [])
];
navItems : function() {
return <Navbar>
const navItems = (
<Navbar>
<Nav.section>
{this.state.error ?
<ErrorNavItem error={this.state.error} parent={this}></ErrorNavItem> :
null
}
{error && (<ErrorNavItem error={error} parent={null}></ErrorNavItem>)}
<NewBrew />
<HelpNavItem />
<VaultNavitem/>
<VaultNavitem />
<RecentNavItem />
<Account />
</Nav.section>
</Navbar>;
},
</Navbar>
);
render : function(){
return <ListPage brewCollection={this.state.brewCollection} navItems={this.navItems()} query={this.props.query} reportError={this.errorReported}></ListPage>;
}
});
return (
<ListPage brewCollection={brewCollection} navItems={navItems} query={props.query} reportError={(err)=>setError(err)} />
);
};
module.exports = UserPage;

View File

@@ -15,7 +15,7 @@ const BrewItem = require('../basePages/listPage/brewItem/brewItem.jsx');
const SplitPane = require('../../../../shared/naturalcrit/splitPane/splitPane.jsx');
const ErrorIndex = require('../errorPage/errors/errorIndex.js');
const request = require('../../utils/request-middleware.js');
import request from '../../utils/request-middleware.js';
const VaultPage = (props)=>{
const [pageState, setPageState] = useState(parseInt(props.query.page) || 1);
@@ -99,14 +99,14 @@ const VaultPage = (props)=>{
setSearching(true);
setError(null);
const title = titleRef.current.value || '';
const author = authorRef.current.value || '';
const count = countRef.current.value || 10;
const v3 = v3Ref.current.checked != false;
const legacy = legacyRef.current.checked != false;
const title = titleRef.current.value || '';
const author = authorRef.current.value || '';
const count = countRef.current.value || 10;
const v3 = v3Ref.current.checked != false;
const legacy = legacyRef.current.checked != false;
const sortOption = sort || 'title';
const dirOption = dir || 'asc';
const pageProp = page || 1;
const dirOption = dir || 'asc';
const pageProp = page || 1;
setSort(sortOption);
setdir(dirOption);
@@ -247,7 +247,7 @@ const VaultPage = (props)=>{
</li>
<li>
Some common words like "a", "after", "through", "itself", "here", etc.,
are ignored in searches. The full list can be found &nbsp;
are ignored in searches. The full list can be found&nbsp;
<a href='https://github.com/mongodb/mongo/blob/0e3b3ca8480ddddf5d0105d11a94bd4698335312/src/mongo/db/fts/stop_words_english.txt'>
here
</a>
@@ -286,9 +286,9 @@ const VaultPage = (props)=>{
};
const renderPaginationControls = ()=>{
if(!totalBrews) return null;
if(!totalBrews || totalBrews < 10) return null;
const countInt = parseInt(props.query.count || 20);
const countInt = parseInt(brewCollection.length || 20);
const totalPages = Math.ceil(totalBrews / countInt);
let startPage, endPage;
@@ -355,7 +355,7 @@ const VaultPage = (props)=>{
};
const renderFoundBrews = ()=>{
if(searching) {
if(searching && !brewCollection) {
return (
<div className='foundBrews searching'>
<h3 className='searchAnim'>Searching</h3>
@@ -395,6 +395,7 @@ const VaultPage = (props)=>{
{`Brews found: `}
<span>{totalBrews}</span>
</span>
{brewCollection.length > 10 && renderPaginationControls()}
{brewCollection.map((brew, index)=>{
return (
<BrewItem
@@ -411,14 +412,13 @@ const VaultPage = (props)=>{
};
return (
<div className='vaultPage'>
<div className='sitePage vaultPage'>
<link href='/themes/V3/Blank/style.css' rel='stylesheet' />
<link href='/themes/V3/5ePHB/style.css' rel='stylesheet' />
{renderNavItems()}
<div className='content'>
<SplitPane showDividerButtons={false}>
<div className='form dataGroup'>{renderForm()}</div>
<div className='resultsContainer dataGroup'>
{renderSortBar()}
{renderFoundBrews()}

View File

@@ -5,369 +5,335 @@
*:not(input) { user-select : none; }
.content {
:where(.content .dataGroup) {
width : 100%;
height : 100%;
background : #2C3E50;
background : white;
.dataGroup {
width : 100%;
height : 100%;
background : white;
&.form .brewLookup {
position : relative;
padding : 50px clamp(20px, 4vw, 50px);
&.form .brewLookup {
position : relative;
padding : 50px clamp(20px, 4vw, 50px);
small {
font-size : 10pt;
color : #555555;
small {
font-size : 10pt;
color : #555555;
a { color : #333333; }
}
a { color : #333333; }
}
code {
padding-inline : 5px;
font-family : monospace;
background : lightgrey;
border-radius : 5px;
}
code {
padding-inline : 5px;
font-family : monospace;
background : lightgrey;
border-radius : 5px;
}
h1, h2, h3, h4 {
font-family : 'CodeBold';
letter-spacing : 2px;
}
h1, h2, h3, h4 {
font-family : 'CodeBold';
letter-spacing : 2px;
}
legend {
h3 {
margin-block : 30px 20px;
font-size : 20px;
text-align : center;
border-bottom : 2px solid;
}
ul {
padding-inline : 30px 10px;
li {
margin-block : 5px;
line-height : calc(1em + 5px);
list-style : disc;
}
}
}
&::after {
position : absolute;
top : 0;
right : 0;
left : 0;
display : block;
padding : 10px;
font-weight : 900;
color : white;
white-space : pre-wrap;
content : 'Error:\A At least one renderer should be enabled to make a search';
background : rgb(255, 60, 60);
opacity : 0;
transition : opacity 0.5s;
}
&:not(:has(input[type='checkbox']:checked))::after { opacity : 1; }
.formTitle {
margin : 20px 0;
font-size : 30px;
color : black;
legend {
h3 {
margin-block : 30px 20px;
font-size : 20px;
text-align : center;
border-bottom : 2px solid;
}
.formContents {
position : relative;
display : flex;
flex-direction : column;
label {
display : flex;
align-items : center;
margin : 10px 0;
ul {
padding-inline : 30px 10px;
li {
margin-block : 5px;
line-height : calc(1em + 5px);
list-style : disc;
}
select { margin : 0 10px; }
}
}
input {
margin : 0 10px;
&::after {
position : absolute;
top : 0;
right : 0;
left : 0;
display : block;
padding : 10px;
font-weight : 900;
color : white;
white-space : pre-wrap;
content : 'Error:\A At least one renderer should be enabled to make a search';
background : rgb(255, 60, 60);
opacity : 0;
transition : opacity 0.5s;
}
&:not(:has(input[type='checkbox']:checked))::after { opacity : 1; }
&:invalid { background : rgb(255, 188, 181); }
.formTitle {
margin : 20px 0;
font-size : 30px;
color : black;
text-align : center;
border-bottom : 2px solid;
}
.formContents {
position : relative;
display : flex;
flex-direction : column;
label {
display : flex;
align-items : center;
margin : 10px 0;
}
select { margin : 0 10px; }
input {
margin : 0 10px;
&:invalid { background : rgb(255, 188, 181); }
&[type='checkbox'] {
position : relative;
display : inline-block;
width : 50px;
height : 30px;
font-family : 'WalterTurncoat';
font-size : 20px;
font-weight : 800;
color : white;
letter-spacing : 2px;
appearance : none;
background : red;
isolation : isolate;
border-radius : 5px;
}
&::before,&::after {
position : absolute;
inset : 0;
z-index : 5;
padding-top : 2px;
text-align : center;
}
#searchButton {
.colorButton(@green);
position : absolute;
right : 20px;
bottom : 0;
&::before {
display : block;
content : 'No';
}
i {
margin-left : 10px;
animation-duration : 1000s;
}
}
}
}
&::after {
display : none;
content : 'Yes';
}
&.resultsContainer {
display : flex;
flex-direction : column;
height : 100%;
overflow-y : auto;
font-size : 0.34cm;
h3 {
font-family : 'Open Sans';
font-weight : 900;
color : white;
}
&:checked {
background : green;
&::before { display : none; }
&::after { display : block; }
}
.sort-container {
display : flex;
flex-wrap : wrap;
column-gap : 15px;
justify-content : center;
height : 30px;
color : white;
background-color : #555555;
border-top : 1px solid #666666;
border-bottom : 1px solid #666666;
.sort-option {
display : flex;
align-items : center;
padding : 0 8px;
&:hover { background-color : #444444; }
&.active {
background-color : #333333;
button {
font-weight : 800;
color : white;
& + .sortDir { padding-left : 5px; }
}
}
#searchButton {
position : absolute;
right : 20px;
bottom : 0;
i {
margin-left : 10px;
animation-duration : 1000s;
}
button {
padding : 0;
font-size : 11px;
font-weight : normal;
color : #CCCCCC;
text-transform : uppercase;
background-color : transparent;
&:hover { background : none; }
}
}
}
&.resultsContainer {
display : flex;
flex-direction : column;
height : 100%;
overflow-y : auto;
font-family : 'BookInsanityRemake';
font-size : 0.34cm;
h3 {
font-family : 'Open Sans';
font-weight : 900;
.foundBrews {
position : relative;
width : 100%;
height : 100%;
max-height : 100%;
padding : 70px 50px;
overflow-y : scroll;
background-color : #2C3E50;
container-type : inline-size;
h3 { font-size : 25px; }
&.noBrews {
display : grid;
place-items : center;
color : white;
}
.sort-container {
display : flex;
flex-wrap : wrap;
column-gap : 15px;
justify-content : center;
height : 30px;
color : white;
background-color : #555555;
border-top : 1px solid #666666;
border-bottom : 1px solid #666666;
.sort-option {
display : flex;
align-items : center;
padding : 0 8px;
&:hover { background-color : #444444; }
&.active {
background-color : #333333;
button {
font-weight : 800;
color : white;
& + .sortDir { padding-left : 5px; }
}
}
&.searching {
display : grid;
place-items : center;
color : white;
button {
padding : 0;
font-size : 11px;
font-weight : normal;
color : #CCCCCC;
text-transform : uppercase;
background-color : transparent;
&:hover { background : none; }
}
h3 { position : relative; }
h3.searchAnim::after {
position : absolute;
top : 50%;
right : 0;
width : max-content;
height : 1em;
content : '';
translate : calc(100% + 5px) -50%;
animation : trailingDots 2s ease infinite;
}
}
.foundBrews {
position : relative;
width : 100%;
height : 100%;
max-height : 100%;
padding : 50px 50px 70px 50px;
overflow-y : scroll;
background-color : #2C3E50;
.totalBrews {
position : fixed;
right : 0;
bottom : 0;
z-index : 1000;
padding : 8px 10px;
font-family : 'Open Sans';
font-size : 11px;
font-weight : 800;
color : white;
background-color : #333333;
h3 { font-size : 25px; }
&.noBrews {
display : grid;
place-items : center;
color : white;
.searchAnim {
position : relative;
display : inline-block;
width : 3ch;
height : 1em;
}
&.searching {
display : grid;
place-items : center;
color : white;
h3 { position : relative; }
h3.searchAnim::after {
position : absolute;
top : 50%;
right : 0;
width : max-content;
height : 1em;
content : '';
translate : calc(100% + 5px) -50%;
animation : trailingDots 2s ease infinite;
}
.searchAnim::after {
position : absolute;
top : 50%;
right : 0;
width : max-content;
height : 1em;
content : '';
translate : -50% -50%;
animation : trailingDots 2s ease infinite;
}
}
.totalBrews {
position : fixed;
right : 0;
bottom : 0;
z-index : 1000;
padding : 8px 10px;
font-family : 'Open Sans';
font-size : 11px;
font-weight : 800;
color : white;
background-color : #333333;
.searchAnim {
position : relative;
display : inline-block;
width : 3ch;
height : 1em;
}
.searchAnim::after {
position : absolute;
top : 50%;
right : 0;
width : max-content;
height : 1em;
content : '';
translate : -50% -50%;
animation : trailingDots 2s ease infinite;
}
}
.brewItem {
width : 47%;
margin-right : 40px;
color : black;
isolation : isolate;
.brewItem {
width : 47%;
margin-right : 40px;
color : black;
isolation : isolate;
transition : width 0.5s;
&::after {
position : absolute;
inset : 0;
z-index : -2;
display : block;
content : '';
background-image : url('/assets/parchmentBackground.jpg');
}
&:nth-child(even of .brewItem) { margin-right : 0; }
h2 {
font-family : 'MrEavesRemake';
font-size : 0.75cm;
font-weight : 800;
line-height : 0.988em;
color : var(--HB_Color_HeaderText);
}
.info {
position : relative;
z-index : 2;
font-family : 'ScalySansRemake';
font-size : 1.2em;
>span {
margin-right : 12px;
line-height : 1.5em;
}
}
.links { z-index : 2; }
hr {
margin : 0px;
visibility : hidden;
}
.thumbnail { z-index : -1; }
&::after {
position : absolute;
inset : 0;
z-index : -2;
display : block;
content : '';
background-image : url('/assets/parchmentBackground.jpg');
}
.paginationControls {
position : absolute;
left : 50%;
display : grid;
grid-template-areas : 'previousPage currentPage nextPage';
grid-template-columns : 50px 1fr 50px;
place-items : center;
width : auto;
translate : -50%;
.pages {
display : flex;
grid-area : currentPage;
justify-content : space-evenly;
width : 100%;
height : 100%;
padding : 5px 8px;
text-align : center;
.pageNumber {
margin-inline : 1vw;
font-family : 'Open Sans';
font-weight : 900;
color : white;
text-underline-position : under;
text-wrap : nowrap;
cursor : pointer;
&.currentPage {
color : gold;
text-decoration : underline;
pointer-events : none;
}
&.firstPage { margin-right : -5px; }
&.lastPage { margin-left : -5px; }
}
}
button {
width : max-content;
&.previousPage { grid-area : previousPage; }
&.nextPage { grid-area : nextPage; }
}
&:nth-child(even of .brewItem) { margin-right : 0; }
h2 {
font-family : 'MrEavesRemake';
font-size : 0.75cm;
font-weight : 800;
line-height : 0.988em;
color : var(--HB_Color_HeaderText);
}
.info {
position : relative;
z-index : 2;
font-family : 'ScalySansRemake';
font-size : 1.2em;
>span {
margin-right : 12px;
line-height : 1.5em;
}
}
.links { z-index : 2; }
hr {
visibility : hidden;
margin : 0px;
}
.thumbnail { z-index : -1; }
}
.paginationControls {
position : absolute;
top : 35px;
left : 50%;
display : grid;
grid-template-areas : 'previousPage currentPage nextPage';
grid-template-columns : 50px 1fr 50px;
gap : 20px;
place-items : center;
width : auto;
font-size : 15px;
translate : -50%;
&:last-child { top : unset; }
.pages {
display : flex;
grid-area : currentPage;
gap : 1em;
justify-content : space-evenly;
width : 100%;
height : 100%;
text-align : center;
.pageNumber {
place-content : center;
width : fit-content;
min-width : 2em;
font-family : 'Open Sans';
font-weight : 900;
color : white;
text-wrap : nowrap;
text-underline-position : under;
cursor : pointer;
&.currentPage {
color : gold;
text-decoration : underline;
pointer-events : none;
}
&.firstPage { margin-right : -5px; }
&.lastPage { margin-left : -5px; }
}
}
button {
.colorButton(@green);
width : max-content;
&.previousPage { grid-area : previousPage; }
&.nextPage { grid-area : nextPage; }
}
}
}
}
@@ -386,9 +352,8 @@
100% { content : ' ...'; }
}
// media query for when the page is smaller than 1079 px in width
@media screen and (max-width : 1079px) {
.vaultPage .content {
@container (width < 670px) {
.vaultPage {
.dataGroup.form .brewLookup { padding : 1px 20px 20px 10px; }

View File

@@ -0,0 +1,19 @@
import * as IDB from 'idb-keyval/dist/index.js';
export function initCustomStore(db, store){
const createCustomStore = async ()=>IDB.createStore(db, store);
return {
entries : async ()=>IDB.entries(await createCustomStore()),
keys : async ()=>IDB.keys(await createCustomStore()),
values : async ()=>IDB.values(await createCustomStore()),
clear : async ()=>IDB.clear(await createCustomStore),
get : async (key)=>IDB.get(key, await createCustomStore()),
getMany : async (keys)=>IDB.getMany(keys, await createCustomStore()),
set : async (key, value)=>IDB.set(key, value, await createCustomStore()),
setMany : async (entries)=>IDB.setMany(entries, await createCustomStore()),
update : async (key, updateFn)=>IDB.update(key, updateFn, await createCustomStore()),
del : async (key)=>IDB.del(key, await createCustomStore()),
delMany : async (keys)=>IDB.delMany(keys, await createCustomStore())
};
};

View File

@@ -1,4 +1,4 @@
const request = require('superagent');
import request from 'superagent';
const addHeader = (request)=>request.set('Homebrewery-Version', global.version);
@@ -9,4 +9,4 @@ const requestMiddleware = {
delete : (path)=>addHeader(request.delete(path)),
};
module.exports = requestMiddleware;
export default requestMiddleware;

View File

@@ -1,4 +1,4 @@
import * as IDB from 'idb-keyval/dist/index.js';
import { initCustomStore } from './customIDBStore.js';
export const HISTORY_PREFIX = 'HOMEBREWERY-HISTORY';
export const HISTORY_SLOTS = 5;
@@ -21,13 +21,15 @@ const HISTORY_SAVE_DELAYS = {
// '5' : 5
// };
const HB_DB = 'HOMEBREWERY-DB';
const HB_STORE = 'HISTORY';
const GARBAGE_COLLECT_DELAY = 28 * 24 * 60;
// const GARBAGE_COLLECT_DELAY = 10;
const HB_DB = 'HOMEBREWERY-DB';
const HB_STORE = 'HISTORY';
const IDB = initCustomStore(HB_DB, HB_STORE);
function getKeyBySlot(brew, slot){
// Return a string representing the key for this brew and history slot
return `${HISTORY_PREFIX}-${brew.shareId}-${slot}`;
@@ -53,11 +55,6 @@ function parseBrewForStorage(brew, slot = 0) {
return [key, archiveBrew];
}
// Create a custom IDB store
async function createHBStore(){
return await IDB.createStore(HB_DB, HB_STORE);
}
export async function loadHistory(brew){
const DEFAULT_HISTORY_ITEM = { expireAt: '2000-01-01T00:00:00.000Z', shareId: brew.shareId, noData: true };
@@ -69,7 +66,7 @@ export async function loadHistory(brew){
};
// Load all keys from IDB at once
const dataArray = await IDB.getMany(historyKeys, await createHBStore());
const dataArray = await IDB.getMany(historyKeys);
return dataArray.map((data)=>{ return data ?? DEFAULT_HISTORY_ITEM; });
}
@@ -97,7 +94,7 @@ export async function updateHistory(brew) {
// Update the most recent brew
historyUpdate.push(parseBrewForStorage(brew, 1));
await IDB.setMany(historyUpdate, await createHBStore());
await IDB.setMany(historyUpdate);
// Break out of data checks because we found an expired value
break;
@@ -106,14 +103,17 @@ export async function updateHistory(brew) {
};
export async function versionHistoryGarbageCollection(){
const entries = await IDB.entries();
const entries = await IDB.entries(await createHBStore());
const expiredKeys = [];
for (const [key, value] of entries){
const expireAt = new Date(value.savedAt);
expireAt.setMinutes(expireAt.getMinutes() + GARBAGE_COLLECT_DELAY);
if(new Date() > expireAt){
await IDB.del(key, await createHBStore());
expiredKeys.push(key);
};
};
if(expiredKeys.length > 0){
await IDB.delMany(expiredKeys);
}
};

View File

@@ -73,3 +73,12 @@
.fit-width {
mask-image: url('../icons/fit-width.svg');
}
.single-spread {
mask-image: url('../icons/single-spread.svg');
}
.facing-spread {
mask-image: url('../icons/facing-spread.svg');
}
.flow-spread {
mask-image: url('../icons/flow-spread.svg');
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(0.979101,0,0,0.919064,-29.0748,1.98095)">
<path d="M78.584,16.13C78.584,15.335 78.164,14.69 77.647,14.69L30.632,14.69C30.115,14.69 29.695,15.335 29.695,16.13L29.695,88.365C29.695,89.16 30.115,89.805 30.632,89.805L77.647,89.805C78.164,89.805 78.584,89.16 78.584,88.365L78.584,16.13Z"/>
</g>
<g transform="matrix(0.979101,0,0,0.919064,23.058,1.98095)">
<path d="M78.584,16.13C78.584,15.335 78.164,14.69 77.647,14.69L30.632,14.69C30.115,14.69 29.695,15.335 29.695,16.13L29.695,88.365C29.695,89.16 30.115,89.805 30.632,89.805L77.647,89.805C78.164,89.805 78.584,89.16 78.584,88.365L78.584,16.13Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1.0781,0,0,1.0781,-3.90545,-3.90502)">
<g transform="matrix(0.590052,0,0,0.553871,-13.8993,-2.19227)">
<path d="M78.584,16.13C78.584,15.335 78.164,14.69 77.647,14.69L30.632,14.69C30.115,14.69 29.695,15.335 29.695,16.13L29.695,88.365C29.695,89.16 30.115,89.805 30.632,89.805L77.647,89.805C78.164,89.805 78.584,89.16 78.584,88.365L78.584,16.13Z"/>
</g>
<g transform="matrix(0.590052,0,0,0.553871,-13.8993,44.3152)">
<path d="M78.584,16.13C78.584,15.335 78.164,14.69 77.647,14.69L30.632,14.69C30.115,14.69 29.695,15.335 29.695,16.13L29.695,88.365C29.695,89.16 30.115,89.805 30.632,89.805L77.647,89.805C78.164,89.805 78.584,89.16 78.584,88.365L78.584,16.13Z"/>
</g>
<g transform="matrix(0.590052,0,0,0.553871,17.5184,-2.19227)">
<path d="M78.584,16.13C78.584,15.335 78.164,14.69 77.647,14.69L30.632,14.69C30.115,14.69 29.695,15.335 29.695,16.13L29.695,88.365C29.695,89.16 30.115,89.805 30.632,89.805L77.647,89.805C78.164,89.805 78.584,89.16 78.584,88.365L78.584,16.13Z"/>
</g>
<g transform="matrix(0.590052,0,0,0.553871,50.0095,-2.19227)">
<path d="M78.584,16.13C78.584,15.335 78.164,14.69 77.647,14.69L30.632,14.69C30.115,14.69 29.695,15.335 29.695,16.13L29.695,88.365C29.695,89.16 30.115,89.805 30.632,89.805L77.647,89.805C78.164,89.805 78.584,89.16 78.584,88.365L78.584,16.13Z"/>
</g>
<g transform="matrix(0.590052,0,0,0.553871,17.5184,44.3152)">
<path d="M78.584,16.13C78.584,15.335 78.164,14.69 77.647,14.69L30.632,14.69C30.115,14.69 29.695,15.335 29.695,16.13L29.695,88.365C29.695,89.16 30.115,89.805 30.632,89.805L77.647,89.805C78.164,89.805 78.584,89.16 78.584,88.365L78.584,16.13Z"/>
</g>
<g transform="matrix(0.590052,0,0,0.553871,50.0095,44.3152)">
<path d="M78.584,16.13C78.584,15.335 78.164,14.69 77.647,14.69L30.632,14.69C30.115,14.69 29.695,15.335 29.695,16.13L29.695,88.365C29.695,89.16 30.115,89.805 30.632,89.805L77.647,89.805C78.164,89.805 78.584,89.16 78.584,88.365L78.584,16.13Z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1.41826,0,0,1.3313,-26.7845,-19.5573)">
<path d="M78.584,16.13C78.584,15.335 78.164,14.69 77.647,14.69L30.632,14.69C30.115,14.69 29.695,15.335 29.695,16.13L29.695,88.365C29.695,89.16 30.115,89.805 30.632,89.805L77.647,89.805C78.164,89.805 78.584,89.16 78.584,88.365L78.584,16.13Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 777 B

View File

@@ -8,6 +8,8 @@ const template = async function(name, title='', props = {}){
});
const ogMetaTags = ogTags.join('\n');
const ssrModule = await import(`../build/${name}/ssr.cjs`);
return `<!DOCTYPE html>
<html>
<head>
@@ -21,7 +23,7 @@ const template = async function(name, title='', props = {}){
<title>${title.length ? `${title} - The Homebrewery`: 'The Homebrewery - NaturalCrit'}</title>
</head>
<body>
<main id="reactRoot">${require(`../build/${name}/ssr.js`)(props)}</main>
<main id="reactRoot">${ssrModule.default(props)}</main>
<script src=${`/${name}/bundle.js`}></script>
<script>start_app(${JSON.stringify(props)})</script>
</body>
@@ -29,4 +31,4 @@ const template = async function(name, title='', props = {}){
`;
};
module.exports = template;
export default template;

View File

@@ -1,4 +1,3 @@
version: '2'
services:
mongodb:
image: mongo:latest

19
faq.md
View File

@@ -69,7 +69,6 @@ pre {
You can check the site status here: [Everyone or Just Me](https://downforeveryoneorjustme.com/homebrewery.naturalcrit.com)
### Why am I getting an error when trying to save, and my account is linked to Google?
A sign-in with Google only lasts a year until the authentication expires. You must go [here](https://www.naturalcrit.com/login), click the *Log-out* button, and then sign back in using your Google account.
@@ -82,12 +81,17 @@ If you have linked your account with a Google account, you would change your pas
### Is there a way to restore a previous version of my brew?
Currently, there is no way to do this through the site yourself. This would take too much of a toll on the amount of storage the homebrewery requires. However, we do have daily backups of our database that we keep for 8 days, and you can contact the moderators on [the subreddit](https://www.reddit.com/r/homebrewery) with your Homebrewery username, the name of the lost brew, and the last known time it was working properly. We can manually look through our backups and restore it if it exists.
In your brew, there is an icon, :fas_clock_rotate_left:, that button opens up a menu with versions of your brew, stored in order from newer to older, up to a week old. Because of the amount of duplicates this function creates, this information is stored in **your browser**, so if you were to uninstall it or clear your cookies and site data, or change computers, the info will not be there.
Also, we do have daily backups of our database that we keep for 8 days, and you can contact the moderators on [the subreddit](https://www.reddit.com/r/homebrewery) with your Homebrewery username, the name of the lost brew, and the last known time it was working properly. We can manually look through our backups and restore it if it exists.
### I worked on a brew for X hours, and suddenly all the text disappeared!
This usually happens if you accidentally drag-select all of your text and then start typing which overwrites the selection. Do not panic, and do not refresh the page or reload your brew quite yet as it is probably auto-saved in this state already. Simply press CTRL+Z as many times as needed to undo your last few changes and you will be back to where you were, then make sure to save your brew in the "good" state.
You can also load a history version old enough to have all the text, using the :fas_clock_rotate_left: history versions button.
\column
### Why is only Chrome supported?
@@ -112,10 +116,7 @@ Once you have an image you would like to use, it is recommended to host it somew
\page
### A particular font does not work for my language, what do I do?
The fonts used were originally created for use with the English language, though revisions since then have added more support for other languages. They are still not complete sets and may be missing a glyph/character you need. Unfortunately, the volunteer group as it stands at the time of this writing does not have a font guru, so it would be difficult to add more glyphs (especially complicated glyphs). Let us know which glyph is missing on the subreddit, but you may need to search [Google Fonts](https://fonts.google.com) for an alternative font if you need something fast.
### Whenever I click on the "Get PDF" button, instead of getting a download, it opens Print Preview in another tab.
Yes, this is by design. In the print preview, select "Save as PDF" as the Destination, and then click "Save". There will be a normal download dialog where you can save your brew as a PDF.
The fonts used were originally created for use with the English language, though revisions since then have added more support for other languages. They are still not complete sets and may be missing a glyph/character you need. Unfortunately, the volunteer group as it stands at the time of this writing does not have a font guru, so it would be difficult to add more glyphs (especially complicated glyphs). Let us know which glyph is missing on the subreddit, but you may need to search [Google Fonts](https://fonts.google.com) for an alternative font if you need something fast.
### I have white borders on the bottom/sides of the print preview.
@@ -126,4 +127,8 @@ The Homebrewery defaults to creating US Letter page sizes. If you are printing
### Typing `#### Adhesion` in the text editor doesn't show the header at all in the completed page?
Your ad-blocking software is mistakenly assuming your text to be an ad. Whitelist homebrewery.naturalcrit.com in your ad-blocking software.
Your ad-blocking software is mistakenly assuming your text to be an ad. We recommend whitelisting homebrewery.naturalcrit.com in your ad-blocking software, as we have no ads.
### My username appears as _hidden_ when checking my brews in the Vault, why is that?
Your username is most likely your e-mail adress, and our code is picking that up and protecting your identity. This will remain as is, but you can ask for a name change by contacting the moderators on [the subreddit](https://www.reddit.com/r/homebrewery) with your Homebrewery username, and your desired new name. You will also be asked to provide details about some of your unpublished brews, to verify your identity. No information will be leaked or shared.

View File

@@ -24,12 +24,16 @@ These instructions assume that you are installing to a completely new, fresh Ubu
These installation instructions have been tested on the following Ubuntu releases:
- *ubuntu-20.04.3-desktop-amd64*
- *ubuntu-24.04.1-desktop-amd64*
- *ubuntu-22.04.5-desktop-amd64*
- *ubuntu-20.04.6-desktop-amd64*
## Final Notes
While this installation process works successfully at the time of writing (December 19, 2021), 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.
Earlier versions of Ubuntu may requier an alternate Mongo setup, see https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-ubuntu/ for assistance.
Regards,
G
December 19, 2021

View File

@@ -3,7 +3,8 @@ Description=Homebrewery Web Server
[Service]
User=root
After=mongodb
BindsTo=mongod.service
After=mongod.service
Environment=NODE_ENV=local
WorkingDirectory=/usr/local/homebrewery
ExecStart=node server.js

View File

@@ -1,14 +1,60 @@
#!/bin/sh
# Detect Ubuntu Version
export DISTRO=$(grep "^NAME=" /etc/os-release | awk -F '=' '{print $2}' | sed 's/"//g')
export DISTRO_VER=$(grep "VERSION_ID=" /etc/os-release | awk -F '=' '{print $2}' | sed 's/"//g')
export MATCHED="Yes"
if [ "${DISTRO}" != "Ubuntu" ];
then
echo :: Ubuntu not detected. Are you using an alternate spin or derivative?
echo :: Detected - ${DISTRO}
read -p [y/N] YESNO
if [ "${YESNO}" != "Y" ] && [ ]"${YESNO}" != "y" ]; then
exit
fi
MATCHED="No"
fi
# Install CURL and add required NodeJS source to package repo
echo ::Install CURL
apt install -y curl
echo ::Add NodeJS source to package repo
curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
# Add Mongo CE Source
if [ ${DISTRO} = "Ubuntu" ];
then
echo ::Add Mongo CE source to package repo
curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc | \
sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg \
--dearmor
if [ "${DISTRO_VER}" == "24.04" ]; then
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list
elif [ "${DISTRO_VER}" == "22.04" ]; then
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list
elif [ "${DISTRO_VER}" == "20.04" ]; then
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list
else
MATCHED="No"
fi
sudo apt-get update
fi
if [ ${MATCHED} == "No" ]; then
echo :: WARNING
echo :: Unable to determine Ubuntu version for Mongo installation purposes.
echo :: Please check your spin/distro documentation to install Mongo CE and enable it on startup.
fi
# Install required packages
echo ::Install Homebrewery requirements
apt satisfy -y git nodejs npm mongodb
apt satisfy -y git nodejs npm mongodb-org
# Enable and start Mongo
systemctl enable mongod
systemctl start mongod
# Clone Homebrewery repo
echo ::Get Homebrewery files

4570
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,11 @@
{
"name": "homebrewery",
"description": "Create authentic looking D&D homebrews using only markdown",
"version": "3.15.0",
"version": "3.18.1",
"type": "module",
"engines": {
"npm": "^10.2.x",
"node": "^20.17.x"
"node": "^20.18.x"
},
"repository": {
"type": "git",
@@ -26,6 +27,7 @@
"test:api-unit:themes": "jest \"server/.*.spec.js\" -t \"theme bundle\" --verbose",
"test:api-unit:css": "jest \"server/.*.spec.js\" -t \"Get CSS\" --verbose",
"test:api-unit:notifications": "jest \"server/.*.spec.js\" -t \"Notifications\" --verbose",
"test:content-negotiation": "jest \"server/middleware/.*.spec.js\" --verbose",
"test:coverage": "jest --coverage --silent --runInBand",
"test:dev": "jest --verbose --watch",
"test:basic": "jest tests/markdown/basic.test.js --verbose",
@@ -36,8 +38,10 @@
"test:mustache-syntax:injection": "jest \".*(mustache-syntax).*\" -t '^Injection:.*' --verbose --noStackTrace",
"test:definition-lists": "jest tests/markdown/definition-lists.test.js --verbose --noStackTrace",
"test:hard-breaks": "jest tests/markdown/hard-breaks.test.js --verbose --noStackTrace",
"test:non-breaking-spaces": "jest tests/markdown/non-breaking-spaces.test.js --verbose --noStackTrace",
"test:emojis": "jest tests/markdown/emojis.test.js --verbose --noStackTrace",
"test:route": "jest tests/routes/static-pages.test.js --verbose",
"test:safehtml": "jest tests/html/safeHTML.test.js --verbose",
"phb": "node --experimental-require-module scripts/phb.js",
"prod": "set NODE_ENV=production && npm run build",
"postinstall": "npm run build",
@@ -55,6 +59,9 @@
"shared",
"server"
],
"transformIgnorePatterns": [
"node_modules/(?!nanoid/).*"
],
"coveragePathIgnorePatterns": [
"build/*"
],
@@ -76,68 +83,63 @@
"jest-expect-message"
]
},
"babel": {
"presets": [
"@babel/preset-env",
"@babel/preset-react"
],
"plugins": [
"@babel/plugin-transform-runtime"
]
},
"dependencies": {
"@babel/core": "^7.25.8",
"@babel/plugin-transform-runtime": "^7.25.7",
"@babel/preset-env": "^7.25.8",
"@babel/preset-react": "^7.25.7",
"@googleapis/drive": "^8.14.0",
"@babel/core": "^7.26.9",
"@babel/plugin-transform-runtime": "^7.26.9",
"@babel/preset-env": "^7.26.9",
"@babel/preset-react": "^7.26.3",
"@googleapis/drive": "^8.16.0",
"body-parser": "^1.20.2",
"classnames": "^2.5.1",
"codemirror": "^5.65.6",
"cookie-parser": "^1.4.7",
"core-js": "^3.41.0",
"cors": "^2.8.5",
"create-react-class": "^15.7.0",
"dedent-tabs": "^0.10.3",
"dompurify": "^3.1.7",
"expr-eval": "^2.0.2",
"express": "^4.21.1",
"express": "^4.21.2",
"express-async-handler": "^1.2.0",
"express-static-gzip": "2.1.8",
"fs-extra": "11.2.0",
"express-static-gzip": "2.2.0",
"fs-extra": "11.3.0",
"idb-keyval": "^6.2.1",
"js-yaml": "^4.1.0",
"jwt-simple": "^0.5.6",
"less": "^3.13.1",
"lodash": "^4.17.21",
"marked": "11.2.0",
"marked-emoji": "^1.4.2",
"marked-extended-tables": "^1.0.10",
"marked-gfm-heading-id": "^3.2.0",
"marked-smartypants-lite": "^1.0.2",
"marked": "14.0.0",
"marked-emoji": "^2.0.0",
"marked-extended-tables": "^2.0.1",
"marked-gfm-heading-id": "^4.0.1",
"marked-smartypants-lite": "^1.0.3",
"marked-subsuper-text": "^1.0.3",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.30.1",
"mongoose": "^8.7.1",
"nanoid": "3.3.4",
"mongoose": "^8.12.1",
"nanoid": "5.1.3",
"nconf": "^0.12.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-frame-component": "^4.1.3",
"react-router-dom": "6.26.2",
"react-router": "^7.3.0",
"sanitize-filename": "1.6.3",
"superagent": "^10.1.0",
"superagent": "^10.1.1",
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
},
"devDependencies": {
"@stylistic/stylelint-plugin": "^3.1.1",
"eslint": "^9.12.0",
"eslint-plugin-jest": "^28.8.3",
"eslint-plugin-react": "^7.37.1",
"globals": "^15.11.0",
"@stylistic/stylelint-plugin": "^3.1.2",
"babel-plugin-transform-import-meta": "^2.3.2",
"eslint": "^9.22.0",
"eslint-plugin-jest": "^28.11.0",
"eslint-plugin-react": "^7.37.4",
"globals": "^16.0.0",
"jest": "^29.7.0",
"jest-expect-message": "^1.1.3",
"jsdom-global": "^3.0.2",
"postcss-less": "^6.0.0",
"stylelint": "^16.9.0",
"stylelint-config-recess-order": "^5.1.1",
"stylelint-config-recommended": "^14.0.1",
"stylelint": "^16.15.0",
"stylelint-config-recess-order": "^6.0.0",
"stylelint-config-recommended": "^15.0.0",
"supertest": "^7.0.0"
}
}

View File

@@ -1,13 +1,14 @@
const fs = require('fs-extra');
const Proj = require('./project.json');
const { pack } = require('vitreum');
import fs from 'fs-extra';
import Proj from './project.json' with { type: 'json' };
import vitreum from 'vitreum';
const { pack } = vitreum;
import lessTransform from 'vitreum/transforms/less.js';
import assetTransform from 'vitreum/transforms/asset.js';
const isDev = !!process.argv.find((arg)=>arg=='--dev');
const lessTransform = require('vitreum/transforms/less.js');
const assetTransform = require('vitreum/transforms/asset.js');
//const Meta = require('vitreum/headtags');
const transforms = {
'.less' : lessTransform,
'*' : assetTransform('./build')
@@ -17,7 +18,7 @@ const build = async ({ bundle, render, ssr })=>{
const css = await lessTransform.generate({ paths: './shared' });
await fs.outputFile('./build/admin/bundle.css', css);
await fs.outputFile('./build/admin/bundle.js', bundle);
await fs.outputFile('./build/admin/ssr.js', ssr);
await fs.outputFile('./build/admin/ssr.cjs', ssr);
};
fs.emptyDirSync('./build/admin');

View File

@@ -1,16 +1,18 @@
const fs = require('fs-extra');
const zlib = require('zlib');
const Proj = require('./project.json');
import fs from 'fs-extra';
import zlib from 'zlib';
import Proj from './project.json' with { type: 'json' };
import vitreum from 'vitreum';
const { pack, watchFile, livereload } = vitreum;
const { pack, watchFile, livereload } = require('vitreum');
const isDev = !!process.argv.find((arg)=>arg=='--dev');
import lessTransform from 'vitreum/transforms/less.js';
import assetTransform from 'vitreum/transforms/asset.js';
import babel from '@babel/core';
import babelConfig from '../babel.config.json' with { type : 'json' };
import less from 'less';
const lessTransform = require('vitreum/transforms/less.js');
const assetTransform = require('vitreum/transforms/asset.js');
const babel = require('@babel/core');
const less = require('less');
const isDev = !!process.argv.find((arg) => arg === '--dev');
const babelify = async (code)=>(await babel.transformAsync(code, { presets: [['@babel/preset-env', { 'exclude': ['proposal-dynamic-import'] }], '@babel/preset-react'], plugins: ['@babel/plugin-transform-runtime'] })).code;
const babelify = async (code)=>(await babel.transformAsync(code, babelConfig)).code;
const transforms = {
'.js' : (code, filename, opts)=>babelify(code),
@@ -24,7 +26,7 @@ const build = async ({ bundle, render, ssr })=>{
//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);
await fs.outputFile('./build/homebrew/ssr.cjs', ssr);
await fs.copy('./client/homebrew/favicon.ico', './build/assets/favicon.ico');
@@ -51,7 +53,7 @@ fs.emptyDirSync('./build');
const themes = { Legacy: {}, V3: {} };
let themeFiles = fs.readdirSync('./themes/Legacy');
for (dir of themeFiles) {
for (let dir of themeFiles) {
const themeData = JSON.parse(fs.readFileSync(`./themes/Legacy/${dir}/settings.json`).toString());
themeData.path = dir;
themes.Legacy[dir] = (themeData);
@@ -68,7 +70,7 @@ fs.emptyDirSync('./build');
}
themeFiles = fs.readdirSync('./themes/V3');
for (dir of themeFiles) {
for (let dir of themeFiles) {
const themeData = JSON.parse(fs.readFileSync(`./themes/V3/${dir}/settings.json`).toString());
themeData.path = dir;
themes.V3[dir] = (themeData);
@@ -104,14 +106,14 @@ fs.emptyDirSync('./build');
const editorThemesBuildDir = './build/homebrew/cm-themes';
await fs.copy('./node_modules/codemirror/theme', editorThemesBuildDir);
await fs.copy('./themes/codeMirror/customThemes', editorThemesBuildDir);
editorThemeFiles = fs.readdirSync(editorThemesBuildDir);
const editorThemeFiles = fs.readdirSync(editorThemesBuildDir);
const editorThemeFile = './themes/codeMirror/editorThemes.json';
if(fs.existsSync(editorThemeFile)) fs.rmSync(editorThemeFile);
const stream = fs.createWriteStream(editorThemeFile, { flags: 'a' });
stream.write('[\n"default"');
for (themeFile of editorThemeFiles) {
for (let themeFile of editorThemeFiles) {
stream.write(`,\n"${themeFile.slice(0, -4)}"`);
}
stream.write('\n]\n');

View File

@@ -1,12 +1,12 @@
const DB = require('./server/db.js');
const server = require('./server/app.js');
const config = require('./server/config.js');
import DB from './server/db.js';
import server from './server/app.js';
import config from './server/config.js';
DB.connect(config).then(()=>{
// Ensure that we have successfully connected to the database
// before launching server
const PORT = process.env.PORT || config.get('web_port') || 8000;
server.app.listen(PORT, ()=>{
server.listen(PORT, ()=>{
const reset = '\x1b[0m'; // Reset to default style
const bright = '\x1b[1m'; // Bright (bold) style
const cyan = '\x1b[36m'; // Cyan color

View File

@@ -1,9 +1,15 @@
const HomebrewModel = require('./homebrew.model.js').model;
const NotificationModel = require('./notifications.model.js').model;
const router = require('express').Router();
const Moment = require('moment');
const templateFn = require('../client/template.js');
const zlib = require('zlib');
import { model as HomebrewModel } from './homebrew.model.js';
import { model as NotificationModel } from './notifications.model.js';
import express from 'express';
import Moment from 'moment';
import zlib from 'zlib';
import templateFn from '../client/template.js';
import HomebrewAPI from './homebrew.api.js';
import asyncHandler from 'express-async-handler';
import { splitTextStyleAndMetadata } from '../shared/helpers.js';
const router = express.Router();
process.env.ADMIN_USER = process.env.ADMIN_USER || 'admin';
process.env.ADMIN_PASS = process.env.ADMIN_PASS || 'password3';
@@ -66,23 +72,8 @@ router.post('/admin/cleanup', mw.adminOnly, (req, res)=>{
});
/* Searches for matching edit or share id, also attempts to partial match */
router.get('/admin/lookup/:id', mw.adminOnly, async (req, res, next)=>{
HomebrewModel.findOne({
$or : [
{ editId: { $regex: req.params.id, $options: 'i' } },
{ shareId: { $regex: req.params.id, $options: 'i' } },
]
}).exec()
.then((brew)=>{
if(!brew) // No document found
return res.status(404).json({ error: 'Document not found' });
else
return res.json(brew);
})
.catch((err)=>{
console.error(err);
return res.status(500).json({ error: 'Internal Server Error' });
});
router.get('/admin/lookup/:id', mw.adminOnly, asyncHandler(HomebrewAPI.getBrew('admin', false)), async (req, res, next)=>{
return res.json(req.brew);
});
/* Find 50 brews that aren't compressed yet */
@@ -100,6 +91,40 @@ router.get('/admin/finduncompressed', mw.adminOnly, (req, res)=>{
});
});
/* Cleans `<script` and `</script>` from the "text" field of a brew */
router.put('/admin/clean/script/:id', asyncHandler(HomebrewAPI.getBrew('admin', false)), async (req, res)=>{
console.log(`[ADMIN: ${req.account?.username || 'Not Logged In'}] Cleaning script tags from ShareID ${req.params.id}`);
function cleanText(text){return text.replaceAll(/(<\/?s)cript/gi, '');};
const brew = req.brew;
const properties = ['text', 'description', 'title'];
properties.forEach((property)=>{
brew[property] = cleanText(brew[property]);
});
splitTextStyleAndMetadata(brew);
req.body = brew;
// Remove Account from request to prevent Admin user from being added to brew as an Author
req.account = undefined;
return await HomebrewAPI.updateBrew(req, res);
});
/* Get list of a user's documents */
router.get('/admin/user/list/:user', mw.adminOnly, async (req, res)=>{
const username = req.params.user;
const fields = { _id: 0, text: 0, textBin: 0 }; // Remove unnecessary fields from document lists
console.log(`[ADMIN: ${req.account?.username || 'Not Logged In'}] Get brew list for ${username}`);
const brews = await HomebrewModel.getByUser(username, true, fields);
return res.json(brews);
});
/* Compresses the "text" field of a brew to binary */
router.put('/admin/compress/:id', (req, res)=>{
@@ -122,7 +147,6 @@ router.put('/admin/compress/:id', (req, res)=>{
});
});
router.get('/admin/stats', mw.adminOnly, async (req, res)=>{
try {
const totalBrewsCount = await HomebrewModel.countDocuments({});
@@ -144,6 +168,7 @@ router.get('/admin/notification/all', async (req, res, next)=>{
try {
const notifications = await NotificationModel.getAll();
return res.json(notifications);
} catch (error) {
console.log('Error getting all notifications: ', error.message);
return res.status(500).json({ message: error.message });
@@ -151,7 +176,6 @@ router.get('/admin/notification/all', async (req, res, next)=>{
});
router.post('/admin/notification/add', mw.adminOnly, async (req, res, next)=>{
console.table(req.body);
try {
const notification = await NotificationModel.addNotification(req.body);
return res.status(201).json(notification);
@@ -182,4 +206,4 @@ router.get('/admin', mw.adminOnly, (req, res)=>{
});
});
module.exports = router;
export default router;

View File

@@ -1,9 +1,10 @@
const supertest = require('supertest');
import supertest from 'supertest';
import HBApp from './app.js';
import {model as NotificationModel } from './notifications.model.js';
const app = supertest.agent(require('app.js').app)
.set('X-Forwarded-Proto', 'https');
const NotificationModel = require('./notifications.model.js').model;
// Mimic https responses to avoid being redirected all the time
const app = supertest.agent(HBApp).set('X-Forwarded-Proto', 'https');
describe('Tests for admin api', ()=>{
afterEach(()=>{

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
const _ = require('lodash');
import _ from 'lodash';
// Default properties for newly-created brews
const DEFAULT_BREW = {
@@ -32,7 +32,7 @@ const DEFAULT_BREW_LOAD = _.defaults(
},
DEFAULT_BREW);
module.exports = {
export {
DEFAULT_BREW,
DEFAULT_BREW_LOAD
};

View File

@@ -1,5 +1,7 @@
module.exports = require('nconf')
.argv()
.env({ lowerCase: true })
.file('environment', { file: `config/${process.env.NODE_ENV}.json` })
.file('defaults', { file: 'config/default.json' });
import nconf from 'nconf';
export default nconf
.argv()
.env({ lowerCase: true })
.file('environment', { file: `config/${process.env.NODE_ENV}.json` })
.file('defaults', { file: 'config/default.json' });

View File

@@ -5,7 +5,7 @@
// reused by both the main application and all tests which require database
// connection.
const Mongoose = require('mongoose');
import Mongoose from 'mongoose';
const getMongoDBURL = (config)=>{
return config.get('mongodb_uri') ||
@@ -31,7 +31,7 @@ const connect = async (config)=>{
.catch((error)=>handleConnectionError(error));
};
module.exports = {
connect : connect,
disconnect : disconnect
export default {
connect,
disconnect
};

View File

@@ -1,4 +1,4 @@
module.exports = (req, res, next)=>{
export default (req, res, next)=>{
if(process.env.NODE_ENV === 'local' || process.env.NODE_ENV === 'docker') return next();
if(req.header('x-forwarded-proto') !== 'https') {
return res.redirect(302, `https://${req.get('Host')}${req.url}`);

View File

@@ -1,8 +1,9 @@
/* eslint-disable max-lines */
const googleDrive = require('@googleapis/drive');
const { nanoid } = require('nanoid');
const token = require('./token.js');
const config = require('./config.js');
import googleDrive from '@googleapis/drive';
import { nanoid } from 'nanoid';
import token from './token.js';
import config from './config.js';
let serviceAuth;
if(!config.get('service_account')){
@@ -59,7 +60,7 @@ const GoogleActions = {
account.googleRefreshToken = tokens.refresh_token;
}
account.googleAccessToken = tokens.access_token;
const JWTToken = token.generateAccessToken(account);
const JWTToken = token(account);
//Save updated token to cookie
//res.cookie('nc_session', JWTToken, { maxAge: 1000*60*60*24*365, path: '/', sameSite: 'lax' });
@@ -72,7 +73,7 @@ const GoogleActions = {
getGoogleFolder : async (auth)=>{
const drive = googleDrive.drive({ version: 'v3', auth });
fileMetadata = {
const fileMetadata = {
'name' : 'Homebrewery',
'mimeType' : 'application/vnd.google-apps.folder'
};
@@ -154,9 +155,8 @@ const GoogleActions = {
return brews;
},
updateGoogleBrew : async (brew, auth = defaultAuth, userIp)=>{
const drive = googleDrive.drive({ version: 'v3', auth: auth });
console.log(auth == defaultAuth ? 'UPDATE w SERVICEACC' : 'UPDATE w USERACC')
updateGoogleBrew : async (brew, userIp)=>{
const drive = googleDrive.drive({ version: 'v3', auth: defaultAuth });
await drive.files.update({
fileId : brew.googleId,
@@ -241,8 +241,8 @@ const GoogleActions = {
return obj.data.id;
},
getGoogleBrew : async (id, accessId, accessType)=>{
const drive = googleDrive.drive({ version: 'v3', auth: defaultAuth });
getGoogleBrew : async (auth = defaultAuth, id, accessId, accessType)=>{
const drive = googleDrive.drive({ version: 'v3', auth: auth });
const obj = await drive.files.get({
fileId : id,
@@ -345,4 +345,4 @@ const GoogleActions = {
}
};
module.exports = GoogleActions;
export default GoogleActions;

View File

@@ -1,18 +1,20 @@
/* eslint-disable max-lines */
const _ = require('lodash');
const HomebrewModel = require('./homebrew.model.js').model;
const router = require('express').Router();
const zlib = require('zlib');
const GoogleActions = require('./googleActions.js');
const Markdown = require('../shared/naturalcrit/markdown.js');
const yaml = require('js-yaml');
const asyncHandler = require('express-async-handler');
const { nanoid } = require('nanoid');
const { splitTextStyleAndMetadata } = require('../shared/helpers.js');
import _ from 'lodash';
import { model as HomebrewModel } from './homebrew.model.js';
import express from 'express';
import zlib from 'zlib';
import GoogleActions from './googleActions.js';
import Markdown from '../shared/naturalcrit/markdown.js';
import yaml from 'js-yaml';
import asyncHandler from 'express-async-handler';
import { nanoid } from 'nanoid';
import { splitTextStyleAndMetadata } from '../shared/helpers.js';
import checkClientVersion from './middleware/check-client-version.js';
const { DEFAULT_BREW, DEFAULT_BREW_LOAD } = require('./brewDefaults.js');
const router = express.Router();
const Themes = require('../themes/themes.json');
import { DEFAULT_BREW, DEFAULT_BREW_LOAD } from './brewDefaults.js';
import Themes from '../themes/themes.json' with { type: 'json' };
const isStaticTheme = (renderer, themeName)=>{
return Themes[renderer]?.[themeName] !== undefined;
@@ -85,66 +87,68 @@ const api = {
// 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);
let { id, googleId } = api.getId(req);
const accessMap = {
edit : { editId: id },
share : { shareId: id },
admin : { $or : [{ editId: id }, { shareId: id }] }
};
// 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 })
let stub = await HomebrewModel.get(accessMap[accessType])
.catch((err)=>{
if(googleId) {
if(googleId)
console.warn(`Unable to find document stub for ${accessType}Id ${id}`);
} else {
else
console.warn(err);
}
});
stub = stub?.toObject();
googleId ??= stub?.googleId;
if(stub?.lock?.locked && accessType != 'edit') {
throw { HBErrorCode: '51', code: stub.lock.code, message: stub.lock.shareMessage, brewId: stub.shareId, brewTitle: stub.title };
const isOwner = (accessType == 'edit' && (!stub || stub?.authors?.length === 0)) || stub?.authors?.[0] === req.account?.username;
const isAuthor = stub?.authors?.includes(req.account?.username);
const isInvited = stub?.invitedAuthors?.includes(req.account?.username);
if(accessType === 'edit' && !(isOwner || isAuthor || isInvited)) {
const accessError = { name: 'Access Error', status: 401, authors: stub?.authors, brewTitle: stub?.title, shareId: stub?.shareId };
if(req.account)
throw { ...accessError, message: 'User is not an Author', HBErrorCode: '03' };
else
throw { ...accessError, message: 'User is not logged in', HBErrorCode: '04' };
}
// 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;
if(stub?.lock?.locked && accessType != 'edit') {
throw { HBErrorCode: '51', code: stub?.lock.code, message: stub?.lock.shareMessage, brewId: stub?.shareId, brewTitle: stub?.title };
}
// If there's a google id, get it if requesting the full brew or if no stub found yet
if(googleId && (!stubOnly || !stub)) {
const oAuth2Client = isOwner ? GoogleActions.authCheck(req.account, res) : undefined;
const googleBrew = await GoogleActions.getGoogleBrew(oAuth2Client, googleId, id, accessType)
.catch((googleError)=>{
const reason = googleError.errors?.[0].reason;
if(reason == 'notFound')
throw { ...googleError, HBErrorCode: '02', authors: stub?.authors, account: req.account?.username };
else
throw { ...googleError, HBErrorCode: '01' };
});
// Throw any error caught while attempting to retrieve Google brew.
if(googleError) {
const reason = googleError.errors?.[0].reason;
if(reason == 'notFound') {
throw { ...googleError, HBErrorCode: '02', authors: stub?.authors, account: req.account?.username };
} else {
throw { ...googleError, HBErrorCode: '01' };
}
}
// Combine the Homebrewery stub with the google brew, or if the stub doesn't exist just use the google brew
stub = stub ? _.assign({ ...api.excludeStubProps(stub), stubbed: true }, api.excludeGoogleProps(googleBrew)) : googleBrew;
}
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))) {
const accessError = { name: 'Access Error', status: 401 };
if(req.account){
throw { ...accessError, message: 'User is not an Author', HBErrorCode: '03', authors: stub.authors, brewTitle: stub.title, shareId: stub.shareId };
}
throw { ...accessError, message: 'User is not logged in', HBErrorCode: '04', authors: stub.authors, brewTitle: stub.title, shareId: stub.shareId };
}
// If after all of that we still don't have a brew, throw an exception
if(!stub && !stubOnly) {
if(!stub)
throw { name: 'BrewLoad Error', message: 'Brew not found', status: 404, HBErrorCode: '05', accessType: accessType, brewId: id };
}
// Clean up brew: fill in missing fields with defaults / fix old invalid values
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
}
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 ?? {};
req.brew = stub;
next();
};
},
@@ -275,6 +279,8 @@ const api = {
let currentTheme;
const completeStyles = [];
const completeSnippets = [];
let themeName;
let themeAuthor;
while (req.params.id) {
//=== User Themes ===//
@@ -288,6 +294,10 @@ const api = {
currentTheme = req.brew;
splitTextStyleAndMetadata(currentTheme);
if(!currentTheme.tags.some(tag => tag === "meta:theme" || tag === "meta:Theme"))
throw { brewId: req.params.id, name: 'Invalid Theme Selected', message: 'Selected theme does not have the meta:theme tag', status: 422, HBErrorCode: '10' };
themeName ??= currentTheme.title;
themeAuthor ??= currentTheme.authors?.[0];
// If there is anything in the snippets or style members, append them to the appropriate array
if(currentTheme?.snippets) completeSnippets.push(JSON.parse(currentTheme.snippets));
@@ -295,9 +305,9 @@ const api = {
req.params.id = currentTheme.theme;
req.params.renderer = currentTheme.renderer;
}
} else {
//=== Static Themes ===//
else {
themeName ??= req.params.id;
const localSnippets = `${req.params.renderer}_${req.params.id}`; // Just log the name for loading on client
const localStyle = `@import url(\"/themes/${req.params.renderer}/${req.params.id}/style.css\");`;
completeSnippets.push(localSnippets);
@@ -310,7 +320,9 @@ const api = {
const returnObj = {
// Reverse the order of the arrays so they are listed oldest parent to youngest child.
styles : completeStyles.reverse(),
snippets : completeSnippets.reverse()
snippets : completeSnippets.reverse(),
name : themeName,
author : themeAuthor
};
res.setHeader('Content-Type', 'application/json');
@@ -353,7 +365,7 @@ const api = {
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));
const updated = await GoogleActions.updateGoogleBrew(api.excludeGoogleProps(brew), req.ip);
if(!updated) return;
}
@@ -464,12 +476,11 @@ const api = {
}
};
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));
router.post('/api', checkClientVersion, asyncHandler(api.newBrew));
router.put('/api/:id', checkClientVersion, asyncHandler(api.getBrew('edit', true)), asyncHandler(api.updateBrew));
router.put('/api/update/:id', checkClientVersion, asyncHandler(api.getBrew('edit', true)), asyncHandler(api.updateBrew));
router.delete('/api/:id', checkClientVersion, asyncHandler(api.deleteBrew));
router.get('/api/remove/:id', checkClientVersion, asyncHandler(api.deleteBrew));
router.get('/api/theme/:renderer/:id', asyncHandler(api.getThemeBundle));
module.exports = api;
export default api;

View File

@@ -1,5 +1,7 @@
/* eslint-disable max-lines */
import { splitTextStyleAndMetadata } from '../shared/helpers.js';
describe('Tests for api', ()=>{
let api;
let google;
@@ -36,8 +38,9 @@ describe('Tests for api', ()=>{
}
});
google = require('./googleActions.js');
model = require('./homebrew.model.js').model;
google = require('./googleActions.js').default;
model = require('./homebrew.model.js').model;
api = require('./homebrew.api').default;
jest.mock('./googleActions.js');
google.authCheck = jest.fn(()=>'client');
@@ -54,8 +57,6 @@ describe('Tests for api', ()=>{
setHeader : jest.fn(()=>{})
};
api = require('./homebrew.api');
hbBrew = {
text : `brew text`,
style : 'hello yes i am css',
@@ -297,7 +298,7 @@ describe('Tests for api', ()=>{
expect(next).toHaveBeenCalled();
expect(api.getId).toHaveBeenCalledWith(req);
expect(model.get).toHaveBeenCalledWith({ shareId: '1' });
expect(google.getGoogleBrew).toHaveBeenCalledWith('2', '1', 'share');
expect(google.getGoogleBrew).toHaveBeenCalledWith(undefined, '2', '1', 'share');
});
it('access is denied to a locked brew', async()=>{
@@ -575,7 +576,7 @@ brew`);
describe('Theme bundle', ()=>{
it('should return Theme Bundle for a User Theme', async ()=>{
const brews = {
userThemeAID : { title: 'User Theme A', renderer: 'V3', theme: null, shareId: 'userThemeAID', style: 'User Theme A Style' }
userThemeAID : { title: 'User Theme A', renderer: 'V3', theme: null, shareId: 'userThemeAID', style: 'User Theme A Style', tags: ['meta:theme'], authors: ['authorName'] }
};
const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew }));
@@ -586,6 +587,8 @@ brew`);
expect(res.status).toHaveBeenCalledWith(200);
expect(res.send).toHaveBeenCalledWith({
name : 'User Theme A',
author : 'authorName',
styles : ['/* From Brew: https://localhost/share/userThemeAID */\n\nUser Theme A Style'],
snippets : []
});
@@ -593,9 +596,9 @@ brew`);
it('should return Theme Bundle for nested User Themes', async ()=>{
const brews = {
userThemeAID : { title: 'User Theme A', renderer: 'V3', theme: 'userThemeBID', shareId: 'userThemeAID', style: 'User Theme A Style' },
userThemeBID : { title: 'User Theme B', renderer: 'V3', theme: 'userThemeCID', shareId: 'userThemeBID', style: 'User Theme B Style' },
userThemeCID : { title: 'User Theme C', renderer: 'V3', theme: null, shareId: 'userThemeCID', style: 'User Theme C Style' }
userThemeAID : { title: 'User Theme A', renderer: 'V3', theme: 'userThemeBID', shareId: 'userThemeAID', style: 'User Theme A Style', tags: ['meta:theme'], authors: ['authorName'] },
userThemeBID : { title: 'User Theme B', renderer: 'V3', theme: 'userThemeCID', shareId: 'userThemeBID', style: 'User Theme B Style', tags: ['meta:theme'], authors: ['authorName'] },
userThemeCID : { title: 'User Theme C', renderer: 'V3', theme: null, shareId: 'userThemeCID', style: 'User Theme C Style', tags: ['meta:theme'], authors: ['authorName'] }
};
const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew }));
@@ -606,6 +609,8 @@ brew`);
expect(res.status).toHaveBeenCalledWith(200);
expect(res.send).toHaveBeenCalledWith({
name : 'User Theme A',
author : 'authorName',
styles : [
'/* From Brew: https://localhost/share/userThemeCID */\n\nUser Theme C Style',
'/* From Brew: https://localhost/share/userThemeBID */\n\nUser Theme B Style',
@@ -622,6 +627,8 @@ brew`);
expect(res.status).toHaveBeenCalledWith(200);
expect(res.send).toHaveBeenCalledWith({
name : '5ePHB',
author : undefined,
styles : [
`/* From Theme Blank */\n\n@import url("/themes/V3/Blank/style.css");`,
`/* From Theme 5ePHB */\n\n@import url("/themes/V3/5ePHB/style.css");`
@@ -635,9 +642,9 @@ brew`);
it('should return Theme Bundle for nested User and Static Themes together', async ()=>{
const brews = {
userThemeAID : { title: 'User Theme A', renderer: 'V3', theme: 'userThemeBID', shareId: 'userThemeAID', style: 'User Theme A Style' },
userThemeBID : { title: 'User Theme B', renderer: 'V3', theme: 'userThemeCID', shareId: 'userThemeBID', style: 'User Theme B Style' },
userThemeCID : { title: 'User Theme C', renderer: 'V3', theme: '5eDMG', shareId: 'userThemeCID', style: 'User Theme C Style' }
userThemeAID : { title: 'User Theme A', renderer: 'V3', theme: 'userThemeBID', shareId: 'userThemeAID', style: 'User Theme A Style', tags: ['meta:theme'], authors: ['authorName'] },
userThemeBID : { title: 'User Theme B', renderer: 'V3', theme: 'userThemeCID', shareId: 'userThemeBID', style: 'User Theme B Style', tags: ['meta:theme'], authors: ['authorName'] },
userThemeCID : { title: 'User Theme C', renderer: 'V3', theme: '5eDMG', shareId: 'userThemeCID', style: 'User Theme C Style', tags: ['meta:theme'], authors: ['authorName'] }
};
const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew }));
@@ -648,6 +655,8 @@ brew`);
expect(res.status).toHaveBeenCalledWith(200);
expect(res.send).toHaveBeenCalledWith({
name : 'User Theme A',
author : 'authorName',
styles : [
`/* From Theme Blank */\n\n@import url("/themes/V3/Blank/style.css");`,
`/* From Theme 5ePHB */\n\n@import url("/themes/V3/5ePHB/style.css");`,
@@ -664,9 +673,9 @@ brew`);
});
});
it('should fail for an invalid Theme in the chain', async()=>{
it('should fail for a missing Theme in the chain', async()=>{
const brews = {
userThemeAID : { title: 'User Theme A', renderer: 'V3', theme: 'missingTheme', shareId: 'userThemeAID', style: 'User Theme A Style' },
userThemeAID : { title: 'User Theme A', renderer: 'V3', theme: 'missingTheme', shareId: 'userThemeAID', style: 'User Theme A Style', tags: ['meta:theme'], authors: ['authorName'] },
};
const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew }));
@@ -685,6 +694,27 @@ brew`);
name : 'ThemeLoad Error',
status : 404 });
});
it('should fail for a User Theme not tagged with meta:theme', async ()=>{
const brews = {
userThemeAID : { title: 'User Theme A', renderer: 'V3', theme: null, shareId: 'userThemeAID', style: 'User Theme A Style' }
};
const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew }));
model.get = jest.fn((getParams)=>toBrewPromise(brews[getParams.shareId]));
const req = { params: { renderer: 'V3', id: 'userThemeAID' }, get: ()=>{ return 'localhost'; }, protocol: 'https' };
let err;
await api.getThemeBundle(req, res)
.catch((e)=>err = e);
expect(err).toEqual({
HBErrorCode : '10',
brewId : 'userThemeAID',
message : 'Selected theme does not have the meta:theme tag',
name : 'Invalid Theme Selected',
status : 422 });
});
});
describe('deleteBrew', ()=>{
@@ -969,4 +999,57 @@ brew`);
expect(res.send).toHaveBeenCalledWith('');
});
});
describe('Split Text, Style, and Metadata', ()=>{
it('basic splitting', async ()=>{
const testBrew = {
text : '```metadata\n' +
'title: title\n' +
'description: description\n' +
'tags: [ \'tag a\' , \'tag b\' ]\n' +
'systems: [ test system ]\n' +
'renderer: legacy\n' +
'theme: 5ePHB\n' +
'lang: en\n' +
'\n' +
'```\n' +
'\n' +
'```css\n' +
'style\n' +
'style\n' +
'style\n' +
'```\n' +
'\n' +
'text\n'
};
splitTextStyleAndMetadata(testBrew);
// Metadata
expect(testBrew.title).toEqual('title');
expect(testBrew.description).toEqual('description');
expect(testBrew.tags).toEqual(['tag a', 'tag b']);
expect(testBrew.systems).toEqual(['test system']);
expect(testBrew.renderer).toEqual('legacy');
expect(testBrew.theme).toEqual('5ePHB');
expect(testBrew.lang).toEqual('en');
// Style
expect(testBrew.style).toEqual('style\nstyle\nstyle');
// Text
expect(testBrew.text).toEqual('text\n');
});
it('convert tags string to array', async ()=>{
const testBrew = {
text : '```metadata\n' +
'tags: tag a\n' +
'```\n\n'
};
splitTextStyleAndMetadata(testBrew);
// Metadata
expect(testBrew.tags).toEqual(['tag a']);
});
});
});

View File

@@ -1,7 +1,8 @@
const mongoose = require('mongoose');
const { nanoid } = require('nanoid');
const _ = require('lodash');
const zlib = require('zlib');
import mongoose from 'mongoose';
import { nanoid } from 'nanoid';
import _ from 'lodash';
import zlib from 'zlib';
const HomebrewSchema = mongoose.Schema({
shareId : { type: String, default: ()=>{return nanoid(12);}, index: { unique: true } },
@@ -44,7 +45,7 @@ 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);
const unzipped = zlib.inflateRawSync(brew.textBin);
brew.text = unzipped.toString();
}
return brew;
@@ -62,7 +63,7 @@ HomebrewSchema.statics.getByUser = async function(username, allowAccess=false, f
const Homebrew = mongoose.model('Homebrew', HomebrewSchema);
module.exports = {
schema : HomebrewSchema,
model : Homebrew,
export {
HomebrewSchema as schema,
Homebrew as model
};

View File

@@ -1,8 +1,10 @@
module.exports = (req, res, next)=>{
const userVersion = req.get('Homebrewery-Version');
const version = require('../../package.json').version;
import packageJSON from '../../package.json' with { type: 'json' };
if(userVersion != version) {
export default (req, res, next)=>{
const userVersion = req.get('Homebrewery-Version');
const version = packageJSON.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}.`
});
@@ -10,3 +12,4 @@ module.exports = (req, res, next)=>{
next();
};

View File

@@ -1,12 +1,12 @@
const config = require('../config.js');
import config from '../config.js';
const nodeEnv = config.get('node_env');
const isLocalEnvironment = config.get('local_environments').includes(nodeEnv);
module.exports = (req, res, next)=>{
export default (req, res, next)=>{
const isImageRequest = req.get('Accept')?.split(',')
?.filter((h)=>!h.includes('q='))
?.every((h)=>/image\/.*/.test(h));
if(isImageRequest && !isLocalEnvironment && !req.url?.startsWith('/staticImages')) {
if(isImageRequest && !(isLocalEnvironment && req.url?.startsWith('/staticImages'))) {
return res.status(406).send({
message : 'Request for image at this URL is not supported'
});

View File

@@ -1,41 +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();
});
});
import contentNegotiationMiddleware from './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

@@ -1,5 +1,5 @@
const mongoose = require('mongoose');
const _ = require('lodash');
import mongoose from 'mongoose';
import _ from 'lodash';
const NotificationSchema = new mongoose.Schema({
dismissKey : { type: String, unique: true, required: true },
@@ -56,7 +56,7 @@ NotificationSchema.statics.getAll = async function() {
const Notification = mongoose.model('Notification', NotificationSchema);
module.exports = {
schema : NotificationSchema,
model : Notification,
export {
NotificationSchema as schema,
Notification as model
};

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