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

Compare commits

..

570 Commits

Author SHA1 Message Date
Trevor Buckner
b9e15746c3 Update app.js 2024-10-11 23:47:45 -04:00
Trevor Buckner
1fff75cc5e Update homebrew.api.js 2024-10-11 23:42:20 -04:00
Trevor Buckner
9037cf1750 Update homebrew.api.js 2024-10-11 23:41:54 -04:00
Trevor Buckner
dfe26280d2 Update app.js 2024-10-11 23:38:00 -04:00
Trevor Buckner
7894d9fbec Update app.js 2024-10-11 23:35:15 -04:00
Trevor Buckner
c3173d2e14 Update homebrew.api.js 2024-10-11 23:25:55 -04:00
Trevor Buckner
4859756ef8 Update homebrew.api.js 2024-10-11 23:23:56 -04:00
Trevor Buckner
1c47d743d6 Remove 429 error 2024-10-11 23:20:32 -04:00
Trevor Buckner
bfbbbe9e86 Update package.json 2024-10-11 23:19:44 -04:00
Trevor Buckner
1aaa146412 Update package-lock.json 2024-10-11 23:19:17 -04:00
Trevor Buckner
086d85c08b Remove Error 55 2024-10-11 23:18:03 -04:00
Trevor Buckner
134fe7d372 Remove /ip path 2024-10-11 23:15:56 -04:00
Trevor Buckner
836dfbade2 SetSaveDelayTo10s 2024-10-11 23:15:03 -04:00
Trevor Buckner
52a7ce9866 Merge branch 'master' into v3.15.2 2024-10-11 23:08:41 -04:00
Trevor Buckner
05f3f40e47 Merge pull request #3812 from naturalcrit/dependabot/npm_and_yarn/babel/preset-env-7.25.8
Bump @babel/preset-env from 7.25.7 to 7.25.8
2024-10-11 12:11:57 -04:00
dependabot[bot]
7cad7fd319 Bump @babel/preset-env from 7.25.7 to 7.25.8
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.25.7 to 7.25.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.25.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>
2024-10-11 16:07:18 +00:00
Trevor Buckner
dca9099d00 Merge pull request #3811 from naturalcrit/dependabot/npm_and_yarn/babel/core-7.25.8
Bump @babel/core from 7.25.7 to 7.25.8
2024-10-11 12:06:05 -04:00
dependabot[bot]
fa78d04e89 Bump @babel/core from 7.25.7 to 7.25.8
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.25.7 to 7.25.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.25.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>
2024-10-11 03:50:24 +00:00
Trevor Buckner
5f9dfc9258 Merge pull request #3688 from G-Ambatte/experimentalDeploymentIdentification 2024-10-10 23:11:14 -04:00
G.Ambatte
d534eddb29 Remove unnecessary useEffect import 2024-10-11 13:14:53 +13:00
G.Ambatte
9099db5ea1 Remove obsolete state and event handlers 2024-10-11 11:56:29 +13:00
G.Ambatte
a9a8b4b9bb Shift static height style to LESS file 2024-10-11 11:55:51 +13:00
G.Ambatte
5d29d40c97 Implement suggested change 2024-10-11 11:42:03 +13:00
G.Ambatte
4291284252 Merge branch 'master' into experimentalDeploymentIdentification 2024-10-11 11:10:28 +13:00
Víctor Losada Hernández
fcede5448e Merge pull request #3492 from 5e-Cleric/fix-vulnerability-admin-pages
Fix admin vulnerability to Brute Force
2024-10-10 23:05:06 +02:00
Víctor Losada Hernández
c47974cb49 suggested changes 2024-10-10 23:00:39 +02:00
Víctor Losada Hernández
4fde4600bc fix pack 2024-10-10 22:58:55 +02:00
Víctor Losada Hernández
27f939201d Merge branch 'master' of https://github.com/naturalcrit/homebrewery into fix-vulnerability-admin-pages 2024-10-10 22:54:22 +02:00
Víctor Losada Hernández
6e2cde507d revert package completely 2024-10-10 22:50:29 +02:00
Víctor Losada Hernández
95d6e39a44 Revert "remove changes package lock"
This reverts commit 00f1d4a27e.
2024-10-10 22:49:19 +02:00
Víctor Losada Hernández
39b8cbae2a Revert "remove package 2"
This reverts commit 0162232053.
2024-10-10 22:49:16 +02:00
Víctor Losada Hernández
0162232053 remove package 2 2024-10-10 22:44:51 +02:00
Víctor Losada Hernández
00f1d4a27e remove changes package lock 2024-10-10 22:43:13 +02:00
Víctor Losada Hernández
db618fe2ad linting changes 2024-10-10 22:42:47 +02:00
Víctor Losada Hernández
47f2703388 remove unrelated change 2024-10-10 22:38:50 +02:00
Víctor Losada Hernández
52e929ee68 remove spaces added 2024-10-10 22:36:59 +02:00
Víctor Losada Hernández
f74e72a35f remove rate-limit 2024-10-10 22:32:17 +02:00
Trevor Buckner
e3d256aaaf Merge pull request #3800 from G-Ambatte/addIndexedDM-#3763
Change local version history to use Indexed DB
2024-10-10 15:38:52 -04:00
G.Ambatte
f65dee28cb Merge branch 'master' into addIndexedDM-#3763 2024-10-11 07:44:05 +13:00
Trevor Buckner
58dd1b147d Merge pull request #3807 from naturalcrit/dependabot/npm_and_yarn/globals-15.11.0
Bump globals from 15.10.0 to 15.11.0
2024-10-10 13:45:14 -04:00
Trevor Buckner
f84dcd9fce Merge branch 'master' into dependabot/npm_and_yarn/globals-15.11.0 2024-10-10 11:52:18 -04:00
Trevor Buckner
cc1ab35255 Merge pull request #3806 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.7.1
Bump mongoose from 8.7.0 to 8.7.1
2024-10-10 11:52:09 -04:00
G.Ambatte
803ca09ab6 Merge branch 'master' into addIndexedDM-#3763 2024-10-10 21:55:00 +13:00
dependabot[bot]
8a60a4a5cc Bump globals from 15.10.0 to 15.11.0
Bumps [globals](https://github.com/sindresorhus/globals) from 15.10.0 to 15.11.0.
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v15.10.0...v15.11.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-10-10 03:23:29 +00:00
dependabot[bot]
a345b67ffe Bump mongoose from 8.7.0 to 8.7.1
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.7.0 to 8.7.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.0...8.7.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-10-10 03:23:22 +00:00
Trevor Buckner
456cefd535 Merge pull request #3786 from dbolack-ab/nanoid-fix 2024-10-09 22:24:03 -04:00
G.Ambatte
ab6861675d Comment out history testing values 2024-10-10 09:07:54 +13:00
G.Ambatte
0deb9073cd Remove obsolete file 2024-10-10 08:57:41 +13:00
G.Ambatte
d5cda45d4d Merge branch 'master' into addIndexedDM-#3763 2024-10-10 08:50:39 +13:00
G.Ambatte
36674f4cf2 Add explicit guard clause to renderHistoryItems 2024-10-10 08:48:14 +13:00
G.Ambatte
618de544bf Remove unnecessary check 2024-10-10 08:43:38 +13:00
G.Ambatte
8f5b421531 Fix infinite loop 2024-10-10 08:34:24 +13:00
G.Ambatte
8db12739d3 Remove obsolete function 2024-10-10 08:34:15 +13:00
Trevor Buckner
4cb093c0c0 Merge branch 'master' into nanoid-fix 2024-10-09 15:10:03 -04:00
Trevor Buckner
9f0f9a9169 Merge pull request #2586 from G-Ambatte/experimentalNotificationDB 2024-10-09 15:09:25 -04:00
Trevor Buckner
a9aab5bb0c Add test for error handling deleting notifications 2024-10-09 14:52:56 -04:00
Trevor Buckner
5ca970bdee Typo 2024-10-09 14:46:18 -04:00
Trevor Buckner
9635e1a8eb Change another return to throw 2024-10-09 14:41:37 -04:00
Trevor Buckner
23e3c98a0d Add test for adding notification without dismissKey 2024-10-09 14:40:38 -04:00
Trevor Buckner
346bb0086e Should throw, not return errors, so they land in catch 2024-10-09 14:40:11 -04:00
Trevor Buckner
e873dcf3a8 Fix error messages crashing page 2024-10-09 14:35:16 -04:00
Trevor Buckner
269dd6107c Merge branch 'master' into experimentalNotificationDB 2024-10-09 11:12:23 -04:00
Trevor Buckner
8281db8543 Merge pull request #3804 from naturalcrit/dependabot/npm_and_yarn/cookie-parser-1.4.7 2024-10-09 11:07:27 -04:00
dependabot[bot]
66db3ecdc1 Bump cookie-parser from 1.4.6 to 1.4.7
Bumps [cookie-parser](https://github.com/expressjs/cookie-parser) from 1.4.6 to 1.4.7.
- [Release notes](https://github.com/expressjs/cookie-parser/releases)
- [Changelog](https://github.com/expressjs/cookie-parser/blob/master/HISTORY.md)
- [Commits](https://github.com/expressjs/cookie-parser/compare/1.4.6...1.4.7)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-09 15:06:37 +00:00
Trevor Buckner
1ef61b32d4 Merge pull request #3803 from naturalcrit/dependabot/npm_and_yarn/express-4.21.1 2024-10-09 11:05:13 -04:00
G.Ambatte
dc66d36b2d Simplify history loading 2024-10-09 19:35:48 +13:00
G.Ambatte
0bd3b53dd1 Merge branch 'master' into addIndexedDM-#3763 2024-10-09 19:00:45 +13:00
G.Ambatte
5651c66562 Fix race condition 2024-10-09 18:29:15 +13:00
G.Ambatte
fb2d03f5a2 Change to test values 2024-10-09 17:50:26 +13:00
G.Ambatte
0b44e68a36 Simplify garbage collection 2024-10-09 17:27:33 +13:00
dependabot[bot]
fe7ee78cae Bump express from 4.21.0 to 4.21.1
Bumps [express](https://github.com/expressjs/express) from 4.21.0 to 4.21.1.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.1/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.21.0...4.21.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-09 03:25:09 +00:00
G.Ambatte
aa68762294 Simplify historyCheck logic 2024-10-09 15:59:11 +13:00
G.Ambatte
2a9402634f Remove unnecessary guard clause 2024-10-09 14:58:20 +13:00
G.Ambatte
291e16b124 Revert to use local consts instead of config vars 2024-10-09 14:57:04 +13:00
G.Ambatte
e75eb72d3f Remove obsolete function 2024-10-09 14:54:23 +13:00
Trevor Buckner
7bf95dd0ca Merge pull request #3132 from dbolacksn/Issue_1958 2024-10-08 17:13:19 -04:00
Trevor Buckner
80a21e3f27 Merge branch 'master' into Issue_1958 2024-10-08 17:12:05 -04:00
Trevor Buckner
a921d0a9bb Merge pull request #3802 from Gazook89/Remove-Unused-Nav-Components 2024-10-08 17:10:20 -04:00
Trevor Buckner
9acecb63ed Merge branch 'master' into addIndexedDM-#3763 2024-10-08 17:07:39 -04:00
Gazook89
a6efaf0e8b Remove unused Nav components 2024-10-08 10:12:53 -05:00
David Bolack
c4b754e467 Lost a stray ) on update 2024-10-07 14:45:33 -05:00
David Bolack
e82411d3d2 Merge branch 'master' into Issue_1958 2024-10-07 14:35:19 -05:00
David Bolack
5080fd068a Merge branch 'master' into nanoid-fix 2024-10-07 14:32:19 -05:00
Trevor Buckner
88d36bcf85 Merge pull request #3798 from naturalcrit/dependabot/npm_and_yarn/eslint-9.12.0
Bump eslint from 9.11.1 to 9.12.0
2024-10-07 13:24:31 -04:00
dependabot[bot]
e2243efe82 Bump eslint from 9.11.1 to 9.12.0
Bumps [eslint](https://github.com/eslint/eslint) from 9.11.1 to 9.12.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.11.1...v9.12.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-07 15:10:37 +00:00
Trevor Buckner
337531a622 Merge pull request #3797 from naturalcrit/dependabot/npm_and_yarn/stylistic/stylelint-plugin-3.1.1
Bump @stylistic/stylelint-plugin from 3.1.0 to 3.1.1
2024-10-07 11:09:18 -04:00
G.Ambatte
7e165c6e61 Remove unnecessary key check 2024-10-07 21:53:24 +13:00
G.Ambatte
5d9ef3fa6c Add custom IDB store 2024-10-07 21:53:05 +13:00
G.Ambatte
24bffacaeb GC functional, config values now actually used 2024-10-07 20:53:32 +13:00
G.Ambatte
1e38ed8d1f Bump max-lines 2024-10-07 20:53:05 +13:00
G.Ambatte
25ce1aa00c Functional history menu 2024-10-07 19:36:17 +13:00
G.Ambatte
97f8493319 Merge branch 'master' into addIndexedDM-#3763 2024-10-07 18:32:05 +13:00
G.Ambatte
c9241e3091 WIP Update 2024-10-07 18:22:06 +13:00
dependabot[bot]
70118022b8 Bump @stylistic/stylelint-plugin from 3.1.0 to 3.1.1
Bumps [@stylistic/stylelint-plugin](https://github.com/stylelint-stylistic/stylelint-stylistic) from 3.1.0 to 3.1.1.
- [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.0...v3.1.1)

---
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>
2024-10-07 03:36:16 +00:00
Trevor Buckner
226e714f32 Merge pull request #3793 from 5e-Cleric/fix-wrong-brew-id-links-generated 2024-10-06 15:57:11 -04:00
Trevor Buckner
f3332fb95b Merge branch 'master' into fix-wrong-brew-id-links-generated 2024-10-06 15:54:37 -04:00
Trevor Buckner
10d4cd4ab3 Merge pull request #3796 from naturalcrit/FixGoogleLinksinUserPage 2024-10-06 15:52:29 -04:00
Trevor Buckner
2a523c4955 Fix links to google drive files in user page
User page was not marking Google Brews as "stubbed" if the brew belongs   to another users' Google Drive or your own credentials are expired (it searches the current user drive for google files and checks if those are stubbed)

This now sets *every* file found on Mongo as "Stubbed", whether the Drive file belongs to the current user or not.
2024-10-06 15:48:10 -04:00
Víctor Losada Hernández
64dd71601c last changes 2024-10-06 19:59:58 +02:00
Víctor Losada Hernández
4968300e7a return correct data 2024-10-06 19:54:41 +02:00
Víctor Losada Hernández
3acb25ce3a adress comments 2024-10-06 19:43:51 +02:00
Víctor Losada Hernández
487a574f50 initital fix 2024-10-06 00:05:12 -04:00
Víctor Losada Hernández
a4e0f1fc0f initital fix 2024-10-04 22:18:11 +02:00
Trevor Buckner
2ada6ce70d Merge pull request #3789 from naturalcrit/dependabot/npm_and_yarn/babel/core-7.25.7
Bump @babel/core from 7.25.2 to 7.25.7
2024-10-04 13:53:11 -04:00
dependabot[bot]
132878fd8c Bump @babel/core from 7.25.2 to 7.25.7
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.25.2 to 7.25.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.25.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>
2024-10-04 17:49:46 +00:00
Trevor Buckner
0146ab7ce0 Merge pull request #3787 from naturalcrit/dependabot/npm_and_yarn/babel/plugin-transform-runtime-7.25.7
Bump @babel/plugin-transform-runtime from 7.25.4 to 7.25.7
2024-10-04 13:48:31 -04:00
dependabot[bot]
a29addbfa3 Bump @babel/plugin-transform-runtime from 7.25.4 to 7.25.7
Bumps [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-runtime) from 7.25.4 to 7.25.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.25.7/packages/babel-plugin-transform-runtime)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-04 17:46:56 +00:00
Trevor Buckner
796f8ac8b7 Merge pull request #3788 from naturalcrit/dependabot/npm_and_yarn/babel/preset-env-7.25.7
Bump @babel/preset-env from 7.25.4 to 7.25.7
2024-10-04 13:45:42 -04:00
dependabot[bot]
19d76bd077 Bump @babel/preset-env from 7.25.4 to 7.25.7
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.25.4 to 7.25.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.25.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>
2024-10-04 14:51:12 +00:00
Trevor Buckner
f59a250bb1 Merge pull request #3790 from naturalcrit/dependabot/npm_and_yarn/babel/preset-react-7.25.7
Bump @babel/preset-react from 7.24.7 to 7.25.7
2024-10-04 10:49:52 -04:00
David Bolack
5b64052c21 Helps if I update the tests. 2024-10-03 18:49:16 -05:00
David Bolack
f00e76319c Hard code latest as min 2024-10-03 18:44:47 -05:00
David Bolack
a844b29165 Try further down the updates. 2024-10-03 18:40:22 -05:00
David Bolack
fcd1a2de5b Update node version one release. 2024-10-03 09:16:08 -05:00
Víctor Losada Hernández
5eb1456915 fix tests 2 2024-10-03 09:15:08 +02:00
Víctor Losada Hernández
a82e9758b3 fix test errors 2024-10-03 09:08:24 +02:00
Víctor Losada Hernández
6adac74f76 updated test 2024-10-03 09:01:12 +02:00
Víctor Losada Hernández
3c3b4d8466 "Updated mock implementation for deleting a notification in admin API test" 2024-10-03 09:00:57 +02:00
Víctor Losada Hernández
9cc4d2d7c5 add last test 2024-10-03 08:53:27 +02:00
Víctor Losada Hernández
d216216df7 remove unnecessary methods and comments 2024-10-03 08:48:54 +02:00
dependabot[bot]
9fd92e00a1 Bump @babel/preset-react from 7.24.7 to 7.25.7
Bumps [@babel/preset-react](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-react) from 7.24.7 to 7.25.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.25.7/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-10-03 03:17:35 +00:00
David Bolack
afeadb5417 Enable --experimental-require-module flag on node build in order to support ESM module only modules. 2024-10-02 22:05:09 -05:00
Trevor Buckner
e9286d4bb7 Merge pull request #3784 from naturalcrit/dependabot/npm_and_yarn/eslint-plugin-react-7.37.1
Bump eslint-plugin-react from 7.37.0 to 7.37.1
2024-10-01 23:39:13 -04:00
dependabot[bot]
22dbe1ebf0 Bump eslint-plugin-react from 7.37.0 to 7.37.1
Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.37.0 to 7.37.1.
- [Release notes](https://github.com/jsx-eslint/eslint-plugin-react/releases)
- [Changelog](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.37.0...v7.37.1)

---
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-02 03:34:52 +00:00
Trevor Buckner
53761bc567 Merge pull request #3785 from naturalcrit/dependabot/npm_and_yarn/globals-15.10.0
Bump globals from 15.9.0 to 15.10.0
2024-10-01 23:33:33 -04:00
dependabot[bot]
e6e9029bb7 Bump globals from 15.9.0 to 15.10.0
Bumps [globals](https://github.com/sindresorhus/globals) from 15.9.0 to 15.10.0.
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v15.9.0...v15.10.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-10-02 03:26:23 +00:00
Trevor Buckner
1a325fb3c5 New notification 2024-10-01 22:25:17 -04:00
Trevor Buckner
84f49aebce Add test for "add notification" 2024-10-01 21:54:22 -04:00
Trevor Buckner
8949248bc4 Example test
Added an example test that queries /admin/notification/all and checks if the response returns a list of notifications.

Since we don't have a real database, we overwrite (mock) NotificationModel to just return some fake data, otherwise the test would crash.
2024-10-01 17:15:36 -04:00
Víctor Losada Hernández
df06d8fcd3 update error index 2024-10-01 21:58:52 +02:00
Víctor Losada Hernández
d6ca6592a2 remove rateLimiter 2024-10-01 21:58:42 +02:00
Trevor Buckner
0110c6afed Remove duplicate error log for googleActions.list 2024-10-01 15:06:11 -04:00
Trevor Buckner
0e29620710 Remove delayMiddleware and ratelimiter 2024-10-01 14:13:15 -04:00
Trevor Buckner
c33b44855a Go back to service account for brew updates 2024-10-01 12:17:30 -04:00
G.Ambatte
77f162f7a4 Initial IDB functionality pass 2024-10-01 23:53:35 +13:00
Trevor Buckner
bc475b5ed9 Merge pull request #3762 from naturalcrit/dependabot/npm_and_yarn/eslint-plugin-react-7.37.0
Bump eslint-plugin-react from 7.36.1 to 7.37.0
2024-09-30 14:14:21 -04:00
Trevor Buckner
0415af624a Merge branch 'master' into dependabot/npm_and_yarn/eslint-plugin-react-7.37.0 2024-09-30 13:52:13 -04:00
Trevor Buckner
8a63859546 Merge pull request #3778 from 5e-Cleric/fix-lang-on-share
fix lang on share page
2024-09-30 13:51:50 -04:00
Trevor Buckner
8d5bc9e37c Merge pull request #3767 from G-Ambatte/fixToolbarZoomInPrint-#3744
Add zoom property to BrewRenderer print styling
2024-09-30 13:51:37 -04:00
Trevor Buckner
313f18c74c Merge branch 'master' into fixToolbarZoomInPrint-#3744 2024-09-30 13:50:00 -04:00
Trevor Buckner
0c6bc5d7ac Merge pull request #3757 from naturalcrit/v3.15.1
Fix Rate Limiting
2024-09-30 13:48:53 -04:00
Trevor Buckner
db6c689914 Merge branch 'master' into fix-lang-on-share 2024-09-30 13:48:20 -04:00
Víctor Losada Hernández
d4970ed119 initial commit 2024-09-30 17:48:07 +02:00
Trevor Buckner
e7e35294c6 disable rate limiter 2024-09-30 10:59:43 -04:00
Trevor Buckner
e9c45b216c Add retryconfig and forward user ip 2024-09-30 08:31:39 -04:00
Trevor Buckner
40925253bd autosave to 16 seconds 2024-09-30 00:59:30 -04:00
Trevor Buckner
66433d9e77 5 requests 2024-09-30 00:45:10 -04:00
Trevor Buckner
3a6750613b express proxy settings 2024-09-30 00:31:58 -04:00
dependabot[bot]
e45fddad60 Bump eslint-plugin-react from 7.36.1 to 7.37.0
Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.36.1 to 7.37.0.
- [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.36.1...v7.37.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-30 04:24:03 +00:00
Trevor Buckner
a31f1da4dc Merge branch 'master' into v3.15.1 2024-09-30 00:23:04 -04:00
Trevor Buckner
3ec3cf8df8 Merge pull request #3741 from naturalcrit/dependabot/npm_and_yarn/stylistic/stylelint-plugin-3.1.0 2024-09-30 00:22:49 -04:00
Trevor Buckner
a7361f8450 add delay between get and update 2024-09-30 00:14:37 -04:00
Trevor Buckner
32fa272947 reduce rate limit to 60 requests in 5 minutes 2024-09-30 00:03:27 -04:00
Trevor Buckner
68895bdca2 Rate limit /api requests from each IP address
100 requests each 5 minutes.
2024-09-29 23:37:26 -04:00
dependabot[bot]
4d6d8a5e5a Bump @stylistic/stylelint-plugin from 3.0.1 to 3.1.0
Bumps [@stylistic/stylelint-plugin](https://github.com/stylelint-stylistic/stylelint-stylistic) from 3.0.1 to 3.1.0.
- [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.0.1...v3.1.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-30 01:54:47 +00:00
Trevor Buckner
96acd334a0 Merge pull request #3742 from naturalcrit/dependabot/npm_and_yarn/eslint-9.11.1 2024-09-29 21:53:36 -04:00
Trevor Buckner
8ab6a8599d Use personal auth if logged in via google. 2024-09-29 21:47:45 -04:00
dependabot[bot]
a0aa975d07 Bump eslint from 9.11.0 to 9.11.1
Bumps [eslint](https://github.com/eslint/eslint) from 9.11.0 to 9.11.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.11.0...v9.11.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-29 18:24:55 +00:00
Trevor Buckner
8a06257a50 Merge pull request #3766 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.7.0 2024-09-29 14:23:41 -04:00
Trevor Buckner
ea656e5119 Issue notice 2024-09-29 00:15:26 -04:00
Trevor Buckner
aaa0acdfea Merge branch 'master' into v3.15.1 2024-09-28 23:40:25 -04:00
G.Ambatte
570c850c4f Merge branch 'master' into fixToolbarZoomInPrint-#3744 2024-09-28 09:05:22 +12:00
G.Ambatte
17dfacd5c9 Add zoom property to BrewRenderer print styling 2024-09-28 09:03:00 +12:00
dependabot[bot]
6d904111f7 Bump mongoose from 8.6.3 to 8.7.0
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.6.3 to 8.7.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.6.3...8.7.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-09-27 19:16:48 +00:00
Trevor Buckner
f1f686d8c7 Merge pull request #3760 from naturalcrit/dependabot/npm_and_yarn/dompurify-3.1.7 2024-09-27 15:15:43 -04:00
Trevor Buckner
6e120c2d05 Merge pull request #3765 from G-Ambatte/fixLegacyBrewRenders-#3764 2024-09-27 15:15:26 -04:00
Trevor Buckner
9b58db9f1e Let sharepage update page numbers 2024-09-27 15:03:29 -04:00
Trevor Buckner
ae123a8310 Change the other page number values as well 2024-09-27 11:35:01 -04:00
G.Ambatte
1f047890ab Change default value of currentEditorCursorPageNum 2024-09-27 23:32:19 +12:00
Trevor Buckner
58b0e12fcc Update app.js 2024-09-27 00:34:35 -04:00
Trevor Buckner
51f4c83ec0 Update app.js 2024-09-27 00:34:12 -04:00
Trevor Buckner
9decaf73f7 Update app.js 2024-09-27 00:19:08 -04:00
Trevor Buckner
15fde76209 Merge branch 'master' into v3.15.1 2024-09-27 00:13:32 -04:00
Trevor Buckner
2ba160fe65 Re-remove extra error log for new google brews. 2024-09-27 00:08:23 -04:00
dependabot[bot]
606af87e0f Bump dompurify from 3.1.6 to 3.1.7
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.1.6 to 3.1.7.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.1.6...3.1.7)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-27 03:53:15 +00:00
Trevor Buckner
05ad8e17a7 Merge pull request #3755 from naturalcrit/RaiseAutoSaveDelay 2024-09-26 19:17:51 -04:00
Trevor Buckner
bf87225415 Merge branch 'v3.15.1' into RaiseAutoSaveDelay 2024-09-26 19:17:35 -04:00
Trevor Buckner
8b61e69b77 Merge pull request #3754 from naturalcrit/RemoveDoubleGoogleDriveLogs 2024-09-26 19:15:46 -04:00
Trevor Buckner
e260eb0911 Raise timeout to 10 s.
No need to be stingy here... Can lower back down if this works.
2024-09-26 19:14:16 -04:00
Trevor Buckner
c8424e0b10 Remove test that no longer applies 2024-09-26 19:12:19 -04:00
Trevor Buckner
ff9a75f6b6 Remove duplicate error logs for google drive update / new
Errors are now logged once in the central error handler in app.js
2024-09-26 19:00:07 -04:00
Víctor Losada Hernández
ab32695ac9 test admin stuff 2024-09-25 11:34:56 +02:00
Trevor Buckner
cd0bf9c947 Merge pull request #3740 from naturalcrit/dependabot/npm_and_yarn/stylelint-config-recess-order-5.1.1
Bump stylelint-config-recess-order from 5.1.0 to 5.1.1
2024-09-23 15:20:43 -04:00
dependabot[bot]
c039a90624 Bump stylelint-config-recess-order from 5.1.0 to 5.1.1
Bumps [stylelint-config-recess-order](https://github.com/stormwarning/stylelint-config-recess-order) from 5.1.0 to 5.1.1.
- [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.0...v5.1.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-23 15:17:32 +00:00
Trevor Buckner
0e8387ec0d Merge pull request #3734 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.6.3
Bump mongoose from 8.6.2 to 8.6.3
2024-09-23 11:16:08 -04:00
dependabot[bot]
1347374ff7 Bump mongoose from 8.6.2 to 8.6.3
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.6.2 to 8.6.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.6.2...8.6.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-09-23 13:54:45 +00:00
Trevor Buckner
9419186e78 Merge pull request #3739 from naturalcrit/dependabot/npm_and_yarn/eslint-9.11.0
Bump eslint from 9.10.0 to 9.11.0
2024-09-23 09:53:30 -04:00
dependabot[bot]
58c6e6a446 Bump eslint from 9.10.0 to 9.11.0
Bumps [eslint](https://github.com/eslint/eslint) from 9.10.0 to 9.11.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.10.0...v9.11.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-09-23 03:35:10 +00:00
Trevor Buckner
6e2bc1cabe Merge pull request #3723 from naturalcrit/sort-in-vault
Add sorting options to Vault Page
2024-09-20 16:03:17 -04:00
Trevor Buckner
971be6375e lint 2024-09-20 16:02:09 -04:00
Trevor Buckner
4353c01032 Update server/vault.api.js 2024-09-20 16:01:29 -04:00
Víctor Losada Hernández
d09cecedd7 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into sort-in-vault 2024-09-20 20:54:14 +02:00
Víctor Losada Hernández
235e3f484f last changes, linted 2024-09-20 20:52:30 +02:00
Víctor Losada Hernández
b53b279241 fix pagination not applying sort 2024-09-20 20:38:54 +02:00
Víctor Losada Hernández
4fd358771a fix class by suggestion 2024-09-20 20:25:33 +02:00
Víctor Losada Hernández
02147411e3 fix sort and dir props 2024-09-20 20:23:58 +02:00
Víctor Losada Hernández
5d68cddd18 update state when necessary 2024-09-20 15:43:19 +02:00
Víctor Losada Hernández
74a065e747 minor css fix 2024-09-20 15:31:19 +02:00
Trevor Buckner
87c6343f30 Merge pull request #3736 from Gazook89/metadataEditor-tweaks 2024-09-19 16:51:37 -04:00
Gazook89
544f4c6103 tweak headers 2024-09-19 15:29:35 -05:00
Gazook89
a6ac6b98c2 some fixes and updates
This fixes something i broke with last commit, but should be final commit.
2024-09-19 11:09:22 -05:00
Gazook89
2336f8508b Rearrange CSS and small HTML changes
Simplified and unified some font-size declarations, adjusted the "descriptions" for various inputs to be similar structure and appearance, change the components h1 label from "Brew" to "Properties Editor", updated the comment about Publishing.
2024-09-19 10:57:55 -05:00
David Bolack
672b787cd5 Merge branch 'Issue_1958' of github.com:dbolacksn/homebrewery-broken into Issue_1958 2024-09-18 16:28:19 -05:00
David Bolack
931566636b Merge branch 'master' into Issue_1958 2024-09-18 16:26:39 -05:00
David Bolack
ffaca4ec10 Update server/middleware/content-negotiation.js
Co-authored-by: Trevor Buckner <calculuschild@gmail.com>
2024-09-18 16:21:31 -05:00
Trevor Buckner
fabc0bea83 Merge branch 'experimentalNotificationDB' of https://github.com/G-Ambatte/homebrewery into pr/2586 2024-09-18 15:50:55 -04:00
Trevor Buckner
5c2ad7dfee More Linting 2024-09-18 15:50:46 -04:00
Víctor Losada Hernández
3e7d4714a2 Merge branch 'experimentalNotificationDB' of https://github.com/G-Ambatte/homebrewery into experimentalNotificationDB 2024-09-18 21:47:05 +02:00
Víctor Losada Hernández
77c4ac6640 deleting useless state 2024-09-18 21:47:03 +02:00
Trevor Buckner
a7c892c1bb Lint 2024-09-18 15:36:48 -04:00
Trevor Buckner
dca7086522 Merge branch 'experimentalNotificationDB' of https://github.com/G-Ambatte/homebrewery into pr/2586 2024-09-18 15:35:12 -04:00
Trevor Buckner
6c42a7e180 Lint 2024-09-18 15:34:58 -04:00
Víctor Losada Hernández
e8c2858154 Merge branch 'experimentalNotificationDB' of https://github.com/G-Ambatte/homebrewery into experimentalNotificationDB 2024-09-18 21:32:19 +02:00
Víctor Losada Hernández
84f84782f5 Merge branch 'experimentalNotificationDB' of https://github.com/G-Ambatte/homebrewery; branch 'master' of https://github.com/naturalcrit/homebrewery into experimentalNotificationDB 2024-09-18 21:32:17 +02:00
Trevor Buckner
3caec793d8 Linting 2024-09-18 15:30:30 -04:00
Trevor Buckner
9717f0cd66 Split state into separate states. 2024-09-18 15:09:53 -04:00
Trevor Buckner
0cdc1947c1 Linting 2024-09-18 14:45:17 -04:00
Trevor Buckner
a8e5a96c98 Merge pull request #3733 from naturalcrit/fix-history-state-snippetbar-error
fix
2024-09-17 15:33:57 -04:00
Víctor Losada Hernández
f024bea493 delete unused error 2024-09-17 19:58:49 +02:00
Víctor Losada Hernández
61d77b4d2d fix 2024-09-17 19:55:50 +02:00
Víctor Losada Hernández
bbe4b5f978 Merge branch 'master' into fix-vulnerability-admin-pages 2024-09-17 12:47:18 +02:00
Víctor Losada Hernández
14d2534542 linting 2024-09-17 12:46:24 +02:00
Víctor Losada Hernández
3b49b5180e update error to auth 2024-09-17 12:25:54 +02:00
Víctor Losada Hernández
30e042635c Merge pull request #3724 from dbolack-ab/Pagella
Add Pagella Font family to Blank
2024-09-17 08:11:13 +02:00
David Bolack
3c04d491e6 Merge branch 'master' into Pagella 2024-09-16 18:34:07 -05:00
David Bolack
41e08831c6 Update font format. 2024-09-16 18:30:59 -05:00
Trevor Buckner
32c583ece8 Merge pull request #3634 from naturalcrit/nav-wrapping 2024-09-16 19:29:51 -04:00
Víctor Losada Hernández
a92b44427d lint 2024-09-16 23:17:12 +02:00
Víctor Losada Hernández
5961e9042a merge from master 2024-09-16 23:11:27 +02:00
Víctor Losada Hernández
2028f3dccd removing console log 2024-09-16 23:04:30 +02:00
Víctor Losada Hernández
8e4fc01831 linting 2024-09-16 23:03:50 +02:00
Víctor Losada Hernández
e2ae6898fd Merge branch 'master' of https://github.com/naturalcrit/homebrewery into fix-vulnerability-admin-pages 2024-09-16 23:00:52 +02:00
Trevor Buckner
471de9df9f Merge pull request #3692 from 5e-Cleric/more-style-snippets
Style snippets, more page sizes, A3, A5, Card
2024-09-16 16:55:58 -04:00
Trevor Buckner
398e6ef6f2 Slight rearranging 2024-09-16 16:53:55 -04:00
Víctor Losada Hernández
44262e2aae change initial status code 2024-09-16 22:52:56 +02:00
Víctor Losada Hernández
d8e174e143 update package-lock, apparently 2024-09-16 22:41:59 +02:00
Víctor Losada Hernández
bb59f0bbae moving page sizes around 2024-09-16 22:38:58 +02:00
Víctor Losada Hernández
c50ffe0723 linting 2024-09-16 22:38:08 +02:00
Víctor Losada Hernández
0d2878a7e7 merge from master and change error codes 2024-09-16 22:34:28 +02:00
Víctor Losada Hernández
a0d043439c Merge branch 'master' of https://github.com/naturalcrit/homebrewery into fix-vulnerability-admin-pages 2024-09-16 22:29:16 +02:00
Víctor Losada Hernández
8126271ea3 Merge branch 'fix-vulnerability-admin-pages' of https://github.com/5e-Cleric/homebrewery into fix-vulnerability-admin-pages 2024-09-16 22:25:17 +02:00
Víctor Losada Hernández
9bb21ddd04 Merge branch 'more-style-snippets' of https://github.com/5e-Cleric/homebrewery into more-style-snippets 2024-09-16 22:20:54 +02:00
Víctor Losada Hernández
746cd34087 suggested changes 2024-09-16 22:20:51 +02:00
Víctor Losada Hernández
313727035b suggested changes 2024-09-16 22:18:13 +02:00
Trevor Buckner
1a8611c528 Merge branch 'master' into more-style-snippets 2024-09-16 16:07:47 -04:00
Trevor Buckner
f7aa9346e9 Merge pull request #3711 from G-Ambatte/experimentalLocalStorageHistory
Store limited Brew History in Local Storage
2024-09-16 16:05:28 -04:00
G.Ambatte
83a7636b6f Simplify historyExists state logic 2024-09-17 07:41:34 +12:00
G.Ambatte
53c05a3ef6 Remove unused default item 2024-09-17 07:27:52 +12:00
Trevor Buckner
e20e681888 Merge branch 'master' into experimentalLocalStorageHistory 2024-09-16 11:10:45 -04:00
Trevor Buckner
f8fef1187c Merge pull request #3689 from dbolack-ab/GlobalToCToggles
Add Style Tab Snippets for Globally toggling additional header inclusion
2024-09-16 11:06:21 -04:00
Trevor Buckner
a866b45c55 Merge branch 'master' into GlobalToCToggles 2024-09-16 09:45:35 -04:00
G.Ambatte
8ceb422156 Separate bundled setState calls 2024-09-16 19:40:11 +12:00
G.Ambatte
8315df33ae Change empty slot logic 2024-09-16 19:39:51 +12:00
G.Ambatte
59f6f40ace Add seconds to display options 2024-09-16 19:24:39 +12:00
G.Ambatte
91f9a76af2 Remove spaces from code indentation 2024-09-16 19:20:14 +12:00
G.Ambatte
ae7404eb1f Remove comments 2024-09-16 19:15:16 +12:00
G.Ambatte
7a2fecf502 Set archiveBrew object directly
Co-authored-by: Trevor Buckner <calculuschild@gmail.com>
2024-09-16 19:07:42 +12:00
Trevor Buckner
dfd3b99232 Merge branch 'master' into experimentalLocalStorageHistory 2024-09-16 01:50:54 -04:00
Trevor Buckner
a953bf0555 Merge pull request #3731 from naturalcrit/dependabot/npm_and_yarn/express-static-gzip-2.1.8 2024-09-16 01:44:48 -04:00
Trevor Buckner
88ff10d229 Merge pull request #3732 from naturalcrit/Linting 2024-09-16 01:44:34 -04:00
Trevor Buckner
8d479b8cd1 Lint whitespace changes 2024-09-16 01:42:44 -04:00
Trevor Buckner
63675a46e0 Lint more things 2024-09-16 01:42:21 -04:00
Trevor Buckner
5cc5eec619 Lint toolbar and snippetbar 2024-09-16 01:41:46 -04:00
Trevor Buckner
b5490e3a53 Lint editor.jsx 2024-09-16 01:40:21 -04:00
Trevor Buckner
1645a5acf4 Lint App.js
Just whitespace changes
2024-09-16 01:39:44 -04:00
Trevor Buckner
98c5b798a7 Merge branch 'master' into experimentalLocalStorageHistory 2024-09-16 01:03:29 -04:00
Trevor Buckner
295d878c3d Merge branch 'master' into dependabot/npm_and_yarn/express-static-gzip-2.1.8 2024-09-16 01:02:24 -04:00
Trevor Buckner
a283438b28 Merge pull request #3484 from dbolack-ab/Issue_241_Part_II 2024-09-16 00:51:04 -04:00
Trevor Buckner
48bdc417fa More logic simplification 2024-09-16 00:39:04 -04:00
dependabot[bot]
d2117259eb Bump express-static-gzip from 2.1.7 to 2.1.8
Bumps [express-static-gzip](https://github.com/tkoenig89/express-static-gzip) from 2.1.7 to 2.1.8.
- [Release notes](https://github.com/tkoenig89/express-static-gzip/releases)
- [Commits](https://github.com/tkoenig89/express-static-gzip/compare/v2.1.7...v2.1.8)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-16 03:50:51 +00:00
David Bolack
67e265b23f Set default values for hb_images and hb_fonts in the config.
Remove stray tab.
2024-09-15 21:55:18 -05:00
Trevor Buckner
25a40e31c5 Remove console logs 2024-09-15 22:31:29 -04:00
Trevor Buckner
a353425d07 More cleanup 2024-09-15 22:13:41 -04:00
Trevor Buckner
c07c02f1d9 Remove unused variable 2024-09-15 21:44:02 -04:00
Trevor Buckner
81ab9417d3 Clean up unused code 2024-09-15 21:42:55 -04:00
Trevor Buckner
85401ba71b Fix BrewRenderer scrolling to 0 2024-09-15 21:26:49 -04:00
David Bolack
3ad0755c36 Correct ToC Global toggles subsnippets
The snippets incorrectedly reflected their previous incarnation as part of the Styles tab menus.
2024-09-15 18:33:14 -05:00
David Bolack
dc67c75130 Merge branch 'master' into Issue_1958 2024-09-15 18:15:19 -05:00
David Bolack
3388fccad7 Merge branch 'master' into Issue_241_Part_II 2024-09-15 18:11:38 -05:00
David Bolack
98cc79df92 Merge branch 'master' into Pagella 2024-09-15 18:03:51 -05:00
David Bolack
189363ec76 Merge branch 'master' into GlobalToCToggles 2024-09-15 18:03:16 -05:00
David Bolack
dbe56abb24 Merge branch 'master' of github.com:naturalcrit/homebrewery 2024-09-15 17:50:14 -05:00
Trevor Buckner
84c0242eee Put page jump checks in componentDidUpdate
Jump when the current page for brew or editor changes
2024-09-15 00:13:49 -04:00
G.Ambatte
eddc81d051 Merge branch 'master' into experimentalLocalStorageHistory 2024-09-15 14:23:14 +12:00
G.Ambatte
2f392a7517 Lint fixes 2024-09-15 14:19:32 +12:00
G.Ambatte
531e6efa5e Get configuration from config files 2024-09-15 14:19:24 +12:00
G.Ambatte
72257dc71b Lint fixes 2024-09-15 14:09:56 +12:00
G.Ambatte
b456bb955a Initial UI functionality 2024-09-15 14:09:47 +12:00
Trevor Buckner
181c6bf65a Update editor.jsx 2024-09-14 19:15:39 -04:00
Trevor Buckner
d4fa5d55d0 Merge branch 'master' into pr/3484 2024-09-14 19:15:12 -04:00
Trevor Buckner
5a932b781b Merge pull request #3729 from naturalcrit/LiftRendererPageStateUp 2024-09-14 19:06:02 -04:00
Trevor Buckner
eebf24e1ba Merge branch 'LiftRendererPageStateUp' of https://github.com/naturalcrit/homebrewery into LiftRendererPageStateUp 2024-09-14 19:03:06 -04:00
Trevor Buckner
26a126859d Lint 2024-09-14 19:02:55 -04:00
Trevor Buckner
41b9a570b5 Merge branch 'master' into LiftRendererPageStateUp 2024-09-14 19:01:10 -04:00
Trevor Buckner
76c9f2ee71 Lint 2024-09-14 18:58:23 -04:00
Trevor Buckner
5c2acf3183 Let Editor pass changes up and inherit values down 2024-09-14 18:52:13 -04:00
Trevor Buckner
fa2874b18f Let brewRenderer pass changes up, and inherit values down 2024-09-14 18:50:38 -04:00
Trevor Buckner
7e776df4d4 Add Current Page states up into editor components, pass down to children 2024-09-14 18:50:09 -04:00
Víctor Losada Hernández
ebc3b4ee66 "Updated admin notification management: added error handling and styling, modified notification add and lookup functionality, and refactored server-side API routes and error handling." 2024-09-14 23:58:47 +02:00
G.Ambatte
7009ef4441 Remove unneeded brew.shareId reference 2024-09-15 00:47:54 +12:00
G.Ambatte
ff19e3875e Shift GC to use savedAt time 2024-09-14 23:43:44 +12:00
G.Ambatte
7ec2558eef Add guard clause for history UI items 2024-09-14 23:43:26 +12:00
G.Ambatte
a7cf49557a Tweak dropdown padding 2024-09-14 23:04:18 +12:00
G.Ambatte
c4c5ffff9b Tweak UI styling 2024-09-14 22:49:53 +12:00
G.Ambatte
719cc0c485 Remove onClick from UI 2024-09-14 22:49:39 +12:00
G.Ambatte
d01548feb6 Add getHistoryItems function 2024-09-14 21:20:31 +12:00
G.Ambatte
48eb42862a Add History styling 2024-09-14 17:32:20 +12:00
G.Ambatte
ace790739f Stub out History function on Editor Nav Bar 2024-09-14 17:32:07 +12:00
G.Ambatte
c77d6e5fae Simplify logic 2024-09-14 16:50:36 +12:00
G.Ambatte
b6bbed0e1b Merge branch 'master' into experimentalLocalStorageHistory 2024-09-14 13:59:14 +12:00
Víctor Losada Hernández
9bf28f1433 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into experimentalNotificationDB 2024-09-13 23:54:01 +02:00
Víctor Losada Hernández
dbbfb0b628 suggestions added, linted 2024-09-13 23:29:36 +02:00
Víctor Losada Hernández
4f2c2916d6 remove cx 2024-09-13 23:03:40 +02:00
Víctor Losada Hernández
629b51a26c remove logs and unecessary state 2024-09-13 20:33:58 +02:00
Víctor Losada Hernández
d947ff45e2 correct style to be coherent and nice 2024-09-13 20:33:21 +02:00
Víctor Losada Hernández
a2d260c297 remove lookup by id funct and fix lost state functions 2024-09-13 20:29:35 +02:00
Víctor Losada Hernández
c411691fd6 remove lookup by id and admin access middleware from lookup all 2024-09-13 20:29:09 +02:00
Trevor Buckner
4a9fe1dbdb Merge pull request #3727 from naturalcrit/dependabot/npm_and_yarn/eslint-plugin-react-7.36.1
Bump eslint-plugin-react from 7.35.2 to 7.36.1
2024-09-13 11:50:16 -04:00
dependabot[bot]
0ce0ae771b Bump eslint-plugin-react from 7.35.2 to 7.36.1
Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.35.2 to 7.36.1.
- [Release notes](https://github.com/jsx-eslint/eslint-plugin-react/releases)
- [Changelog](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.35.2...v7.36.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-13 15:45:11 +00:00
Trevor Buckner
6334d191f8 Merge pull request #3726 from naturalcrit/dependabot/npm_and_yarn/express-4.21.0
Bump express from 4.20.0 to 4.21.0
2024-09-13 11:43:57 -04:00
dependabot[bot]
75699874d0 Bump express from 4.20.0 to 4.21.0
Bumps [express](https://github.com/expressjs/express) from 4.20.0 to 4.21.0.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.20.0...4.21.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-13 15:26:06 +00:00
Trevor Buckner
f1633cf03c Merge pull request #3725 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.6.2
Bump mongoose from 8.6.1 to 8.6.2
2024-09-13 11:24:45 -04:00
Trevor Buckner
3ef91cb1ea Add check for scroll event complete/ lift page state up 2024-09-12 12:55:11 -04:00
Víctor Losada Hernández
f40c5e17ca change to 401 2024-09-12 14:04:35 +02:00
dependabot[bot]
5b8928685f Bump mongoose from 8.6.1 to 8.6.2
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.6.1 to 8.6.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.6.1...8.6.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-09-12 03:14:50 +00:00
David Bolack
1b0fd6bb33 Add Pagella face to Blank Template.
Pagella is a TeX update of the URW Palladio L face that is a good substitute for the commonly used Book Antiqua and Palatino faces.

    https://en.wikipedia.org/wiki/Palatino#:~:text=The%20first%20legal%20free%20version,on%20URW%20Palladio%20L%20font.
2024-09-10 20:52:19 -05:00
David Bolack
84d237e792 Revert "Add Pagella face to Blank Template."
This reverts commit 7d298565f9.
2024-09-10 20:50:47 -05:00
David Bolack
7d298565f9 Add Pagella face to Blank Template.
Pagella is a TeX update of the URW Palladio L face that is a good substitute for the commonly used Book Antiqua and Palatino faces.

https://en.wikipedia.org/wiki/Palatino#:~:text=The%20first%20legal%20free%20version,on%20URW%20Palladio%20L%20font.
2024-09-10 20:44:42 -05:00
David Bolack
7c59f56fb2 Explode tocInclude and tocExclude snippet menus to match tocGlobal and tocDepth pattern. 2024-09-10 20:22:50 -05:00
G.Ambatte
091e7e0b65 Merge branch 'master' into experimentalLocalStorageHistory 2024-09-11 07:38:42 +12:00
David Bolack
bc6b4e3bfc Move ToC Includes Menu from styles to Table of Contents subsnippet
Create additional subsnippets for .tocInclude*, .tocExclude*, and move the existing depth entries to a subsnippet.
2024-09-10 14:18:36 -05:00
David Bolack
5a2e071879 Merge branch 'master' into GlobalToCToggles 2024-09-10 14:12:04 -05:00
David Bolack
8fa5eeb0ef Merge branch 'master' into Issue_241_Part_II 2024-09-10 14:10:20 -05:00
David Bolack
59f27197f6 A few small cleanups for ToC
Explicitly define --TOC as included in :root so there is no doubt the default value.
Rearrange Block ToC inclusion classes for organization and comments

Add block level, single Header class exclusion convienance classes.
2024-09-10 13:34:47 -05:00
Trevor Buckner
1646ba7e25 Merge pull request #3481 from naturalcrit/metadata-api-endpoint
Add API endpoint to get metadata from brews
2024-09-10 13:36:17 -04:00
Trevor Buckner
29460edca9 Merge branch 'master' into metadata-api-endpoint 2024-09-10 13:26:40 -04:00
David Bolack
f8d170be87 Document level toggles need to look at pages, not page. 2024-09-10 12:15:12 -05:00
Trevor Buckner
2ecdd962bd Merge pull request #3721 from naturalcrit/dependabot/npm_and_yarn/react-router-dom-6.26.2
Bump react-router-dom from 6.26.1 to 6.26.2
2024-09-10 13:13:11 -04:00
David Bolack
ed376f3154 Oy, what a typo. 2024-09-10 11:25:06 -05:00
David Bolack
930974f66d Merge branch 'GlobalToCToggles' of github.com:dbolack-ab/homebrewery into GlobalToCToggles 2024-09-10 11:11:12 -05:00
dependabot[bot]
aba8946274 Bump react-router-dom from 6.26.1 to 6.26.2
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.26.1 to 6.26.2.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.26.2/packages/react-router-dom)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-10 16:01:10 +00:00
Trevor Buckner
a2b5903bde Merge pull request #3720 from naturalcrit/dependabot/npm_and_yarn/express-4.20.0
Bump express from 4.19.2 to 4.20.0
2024-09-10 11:59:55 -04:00
G.Ambatte
a93133a9f3 Merge branch 'master' into experimentalLocalStorageHistory 2024-09-10 23:13:13 +12:00
Víctor Losada Hernández
ea1d0714b4 initial commit 2024-09-10 08:28:34 +02:00
Víctor Losada Hernández
9f4cf60cda Merge branch 'master' into more-style-snippets 2024-09-10 08:05:36 +02:00
Trevor Buckner
e5ab223571 Better line position (viewport has some margin) 2024-09-10 01:25:26 -04:00
Trevor Buckner
45a9501459 Jump based on scroll position, not cursor position 2024-09-10 01:11:28 -04:00
Trevor Buckner
ec74b994d7 Simplify scroll event for source editor using lodash Throttle 2024-09-10 00:43:44 -04:00
Trevor Buckner
b5155ed256 remove unused variable 2024-09-09 23:40:06 -04:00
Trevor Buckner
315296458a Remove setting button styles in componentDidMount
Just set the state, and the renderer will know what to display.
2024-09-09 23:39:29 -04:00
dependabot[bot]
e601e19381 Bump express from 4.19.2 to 4.20.0
Bumps [express](https://github.com/expressjs/express) from 4.19.2 to 4.20.0.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.19.2...4.20.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-10 03:36:23 +00:00
Trevor Buckner
0fbb4879a9 Set button appearance based on state
Avoid manually editing the DOM elements. Let the Render function update the appearance based on state.
2024-09-09 23:35:18 -04:00
Trevor Buckner
51c8973a85 Move onClick from the lock icon to the whole button 2024-09-09 23:29:10 -04:00
Trevor Buckner
707b90e445 Merge branch 'master' into pr/3484 2024-09-09 23:22:00 -04:00
Trevor Buckner
7f656bc408 Merge pull request #3719 from naturalcrit/Refactor-tableOfContents.gen.js 2024-09-09 23:20:59 -04:00
Trevor Buckner
5c906ee722 Logic rewrite
Realized we don't need to build a whole descendency tree of all the headers. We can just track the current indendation level and what headers are at each indent. This removes about 1/4 of the code, and lets us put all of the exit conditions (no title, no showPage, ToCExclude) in one place to easily see what is being excluded and what not.
2024-09-09 23:16:56 -04:00
David Bolack
3629292ebb Remove 2024-09-09 17:09:24 -05:00
Trevor Buckner
2cb3ca6880 Merge pull request #3714 from Gazook89/Meta-Tags-for-Vault
Meta Tags for the Vault Page
2024-09-09 11:13:42 -04:00
Trevor Buckner
90ee9afb54 Merge pull request #3679 from dbolack-ab/skipCountingSnippet
Add Page number alteration snippets
2024-09-09 11:12:16 -04:00
Trevor Buckner
2284f15876 Update tableOfContents.gen.js 2024-09-09 11:11:40 -04:00
Trevor Buckner
bfcb904ab7 Merge branch 'master' into skipCountingSnippet 2024-09-09 11:10:47 -04:00
Trevor Buckner
232d3c66a4 Merge pull request #3705 from Gazook89/Hide-Toolbar-2
Add button to toggle Preview tools
2024-09-09 11:03:53 -04:00
Trevor Buckner
2b458d1265 Merge branch 'master' into Hide-Toolbar-2 2024-09-09 11:01:39 -04:00
Trevor Buckner
58a2993fe1 use className for react classes
Avoid warning of conflict with JS "class" keyword.
2024-09-09 11:00:45 -04:00
Trevor Buckner
0f8fcb9889 Merge pull request #3716 from 5e-Cleric/fix-arrows-in-vault-this-time-for-real
fixing it once and for all
2024-09-09 10:52:52 -04:00
Trevor Buckner
cbe3c79b6b Merge branch 'master' into fix-arrows-in-vault-this-time-for-real 2024-09-09 10:46:46 -04:00
Trevor Buckner
c707db4aa5 Merge pull request #3717 from naturalcrit/dependabot/npm_and_yarn/eslint-9.10.0
Bump eslint from 9.9.1 to 9.10.0
2024-09-09 10:46:33 -04:00
Trevor Buckner
87415d54d5 Merge branch 'master' into fix-arrows-in-vault-this-time-for-real 2024-09-09 10:46:24 -04:00
Trevor Buckner
7525509887 Merge branch 'master' into dependabot/npm_and_yarn/eslint-9.10.0 2024-09-09 10:40:11 -04:00
Trevor Buckner
e5a189939b Merge pull request #3639 from dbolack-ab/actualPageNumber
Rework page counters for skipping and resets.
2024-09-09 10:39:25 -04:00
dependabot[bot]
f3bc8f91cc Bump eslint from 9.9.1 to 9.10.0
Bumps [eslint](https://github.com/eslint/eslint) from 9.9.1 to 9.10.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.9.1...v9.10.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-09-09 03:41:08 +00:00
David Bolack
3b4dd7dd61 Merge branch 'actualPageNumber' of github.com:dbolack-ab/homebrewery into actualPageNumber 2024-09-08 15:27:43 -05:00
David Bolack
4bc957159d Move a couple of variables back out of the global space because that was bad. 2024-09-08 15:23:03 -05:00
Trevor Buckner
7881d4b4a2 Small logic cleanup and renaming 2024-09-08 16:22:58 -04:00
David Bolack
1e9c7423c7 Fix "clicked on the toggle ring" crash with scroll lock.
The code was doing dom-climbing math based on clicking on the div contents but was attached to the div. Moved the onClick to the contents.
2024-09-07 22:36:27 -05:00
David Bolack
fa74fb4ada Update tooltips for locking. 2024-09-07 21:38:07 -05:00
David Bolack
7a37bf47c5 Bodge Render side mirroring back into place. 2024-09-07 21:33:51 -05:00
David Bolack
be70b9e67d Regroup page numbering snippets, update icons 2024-09-07 20:50:18 -05:00
David Bolack
f7a5097dd8 Merge branch 'master' into skipCountingSnippet 2024-09-07 20:43:28 -05:00
David Bolack
758c2799a1 That was the wrong way. Lets try this ugly fix. 2024-09-07 20:40:29 -05:00
David Bolack
b0dffc6df1 Drop empty entries 2024-09-07 20:35:43 -05:00
David Bolack
6ea724bb16 Start skipping .skipCount in ToC 2024-09-07 20:30:16 -05:00
David Bolack
b58688bd62 Stop comparing lengths, dude. 2024-09-07 20:19:56 -05:00
David Bolack
0f8461ced6 Not a collection. 2024-09-07 20:16:16 -05:00
David Bolack
3b0028da69 Move some of thos variables back. 2024-09-07 20:12:05 -05:00
David Bolack
049b64cd41 Remove unneeded variable 2024-09-07 19:54:52 -05:00
David Bolack
8709772f51 Merge branch 'actualPageNumber' of github.com:dbolack-ab/homebrewery into actualPageNumber 2024-09-07 19:54:13 -05:00
David Bolack
dcc7a22272 First pass at code fixes.
Move functions out of function
Use querySelector instead of querySelectorAll
Flip skip and reset counter order.
2024-09-07 19:47:16 -05:00
David Bolack
92f963d798 Merge branch 'master' into actualPageNumber 2024-09-07 18:59:12 -05:00
Víctor Losada Hernández
e5f6d28abd fixing it once and for all 2024-09-07 22:37:22 +02:00
Trevor Buckner
b124e55b3d Merge branch 'master' into Issue_241_Part_II 2024-09-06 23:51:14 -04:00
G.Ambatte
6e1cf63ed9 Merge branch 'experimentalLocalStorageHistory' of https://github.com/G-Ambatte/homebrewery into experimentalLocalStorageHistory 2024-09-07 14:07:36 +12:00
G.Ambatte
bc35b5245b Fix renamed variable 2024-09-07 14:07:30 +12:00
G.Ambatte
4033307473 Merge branch 'master' into experimentalLocalStorageHistory 2024-09-07 14:05:16 +12:00
G.Ambatte
cd30679aac Remove debugging line 2024-09-07 14:01:25 +12:00
G.Ambatte
9679e5b130 Add garbage collection function to remove version data after specified period without update 2024-09-07 14:00:31 +12:00
G.Ambatte
4d295f5f18 Add comments to elucidate the madness 2024-09-07 13:22:44 +12:00
G.Ambatte
6ed6b6d66f Remove debugging line 2024-09-07 13:10:36 +12:00
G.Ambatte
87ba4ee264 Basic functionality working 2024-09-07 13:07:58 +12:00
Trevor Buckner
5e9fad9b09 Merge branch 'master' into actualPageNumber 2024-09-06 16:56:49 -04:00
G.Ambatte
6693eebe64 Updated version saving logic 2024-09-07 08:47:53 +12:00
Trevor Buckner
f0a8bf379a Fix non-uniform spacing/indenting 2024-09-06 16:43:44 -04:00
Trevor Buckner
fb843ef3c1 Merge branch 'master' into GlobalToCToggles 2024-09-06 16:36:02 -04:00
Trevor Buckner
22678b15af Fix snippet filter 2024-09-06 16:35:18 -04:00
Trevor Buckner
d2cefa8bf7 Merge branch 'master' into GlobalToCToggles 2024-09-06 16:22:52 -04:00
Trevor Buckner
e5d0051075 Create pull_request_template.md 2024-09-06 15:57:33 -04:00
Trevor Buckner
df8fd077ca Merge pull request #3696 from dbolack-ab/snippets-no-gen 2024-09-06 14:16:50 -04:00
David Bolack
88caa81baa Merge branch 'master' into snippets-no-gen 2024-09-06 12:25:22 -05:00
David Bolack
4a1e4c1b80 Merge branch 'master' into actualPageNumber 2024-09-06 12:24:40 -05:00
David Bolack
cf4747553c Merge branch 'master' into skipCountingSnippet 2024-09-06 12:23:46 -05:00
David Bolack
a2497052b4 Merge branch 'master' into Issue_1958 2024-09-06 11:56:04 -05:00
David Bolack
240dfa3954 Merge branch 'Issue_1958' of github.com:dbolacksn/homebrewery-broken into Issue_1958
Only except /staticImages with a `local` NODE_ENV
2024-09-06 11:55:21 -05:00
David Bolack
d19aaf6c78 Except staticImages and staticFonts paths from middleware evaluation if in a local ENV. 2024-09-06 11:50:46 -05:00
David Bolack
e777fb542a Merge branch 'master' into GlobalToCToggles 2024-09-06 09:47:59 -05:00
David Bolack
5c9c342b10 Update client/homebrew/editor/snippetbar/snippetbar.jsx
Co-authored-by: Trevor Buckner <calculuschild@gmail.com>
2024-09-06 01:25:13 -05:00
G.Ambatte
f3011eeef9 Update delay amounts 2024-09-06 16:58:30 +12:00
G.Ambatte
9fd581149b Shift version history to separate file 2024-09-06 16:57:11 +12:00
Trevor Buckner
84736980c9 Merge pull request #3713 from Gazook89/Fix-Vault-Styling-Issues
Fix Vault Page CSS specificity issues
2024-09-05 14:59:09 -04:00
Gazook89
03c14e5847 adds meta tags for the Vault page
So they show up when sharing the link in Discord or wherever.
2024-09-05 11:24:59 -05:00
Gazook89
e0be7a5db3 Move rules out of body and into more specific elements 2024-09-05 11:13:08 -05:00
Trevor Buckner
2e332d7699 Merge pull request #3710 from naturalcrit/dependabot/npm_and_yarn/eslint-plugin-jest-28.8.3
Bump eslint-plugin-jest from 28.8.2 to 28.8.3
2024-09-05 11:01:57 -04:00
G.Ambatte
03bc9a8189 Test of combined version and time differential requirement for update 2024-09-05 23:24:14 +12:00
G.Ambatte
421c88cc07 Save brew text/style to local storage 2024-09-05 22:35:14 +12:00
G.Ambatte
235969a485 Fix a dropped bracket 2024-09-05 16:50:19 +12:00
G.Ambatte
2e459118aa Update content-negotiation.js 2024-09-05 16:45:07 +12:00
G.Ambatte
ff60ca163f Merge branch 'master' into Issue_1958 2024-09-05 16:38:14 +12:00
dependabot[bot]
53979f2266 Bump eslint-plugin-jest from 28.8.2 to 28.8.3
Bumps [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) from 28.8.2 to 28.8.3.
- [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.2...v28.8.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-05 03:38:40 +00:00
David Bolack
4dc5746c71 Merge branch 'master' into Issue_1958 2024-09-04 20:52:46 -05:00
Trevor Buckner
780c92cb9b Merge pull request #3704 from G-Ambatte/experimentalGitAttribs 2024-09-04 19:38:41 -04:00
Trevor Buckner
20c54ef79e Merge branch 'master' into experimentalGitAttribs 2024-09-04 19:38:32 -04:00
Trevor Buckner
5ce69041fc Merge pull request #3708 from naturalcrit/fix-arrows
FIx missing arrows
2024-09-04 18:07:38 -04:00
Víctor Losada Hernández
20db8c6720 restore missing state 2024-09-04 23:57:44 +02:00
Trevor Buckner
ed35eb2680 Merge pull request #3702 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.6.1 2024-09-04 17:22:22 -04:00
Trevor Buckner
2a7b7cd50c Merge branch 'master' into dependabot/npm_and_yarn/mongoose-8.6.1 2024-09-04 17:21:44 -04:00
Trevor Buckner
d37fa03ec7 Merge pull request #3701 from naturalcrit/dependabot/npm_and_yarn/eslint-plugin-react-7.35.2 2024-09-04 17:21:33 -04:00
Trevor Buckner
2c7d39147d Merge branch 'master' into dependabot/npm_and_yarn/eslint-plugin-react-7.35.2 2024-09-04 17:20:58 -04:00
Trevor Buckner
6535e94ccd Merge pull request #3707 from naturalcrit/v3.15.0 2024-09-04 17:20:49 -04:00
Gazook89
49e072f03f Add button to toggle Preview tools
Toggles a state variable to either visible or hidden which is used to set a related class on the toolbar.  The hiding is done with CSS, just reducing the width of the toolbar and the opacity of the tools.
2024-09-04 13:54:55 -05:00
G.Ambatte
dd5d551c73 Merge branch 'master' into experimentalGitAttribs 2024-09-04 17:11:21 +12:00
G.Ambatte
aa90513825 Update gitattributes 2024-09-04 15:46:00 +12:00
dependabot[bot]
8f18601c2e Bump mongoose from 8.6.0 to 8.6.1
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.6.0 to 8.6.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.6.0...8.6.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-09-04 03:39:03 +00:00
dependabot[bot]
db02f88287 Bump eslint-plugin-react from 7.35.1 to 7.35.2
Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.35.1 to 7.35.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.35.1...v7.35.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-09-04 03:38:40 +00:00
David Bolack
6f837980eb All Snippet entries that have subsnippets but not generators. 2024-08-31 13:54:52 -05:00
David Bolack
82f2d0254f Merge branch 'master' into Issue_241_Part_II
Clean up a small bit of linting in the pr related functions.
2024-08-31 11:11:22 -05:00
David Bolack
5cf8715dea Merge branch 'master' into Issue_1958 2024-08-31 11:07:45 -05:00
Víctor Losada Hernández
849e5d5d1a Merge branch 'master' of https://github.com/naturalcrit/homebrewery into experimentalNotificationDB 2024-08-31 13:15:55 +02:00
Víctor Losada Hernández
188090ee45 revert themes.json 2024-08-31 13:15:11 +02:00
Víctor Losada Hernández
d352b76efe join styles and lint 2024-08-31 13:12:53 +02:00
Víctor Losada Hernández
e88272c684 "Refactor admin UI components: update class names, element types, and nesting in admin.jsx, notificationLookup.jsx, and notificationUtils.jsx" 2024-08-31 12:51:06 +02:00
Víctor Losada Hernández
10ce696333 basic styles 2024-08-31 12:50:53 +02:00
Víctor Losada Hernández
4488fe36db "Refactored notification lookup and management functionality in admin API and model, added new endpoints for getting all notifications and deleting a notification by dismiss key." 2024-08-31 12:17:12 +02:00
Víctor Losada Hernández
c79765396d add notif working 2024-08-31 00:04:44 +02:00
Víctor Losada Hernández
36549f3224 "Added 'required' attribute to several form input fields in NotificationAdd component." 2024-08-30 20:25:39 +02:00
David Bolack
2a366c3053 Update ToC Style snippets for better specificity 2024-08-29 17:51:59 -05:00
David Bolack
de8bd67e07 Add toggles for global Toc changes. 2024-08-29 17:44:45 -05:00
Víctor Losada Hernández
dcfc510ce8 more page sizes + more background options 2024-08-30 00:22:47 +02:00
Víctor Losada Hernández
e81a9dab1f add good stylings, and lint 2024-08-29 23:40:13 +02:00
Víctor Losada Hernández
65759e18bd clean inputs 2024-08-29 23:39:54 +02:00
G.Ambatte
f458b98dcf Merge branch 'master' into experimentalDeploymentIdentification 2024-08-29 21:31:55 +12:00
G.Ambatte
cc7fe99760 Initial functionality pass 2024-08-29 21:26:24 +12:00
Víctor Losada Hernández
78642e514d revert console log 2024-08-29 10:47:38 +02:00
Víctor Losada Hernández
4edbfa10b5 log config vars 2024-08-29 10:45:36 +02:00
David Bolack
03f8fc83ee Add snippets for page Numbering updates
Adds options to add skipCounting and ResetCounting classes
2024-08-28 21:33:32 -05:00
David Bolack
089dcb942b Merge branch 'master' into actualPageNumber 2024-08-28 21:23:22 -05:00
David Bolack
a4f30d687d Merge branch 'master' into Issue_241_Part_II 2024-08-28 21:17:10 -05:00
David Bolack
5e8f74b9bc Merge branch 'master' into Issue_1958 2024-08-28 21:09:07 -05:00
Víctor Losada Hernández
b39e8eea16 Merge branch 'experimentalNotificationDB' of https://github.com/G-Ambatte/homebrewery; branch 'master' of https://github.com/naturalcrit/homebrewery into experimentalNotificationDB 2024-08-29 00:24:22 +02:00
Víctor Losada Hernández
0c6c0c9fd6 use actual inputs and textarea with good attributes 2024-08-29 00:23:22 +02:00
Víctor Losada Hernández
51d3d11bff "Refactor notification utils components to use React Hooks instead of createClass" 2024-08-29 00:01:02 +02:00
Víctor Losada Hernández
46882c4fb4 add error logging on admin route 2024-08-29 00:00:55 +02:00
Víctor Losada Hernández
760c1a9e8c Merge branch 'master' of https://github.com/naturalcrit/homebrewery into experimentalNotificationDB 2024-08-28 22:28:24 +02:00
David Bolack
f24e47785c Merge branch 'master' into Issue_241_Part_II 2024-08-24 00:48:52 -05:00
David Bolack
e27e61aaca Bind livescrolling when done via scrollbars. 2024-08-24 00:47:06 -05:00
David Bolack
695293333f Fix merge 2024-08-21 21:19:10 -05:00
David Bolack
5431d3ed9b Merge branch 'master' into Issue_241_Part_II 2024-08-21 21:03:26 -05:00
David Bolack
fc9821a6c4 Merge branch 'master' into actualPageNumber 2024-08-21 20:55:21 -05:00
David Bolack
fa63f1d4d5 Merge branch 'master' into Issue_241_Part_II 2024-08-20 13:38:47 -05:00
David Bolack
a6969a9ce2 Merge branch 'master' into actualPageNumber 2024-08-20 13:38:26 -05:00
David Bolack
78c4061199 Merge branch 'master' into Issue_241_Part_II 2024-08-20 13:26:19 -05:00
David Bolack
1ad88c2fca Merge branch 'master' into actualPageNumber 2024-08-20 13:25:24 -05:00
David Bolack
51f758bf47 Rework page counters for skipping and resets.
Solves #513

This adds the .skipCounting and .resetCounting classes for causing
a page number to not be incremented or to reset the number at 1.

The ToC Snippet is corrected to match the displayed page numbers
while correctly tracking the page ids.
2024-08-15 17:15:49 -05:00
Víctor Losada Hernández
7b18c3ea0a Merge branch 'master' into metadata-api-endpoint 2024-08-15 17:35:51 +02:00
David Bolack
17b22b8afe Merge branch 'master' into Issue_241_Part_II 2024-08-15 09:41:03 -05:00
Víctor Losada Hernández
1c0bbc9390 linting 2024-08-14 20:05:28 +02:00
Víctor Losada Hernández
bf3c083e8c flow changed, flex added, elipsis added 2024-08-14 16:33:02 +02:00
Víctor Losada Hernández
031ed751d1 up less js 2024-08-14 16:30:33 +02:00
David Bolack
2d781f02e3 Merge branch 'master' into Issue_241_Part_II 2024-08-13 12:26:29 -05:00
David Bolack
baf201cc3a Merge branch 'master' into Issue_1958 2024-08-13 12:25:49 -05:00
David Bolack
0057e2b57e Merge branch 'master' into Issue_241_Part_II 2024-08-02 15:53:03 -05:00
David Bolack
e2ce1185b6 Merge branch 'master' into Issue_1958 2024-08-02 15:47:50 -05:00
Trevor Buckner
8983d74775 rebuild package lock again? 2024-08-01 21:30:09 -04:00
Trevor Buckner
f084c11936 Update package-lock.json 2024-08-01 21:26:04 -04:00
Víctor Losada Hernández
fa0d1d6bc1 Merge branch 'master' into metadata-api-endpoint 2024-08-01 23:44:00 +02:00
Trevor Buckner
a442817226 Re-build package-lock. 2024-08-01 17:43:54 -04:00
David Bolack
73e579703a Merge branch 'master' into Issue_1958 2024-08-01 11:19:17 -05:00
David Bolack
f10ef2bdb3 Merge branch 'master' into Issue_241_Part_II 2024-08-01 11:02:30 -05:00
David Bolack
b34027699f Move livescrollToggle function out into a class method instead of an anonymous function.
Adjust code accordingly ( event.target vs document.getElementByClassname )
2024-07-30 03:09:25 -05:00
David Bolack
dcdc8b4943 Remove Livescrolling toggle hot-key. 2024-07-30 02:41:03 -05:00
David Bolack
184462616f Merge branch 'master' into Issue_241_Part_II 2024-07-30 02:31:14 -05:00
Víctor Losada Hernández
df265ffc8a Merge branch 'master' of https://github.com/naturalcrit/homebrewery into metadata-api-endpoint 2024-07-19 08:59:04 +02:00
Víctor Losada Hernández
73a400b882 Merge branch 'metadata-api-endpoint' of https://github.com/naturalcrit/homebrewery into metadata-api-endpoint 2024-07-19 08:58:21 +02:00
Víctor Losada Hernández
bcef4006dc Remove console.log statement in /metadata/:id route handler 2024-07-19 08:58:19 +02:00
David Bolack
19ee3d6dbb Merge branch 'master' into Issue_241_Part_II 2024-07-08 10:14:43 -05:00
David Bolack
7e3f2a3deb Merge branch 'master' into Issue_241_Part_II 2024-06-27 10:24:48 -05:00
Víctor Losada Hernández
4680e7a5cc i messed up authentication entirely, this commit restores it 2024-06-16 17:21:55 +02:00
Víctor Losada Hernández
f07252d670 errors for access denied and authorization required 2024-06-16 17:14:27 +02:00
Víctor Losada Hernández
f15c831b70 proper error page 2024-06-16 17:06:18 +02:00
Víctor Losada Hernández
8c09772605 Merge branch 'master' into metadata-api-endpoint 2024-06-06 01:02:10 +02:00
David Bolack
510d8f410d Resolve timing issue with liveScroll on linking.
Checks to see if prevProps.livescroll has a proper Bool value. If not, do not brewJump() in editor.componantSDidUpdate.
2024-06-03 22:45:22 -05:00
David Bolack
ea9f9a8c36 Missed a couple of variable repalcements. 2024-06-03 02:39:20 -05:00
David Bolack
4818f70aed Add additional visual hinting to liveScroll lock. 2024-06-03 02:36:44 -05:00
David Bolack
cca79d4b17 Merge branch 'master' into Issue_241_Part_II 2024-06-03 02:29:19 -05:00
David Bolack
a715c9e1e6 Store livescrolling in local storage
Small fixes for loading the correct current state.
2024-06-03 02:26:56 -05:00
David Bolack
587831652c Merge branch 'master' into Issue_1958 2024-06-02 12:33:14 -05:00
Víctor Losada Hernández
6e0aff525f Updated rate limiter window name 2024-05-25 20:51:44 +02:00
Víctor Losada Hernández
748c25aae4 "Added express-rate-limit package and implemented rate limiting for admin API login attempts" 2024-05-24 20:42:25 +02:00
David Bolack
e69132b40a Constant a lookup. 2024-05-20 20:31:30 -05:00
David Bolack
77450ed334 Merge branch 'master' into Issue_241_Part_II 2024-05-20 20:03:23 -05:00
David Bolack
835ca0de32 WIP 2024-05-20 16:21:02 -05:00
David Bolack
f675fd130f Merge branch 'master' into Issue_1958 2024-05-20 13:36:41 -05:00
David Bolack
bacdd65025 Add a CR. 2024-05-19 11:52:16 -05:00
David Bolack
07f2e8ba4f Merge branch 'master' into Issue_241_Part_II 2024-05-19 11:20:09 -05:00
David Bolack
86887b536e Update Jump keys to match parent PR and shift live scrolling to scroll-lock.
Needs non-PC testing.
2024-05-19 11:16:50 -05:00
David Bolack
b7dc47fe9e Add a Live Scroll lock/unlock below Brew/Source Jump buttons.
The button displays the *next* state of the toggle. IE, if the current state is locked ( Live scrolling is active ) the icon is unlock with a corresponding mouse-over.

It may be desirable to invert this.
2024-05-18 22:17:29 -05:00
Víctor Losada Hernández
9343f11366 Merge branch 'master' into metadata-api-endpoint 2024-05-19 00:11:34 +02:00
David Bolack
8ece54701d Add live scrolling to keep the preview in sync with editor position.
This catchs CTRL-HOME, CTRL-END, and mouseclicks.

It tests for changes on arrow keys and enter.

Not sure if it's the best way to do this, but it works quickly on a large, crappy brew.
2024-05-18 01:44:42 -05:00
Víctor Losada Hernández
243038474e Initial commit 2024-05-17 21:23:31 +02:00
David Bolack
a69d251f53 Merge branch 'master' into Issue_1958 2024-05-12 10:37:20 -05:00
David Bolack
7ed48f3e70 Merge branch 'master' into Issue_1958 2024-03-09 20:12:03 -06:00
David Bolack
627b4ace0f Merge branch 'master' into Issue_1958 2024-03-06 23:42:11 -06:00
David Bolack
f2d5a8df99 Merge branch 'master' into Issue_1958 2024-03-04 11:45:53 -06:00
David Bolack
0d8026436c Merge branch 'master' into Issue_1958 2024-02-07 20:10:04 -06:00
David Bolack
8656feba44 Merge branch 'master' into Issue_1958 2024-01-25 00:18:47 -06:00
Trevor Buckner
e9a76dd018 Use existing dependency fs-extra instead of adding new one 2023-12-04 22:28:48 -05:00
Trevor Buckner
db0f75c852 Merge branch 'master' into pr/3132 2023-12-04 22:26:05 -05:00
David Bolack
0db6ffe340 Merge branch 'master' into Issue_1958 2023-11-10 23:23:55 -06:00
David Bolack
1b855108bf Correct omitted static path 2023-11-07 21:26:11 -06:00
David Bolack
ffe12ebee7 Add local statics for images and typefaces
This solves issue #1958.

Add static paths /staticImages and /staticFonts

If a local environment is detected ( per existing loginc for login )
paths are added using the values in HB_IMAGES and HB_FONTS or the default values of /staticImages and /staticFonts respectively.
2023-11-07 20:21:19 -06:00
G.Ambatte
e211b0858d Merge branch 'master' into experimentalNotificationDB 2023-08-28 07:51:31 +12:00
G.Ambatte
c8ac3f36fd Merge branch 'master' into experimentalNotificationDB 2023-07-16 09:41:05 +12:00
G.Ambatte
8c0cf4ccd4 Merge branch 'master' into experimentalNotificationDB 2023-07-06 17:55:00 +12:00
G.Ambatte
79eb4d8a9a Merge branch 'master' into experimentalNotificationDB 2023-06-10 14:27:49 +12:00
G.Ambatte
52d5d17561 Merge branch 'master' into experimentalNotificationDB 2023-03-24 07:56:24 +13:00
G.Ambatte
0fc3e03e95 Merge branch 'master' into experimentalNotificationDB 2023-03-12 22:30:53 +13:00
G.Ambatte
28cadcad06 Merge branch 'master' into experimentalNotificationDB 2023-02-22 16:14:19 +13:00
G.Ambatte
1fd8648602 Merge branch 'naturalcrit:master' into experimentalNotificationDB 2023-02-19 15:22:19 +13:00
G.Ambatte
66e10f3b4e Merge branch 'master' into experimentalNotificationDB 2023-02-14 13:00:02 +13:00
G.Ambatte
da0372e44c WIP commit 2023-01-23 15:18:50 +13:00
G.Ambatte
a4e6b2358a Merge branch 'master' into experimentalNotificationDB 2023-01-21 17:59:32 +13:00
G.Ambatte
24adbdc429 Change model to use defaults rather than mergeWith 2023-01-15 23:28:54 +13:00
G.Ambatte
ccd5cacb0c Stub notification deletion function 2023-01-15 23:25:17 +13:00
G.Ambatte
5e2171ceb1 Remove debugging console.log calls 2023-01-15 22:21:06 +13:00
G.Ambatte
b00a962e77 Fix typo 2023-01-15 20:44:41 +13:00
G.Ambatte
c518fc2d23 Merge branch 'naturalcrit:master' into experimentalNotificationDB 2023-01-15 13:55:25 +13:00
G.Ambatte
ca2582fdbd Merge branch 'experimentalNotificationDB' of https://github.com/G-Ambatte/homebrewery into experimentalNotificationDB 2023-01-15 13:54:28 +13:00
G.Ambatte
04916d8931 Initial notificationAdd functionality 2023-01-15 13:54:19 +13:00
G.Ambatte
f781c2bd56 Merge branch 'master' into experimentalNotificationDB 2023-01-07 10:29:54 +13:00
G.Ambatte
8adf5ce463 Add user-specified DismissKey to Add Notification 2023-01-06 13:53:16 +13:00
G.Ambatte
94afbe5417 Merge branch 'master' into experimentalNotificationDB 2023-01-06 13:51:37 +13:00
G.Ambatte
9e169aba91 Tweak LookUp title 2023-01-05 10:56:50 +13:00
G.Ambatte
f5c7761c61 Add styling to active tab 2023-01-05 10:52:24 +13:00
G.Ambatte
ec040cc2bb Add DisplayNames 2023-01-05 10:04:45 +13:00
G.Ambatte
42125f4041 Update Notification schema 2023-01-05 09:03:51 +13:00
G.Ambatte
a499bb3a54 Add basic Notification Lookup functionality 2023-01-04 23:32:35 +13:00
G.Ambatte
35b4c354f2 Add key prop to Admin tabs 2023-01-04 23:20:11 +13:00
G.Ambatte
b8fd8a7a86 Add Notification lookup to Admin API 2023-01-04 22:52:37 +13:00
G.Ambatte
620cb95ae8 Initial pass at Notification Mongoose model 2023-01-04 22:50:24 +13:00
G.Ambatte
f66664a3e2 Tabify Admin page, add Notification tab 2023-01-04 22:49:38 +13:00
G.Ambatte
d7ee004127 Update Admin pages 2023-01-04 22:08:44 +13:00
G.Ambatte
4a449c7895 Update Buffer method 2023-01-04 22:08:22 +13:00
72 changed files with 2798 additions and 1701 deletions

View File

@@ -10,7 +10,7 @@ orbs:
jobs:
build:
docker:
- image: cimg/node:20.8.0
- image: cimg/node:20.17.0
- image: mongo:4.4
working_directory: ~/homebrewery
@@ -27,7 +27,7 @@ jobs:
# fallback to using the latest cache if no exact match is found
- v1-dependencies-
- run: sudo npm install -g npm@10.2.0
- run: sudo npm install -g npm@10.8.2
- node/install-packages:
app-dir: ~/homebrewery
cache-path: node_modules
@@ -45,7 +45,7 @@ jobs:
test:
docker:
- image: cimg/node:20.8.0
- image: cimg/node:20.17.0
working_directory: ~/homebrewery
parallelism: 1

4
.gitattributes vendored
View File

@@ -1 +1,3 @@
package-lock.json binary
package-lock.json binary
*.json text eol=lf

36
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,36 @@
<!--
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
## Related Issues or Discussions
- 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._
### Reviewer Checklist
_Please 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
- [ ] Feature A does X
- [ ] Feature B does Y
- [ ] Verify old features have not broken
- [ ] Feature Z can still be used
- [ ] Test for edge cases / try to break things
- [ ] 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

@@ -2,35 +2,44 @@ require('./admin.less');
const React = require('react');
const createClass = require('create-react-class');
const BrewUtils = require('./brewUtils/brewUtils.jsx');
const NotificationUtils = require('./notificationUtils/notificationUtils.jsx');
const BrewCleanup = require('./brewCleanup/brewCleanup.jsx');
const BrewLookup = require('./brewLookup/brewLookup.jsx');
const BrewCompress = require ('./brewCompress/brewCompress.jsx');
const Stats = require('./stats/stats.jsx');
const tabGroups = ['brew', 'notifications'];
const Admin = createClass({
getDefaultProps : function() {
return {};
},
getInitialState : function(){
return ({
currentTab : 'brew'
});
},
handleClick : function(newTab){
if(this.state.currentTab === newTab) return;
this.setState({
currentTab : newTab
});
},
render : function(){
return <div className='admin'>
<header>
<div className='container'>
<i className='fas fa-rocket' />
homebrewery admin
</div>
</header>
<div className='container'>
<Stats />
<hr />
<BrewLookup />
<hr />
<BrewCleanup />
<hr />
<BrewCompress />
</div>
<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>; })}
</nav>
{this.state.currentTab==='brew' && <BrewUtils />}
{this.state.currentTab==='notifications' && <NotificationUtils />}
</main>
</div>;
}
});

View File

@@ -6,39 +6,95 @@
@import 'font-awesome/css/font-awesome.css';
html,body, #reactContainer, .naturalCrit{
min-height : 100%;
}
html,body, #reactContainer, .naturalCrit { min-height : 100%; }
@sidebarWidth : 250px;
body{
background-color : #eee;
font-family : 'Open Sans', sans-serif;
color : #4b5055;
font-weight : 100;
text-rendering : optimizeLegibility;
margin : 0;
body {
height : 100%;
padding : 0;
height : 100%;
margin : 0;
font-family : 'Open Sans', sans-serif;
font-weight : 100;
color : #4B5055;
background-color : #EEEEEE;
text-rendering : optimizeLegibility;
}
.admin{
:where(.admin) {
header{
header {
padding : 20px 0px;
margin-bottom : 30px;
font-size : 2em;
color : white;
background-color : @red;
font-size: 2em;
padding : 20px 0px;
color : white;
margin-bottom: 30px;
i{
margin-right: 30px;
i { margin-right : 30px; }
}
hr { margin : 30px 0px; }
:where(.container) {
input {
height : 33px;
padding : 0px 10px;
margin-bottom : 20px;
font-family : monospace;
}
button {
height : 37px;
vertical-align : middle;
}
dl {
@maxItemWidth : 132px;
dt {
float : left;
width : @maxItemWidth;
clear : left;
text-align : right;
&::after { content : ' : '; }
}
dd {
height : 1em;
padding : 0 0 0.5em 0;
margin-left : @maxItemWidth + 6px;
}
}
.tabs button {
margin-right : 3px;
margin-left : 3px;
color : black;
background-color : #EEEEEE;
border : 1px solid #444444;
border-radius : 5px;
&:hover {
color : #EEEEEE;
background-color : #444444;
}
&.active {
margin-right : 2px;
margin-left : 2px;
text-decoration : underline;
background-color : #CCCCCC;
border : 2px solid #444444;
}
}
.notificationUtils {
display : flex;
gap : 50px;
justify-content : space-between;
}
}
hr{
margin : 30px 0px;
.error {
background: rgb(178, 54, 54);
color:white;
font-weight: 900;
margin-block:10px;
padding:10px;
}
}

View File

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

View File

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

View File

@@ -1,30 +0,0 @@
.brewLookup{
input{
height : 33px;
margin-bottom : 20px;
padding : 0px 10px;
font-family : monospace;
}
button{
vertical-align : middle;
height : 37px;
}
dl{
@maxItemWidth : 132px;
dt{
float : left;
clear : left;
width : @maxItemWidth;
text-align : right;
&::after {
content: " : ";
}
}
dd{
height : 1em;
margin-left : @maxItemWidth + 6px;
padding : 0 0 0.5em 0;
}
}
}

View File

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

View File

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

View File

@@ -1,4 +1,3 @@
require('./brewLookup.less');
const React = require('react');
const createClass = require('create-react-class');
const cx = require('classnames');

View File

@@ -0,0 +1,24 @@
const React = require('react');
const createClass = require('create-react-class');
const BrewCleanup = require('./brewCleanup/brewCleanup.jsx');
const BrewLookup = require('./brewLookup/brewLookup.jsx');
const BrewCompress = require ('./brewCompress/brewCompress.jsx');
const Stats = require('./stats/stats.jsx');
const BrewUtils = createClass({
render : function(){
return <>
<Stats />
<hr />
<BrewLookup />
<hr />
<BrewCleanup />
<hr />
<BrewCompress />
</>;
}
});
module.exports = BrewUtils;

View File

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

View File

@@ -0,0 +1,109 @@
require('./notificationAdd.less');
const React = require('react');
const { useState, useRef } = require('react');
const request = require('superagent');
const NotificationAdd = ()=>{
const [notificationResult, setNotificationResult] = useState(null);
const [searching, setSearching] = useState(false);
const [error, setError] = useState(null);
const dismissKeyRef = useRef(null);
const titleRef = useRef(null);
const textRef = useRef(null);
const startAtRef = useRef(null);
const stopAtRef = useRef(null);
const saveNotification = async ()=>{
const dismissKey = dismissKeyRef.current.value;
const title = titleRef.current.value;
const text = textRef.current.value;
const startAt = new Date(startAtRef.current.value);
const stopAt = new Date(stopAtRef.current.value);
// Basic validation
if(!dismissKey || !title || !text || isNaN(startAt.getTime()) || isNaN(stopAt.getTime())) {
setError('All fields are required');
return;
}
if(startAt >= stopAt) {
setError('End date must be after the start date!');
return;
}
const data = {
dismissKey,
title,
text,
startAt : startAt?.toISOString() ?? '',
stopAt : stopAt?.toISOString() ?? '',
};
try {
setSearching(true);
setError(null);
const response = await request.post('/admin/notification/add').send(data);
console.log(response.body);
// Reset form fields
dismissKeyRef.current.value = '';
titleRef.current.value = '';
textRef.current.value = '';
setNotificationResult('Notification successfully created.');
setSearching(false);
} catch (err) {
console.log(err.response.body.message);
setError(`Error saving notification: ${err.response.body.message}`);
setSearching(false);
}
};
return (
<div className='notificationAdd'>
<h2>Add Notification</h2>
<label className='field'>
Dismiss Key:
<input className='fieldInput' type='text' ref={dismissKeyRef} required
placeholder='GOOGLEDRIVENOTIF'
/>
</label>
<label className='field'>
Title:
<input className='fieldInput' type='text' ref={titleRef} required
placeholder='Stop using Google Drive as image host'
/>
</label>
<label className='field'>
Text:
<textarea className='fieldInput' type='text' ref={textRef} required
placeholder='Google Drive is not an image hosting site, you should not use it as such.'
>
</textarea>
</label>
<label className='field'>
Start Date:
<input type='date' className='fieldInput' ref={startAtRef} required/>
</label>
<label className='field'>
End Date:
<input type='date' className='fieldInput' ref={stopAtRef} required/>
</label>
<div className='notificationResult'>{notificationResult}</div>
<button className='notificationSave' onClick={saveNotification} disabled={searching}>
<i className={`fas ${searching ? 'fa-spin fa-spinner' : 'fa-save'}`}/>
Save Notification
</button>
{error && <div className='error'>{error}</div>}
</div>
);
};
module.exports = NotificationAdd;

View File

@@ -0,0 +1,37 @@
.notificationAdd {
position : relative;
display : flex;
flex-direction : column;
width : 500px;
.field {
display : grid;
grid-template-columns : 120px 150px;
align-items : center;
justify-items : stretch;
width : 100%;
margin-bottom : 20px;
input {
height : 33px;
padding : 0px 10px;
margin-bottom : unset;
font-family : monospace;
}
textarea {
width : 50ch;
min-height : 7em;
max-height : 20em;
resize : vertical;
padding : 10px;
}
}
button {
width: 200px;
i { margin-right : 10px; }
}
}

View File

@@ -0,0 +1,105 @@
require('./notificationLookup.less');
const React = require('react');
const { useState } = require('react');
const request = require('superagent');
const Moment = require('moment');
const NotificationDetail = ({ notification, onDelete })=>(
<>
<dl>
<dt>Key</dt>
<dd>{notification.dismissKey}</dd>
<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>
<dt>Start</dt>
<dd>{Moment(notification.startAt).format('LLLL') || 'No Start Time'}</dd>
<dt>Stop</dt>
<dd>{Moment(notification.stopAt).format('LLLL') || 'No End Time'}</dd>
</dl>
<button onClick={()=>onDelete(notification.dismissKey)}>DELETE</button>
</>
);
const NotificationLookup = ()=>{
const [searching, setSearching] = useState(false);
const [error, setError] = useState(null);
const [notifications, setNotifications] = useState([]);
const lookupAll = async ()=>{
setSearching(true);
setError(null);
try {
const res = await request.get('/admin/notification/all');
setNotifications(res.body || []);
} catch (err) {
console.log(err);
setError(`Error looking up notifications: ${err.response.body.message}`);
} finally {
setSearching(false);
}
};
const deleteNotification = async (dismissKey)=>{
if(!dismissKey) return;
const confirmed = window.confirm(
`Really delete notification ${dismissKey}?`
);
if(!confirmed) {
console.log('Delete notification cancelled');
return;
}
console.log('Delete notification confirm');
try {
await request.delete(`/admin/notification/delete/${dismissKey}`);
lookupAll();
} catch (err) {
console.log(err);
setError(`Error deleting notification: ${err.response.body.message}`);
};
};
const renderNotificationsList = ()=>{
if(error)
return <div className='error'>{error}</div>;
if(notifications.length === 0)
return <div className='noNotification'>No notifications available.</div>;
return (
<ul className='notificationList'>
{notifications.map((notification)=>(
<li key={notification.dismissKey} >
<details>
<summary>{notification.title || 'No Title'}</summary>
<NotificationDetail notification={notification} onDelete={deleteNotification} />
</details>
</li>
))}
</ul>
);
};
return (
<div className='notificationLookup'>
<h2>Check all Notifications</h2>
<button onClick={lookupAll}>
<i className={`fas ${searching ? 'fa-spin fa-spinner' : 'fa-search'}`} />
</button>
{renderNotificationsList()}
</div>
);
};
module.exports = NotificationLookup;

View File

@@ -0,0 +1,40 @@
.notificationLookup {
width : 450px;
height : fit-content;
.notificationList {
display : flex;
flex-direction : column;
max-height : 500px;
margin-block : 20px;
overflow : auto;
border : 1px solid;
border-radius : 5px;
li {
padding : 10px;
background : #CCCCCC;
&:nth-child(even) { background : #DDDDDD; }
&:first-child {
border-top-left-radius : 5px;
border-top-right-radius : 5px;
}
&:last-child {
border-bottom-right-radius : 5px;
border-bottom-left-radius : 5px;
}
summary {
font-size : 20px;
font-weight : 900;
}
dl dt{
font-weight: 900;
}
}
}
.noNotification { margin-block : 20px; }
}

View File

@@ -0,0 +1,15 @@
const React = require('react');
const NotificationLookup = require('./notificationLookup/notificationLookup.jsx');
const NotificationAdd = require('./notificationAdd/notificationAdd.jsx');
const NotificationUtils = ()=>{
return (
<section className='notificationUtils'>
<NotificationAdd />
<NotificationLookup />
</section>
);
};
module.exports = NotificationUtils;

View File

@@ -1,28 +0,0 @@
.Stats{
position : relative;
.pending{
position : absolute;
top : 0px;
left : 0px;
height : 100%;
width : 100%;
background-color : rgba(238,238,238, 0.5);
}
dl{
@maxItemWidth : 132px;
dt{
float : left;
clear : left;
width : @maxItemWidth;
text-align : right;
&::after {
content: " : ";
}
}
dd{
margin : 0 0 0 @maxItemWidth + 10px;
padding : 0 0 0.5em 0;
}
}
}

View File

@@ -1,7 +1,7 @@
/*eslint max-lines: ["warn", {"max": 300, "skipBlankLines": true, "skipComments": true}]*/
require('./brewRenderer.less');
const React = require('react');
const { useState, useRef, useEffect } = React;
const { useState, useRef, useCallback } = React;
const _ = require('lodash');
const MarkdownLegacy = require('naturalcrit/markdownLegacy.js');
@@ -49,23 +49,24 @@ let rawPages = [];
const BrewRenderer = (props)=>{
props = {
text : '',
style : '',
renderer : 'legacy',
theme : '5ePHB',
lang : '',
errors : [],
currentEditorPage : 0,
themeBundle : {},
text : '',
style : '',
renderer : 'legacy',
theme : '5ePHB',
lang : '',
errors : [],
currentEditorCursorPageNum : 1,
currentEditorViewPageNum : 1,
currentBrewRendererPageNum : 1,
themeBundle : {},
onPageChange : ()=>{},
...props
};
const [state, setState] = useState({
height : PAGE_HEIGHT,
isMounted : false,
visibility : 'hidden',
zoom : 100,
currentPageNumber : 1,
isMounted : false,
visibility : 'hidden',
zoom : 100
});
const mainRef = useRef(null);
@@ -76,36 +77,22 @@ const BrewRenderer = (props)=>{
rawPages = props.text.split(/^\\page$/gm);
}
useEffect(()=>{ // Unmounting steps
return ()=>{window.removeEventListener('resize', updateSize);};
}, []);
const updateSize = ()=>{
setState((prevState)=>({
...prevState,
height : mainRef.current.parentNode.clientHeight,
}));
};
const getCurrentPage = (e)=>{
const updateCurrentPage = useCallback(_.throttle((e)=>{
const { scrollTop, clientHeight, scrollHeight } = e.target;
const totalScrollableHeight = scrollHeight - clientHeight;
const currentPageNumber = Math.ceil((scrollTop / totalScrollableHeight) * rawPages.length);
const currentPageNumber = Math.max(Math.ceil((scrollTop / totalScrollableHeight) * rawPages.length), 1);
setState((prevState)=>({
...prevState,
currentPageNumber : currentPageNumber || 1
}));
};
props.onPageChange(currentPageNumber);
}, 200), []);
const isInView = (index)=>{
if(!state.isMounted)
return false;
if(index == props.currentEditorPage) //Already rendered before this step
if(index == props.currentEditorCursorPageNum - 1) //Already rendered before this step
return false;
if(Math.abs(index - state.currentPageNumber) <= 3)
if(Math.abs(index - props.currentBrewRendererPageNum - 1) <= 3)
return true;
return false;
@@ -142,7 +129,7 @@ const BrewRenderer = (props)=>{
renderedPages.length = 0;
// Render currently-edited page first so cross-page effects (variables, links) can propagate out first
renderedPages[props.currentEditorPage] = renderPage(rawPages[props.currentEditorPage], props.currentEditorPage);
renderedPages[props.currentEditorCursorPageNum - 1] = renderPage(rawPages[props.currentEditorCursorPageNum - 1], props.currentEditorCursorPageNum - 1);
_.forEach(rawPages, (page, index)=>{
if((isInView(index) || !renderedPages[index]) && typeof window !== 'undefined'){
@@ -164,8 +151,6 @@ const BrewRenderer = (props)=>{
const frameDidMount = ()=>{ //This triggers when iFrame finishes internal "componentDidMount"
setTimeout(()=>{ //We still see a flicker where the style isn't applied yet, so wait 100ms before showing iFrame
updateSize();
window.addEventListener('resize', updateSize);
renderPages(); //Make sure page is renderable before showing
setState((prevState)=>({
...prevState,
@@ -188,11 +173,17 @@ const BrewRenderer = (props)=>{
}));
};
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>")`;
}
return (
<>
{/*render dummy page while iFrame is mounting.*/}
{!state.isMounted
? <div className='brewRenderer' onScroll={getCurrentPage}>
? <div className='brewRenderer' onScroll={updateCurrentPage}>
<div className='pages'>
{renderDummyPage(1)}
</div>
@@ -205,7 +196,7 @@ const BrewRenderer = (props)=>{
<NotificationPopup />
</div>
<ToolBar onZoomChange={handleZoom} currentPage={state.currentPageNumber} totalPages={rawPages.length}/>
<ToolBar onZoomChange={handleZoom} currentPage={props.currentBrewRendererPageNum} totalPages={rawPages.length}/>
{/*render in iFrame so broken code doesn't crash the site.*/}
<Frame id='BrewRenderer' initialContent={INITIAL_CONTENT}
@@ -213,11 +204,11 @@ const BrewRenderer = (props)=>{
contentDidMount={frameDidMount}
onClick={()=>{emitClick();}}
>
<div className={'brewRenderer'}
onScroll={getCurrentPage}
<div className={`brewRenderer ${global.config.deployment && 'deployment'}`}
onScroll={updateCurrentPage}
onKeyDown={handleControlKeys}
tabIndex={-1}
style={{ height: state.height }}>
style={ styleObject }>
{/* Apply CSS from Style tab and render pages from Markdown tab */}
{state.isMounted

View File

@@ -4,6 +4,10 @@
overflow-y : scroll;
will-change : transform;
padding-top : 30px;
height : 100vh;
&.deployment {
background-color: darkred;
}
:where(.pages) {
margin : 30px 0px;
& > :where(.page) {
@@ -39,6 +43,7 @@
overflow-y : unset;
.pages {
margin : 0px;
zoom: 100% !important;
& > .page { box-shadow : unset; }
}
}

View File

@@ -4,7 +4,7 @@ const _ = require('lodash');
import Dialog from '../../../components/dialog.jsx';
const DISMISS_KEY = 'dismiss_notification04-09-24';
const DISMISS_KEY = 'dismiss_notification01-10-24';
const DISMISS_BUTTON = <i className='fas fa-times dismiss' />;
const NotificationPopup = ()=>{
@@ -17,7 +17,7 @@ const NotificationPopup = ()=>{
<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!
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.

View File

@@ -11,6 +11,7 @@ const ToolBar = ({ onZoomChange, currentPage, onPageChange, totalPages })=>{
const [zoomLevel, setZoomLevel] = useState(100);
const [pageNum, setPageNum] = useState(currentPage);
const [toolsVisible, setToolsVisible] = useState(true);
useEffect(()=>{
onZoomChange(zoomLevel);
@@ -55,7 +56,7 @@ const ToolBar = ({ onZoomChange, currentPage, onPageChange, totalPages })=>{
} else if(mode == 'fit'){
// find the page with the largest single dim (height or width) so that zoom can be adapted to fit it.
const minDimRatio = [...pages].reduce((minRatio, page) => Math.min(minRatio, iframeWidth / page.offsetWidth, iframeHeight / page.offsetHeight), Infinity);
const minDimRatio = [...pages].reduce((minRatio, page)=>Math.min(minRatio, iframeWidth / page.offsetWidth, iframeHeight / page.offsetHeight), Infinity);
desiredZoom = minDimRatio * 100;
}
@@ -67,7 +68,8 @@ const ToolBar = ({ onZoomChange, currentPage, onPageChange, totalPages })=>{
};
return (
<div className='toolBar'>
<div className={`toolBar ${toolsVisible ? 'visible' : 'hidden'}`}>
<button className='toggleButton' title={`${toolsVisible ? 'Hide' : 'Show'} Preview Toolbar`} onClick={()=>{setToolsVisible(!toolsVisible);}}><i className='fas fa-glasses' /></button>
{/*v=====----------------------< Zoom Controls >---------------------=====v*/}
<div className='group'>
<button

View File

@@ -15,6 +15,10 @@
font-family : 'Open Sans', sans-serif;
color : #CCCCCC;
background-color : #555555;
& > *:not(.toggleButton) {
opacity: 1;
transition: all .2s ease;
}
.group {
box-sizing : border-box;
@@ -100,4 +104,25 @@
font-size:1.2em;
}
}
&.hidden {
width: 32px;
transition: all .3s ease;
flex-wrap:nowrap;
overflow: hidden;
background-color: unset;
opacity: .5;
& > *:not(.toggleButton) {
opacity: 0;
transition: all .2s ease;
}
}
}
button.toggleButton {
z-index : 5;
position:absolute;
left: 0;
width: 32px;
min-width: unset;
}

View File

@@ -1,9 +1,8 @@
/*eslint max-lines: ["warn", {"max": 300, "skipBlankLines": true, "skipComments": true}]*/
/*eslint max-lines: ["warn", {"max": 500, "skipBlankLines": true, "skipComments": true}]*/
require('./editor.less');
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
const dedent = require('dedent-tabs').default;
const Markdown = require('../../../shared/naturalcrit/markdown.js');
@@ -22,6 +21,7 @@ const DEFAULT_STYLE_TEXT = dedent`
color: black;
}`;
let isJumping = false;
const Editor = createClass({
displayName : 'Editor',
@@ -37,8 +37,15 @@ const Editor = createClass({
onMetaChange : ()=>{},
reportError : ()=>{},
onCursorPageChange : ()=>{},
onViewPageChange : ()=>{},
editorTheme : 'default',
renderer : 'legacy'
renderer : 'legacy',
currentEditorCursorPageNum : 1,
currentEditorViewPageNum : 1,
currentBrewRendererPageNum : 1,
};
},
getInitialState : function() {
@@ -56,12 +63,16 @@ const Editor = createClass({
isMeta : function() {return this.state.view == 'meta';},
componentDidMount : function() {
this.updateEditorSize();
this.highlightCustomMarkdown();
window.addEventListener('resize', this.updateEditorSize);
document.getElementById('BrewRenderer').addEventListener('keydown', this.handleControlKeys);
document.addEventListener('keydown', this.handleControlKeys);
this.codeEditor.current.codeMirror.on('cursorActivity', (cm)=>{this.updateCurrentCursorPage(cm.getCursor());});
this.codeEditor.current.codeMirror.on('scroll', _.throttle(()=>{this.updateCurrentViewPage(this.codeEditor.current.getTopVisibleLine());}, 200));
const editorTheme = window.localStorage.getItem(EDITOR_THEME_KEY);
if(editorTheme) {
this.setState({
@@ -75,28 +86,37 @@ const Editor = createClass({
},
componentDidUpdate : function(prevProps, prevState, snapshot) {
this.highlightCustomMarkdown();
if(prevProps.moveBrew !== this.props.moveBrew) {
if(prevProps.moveBrew !== this.props.moveBrew)
this.brewJump();
};
if(prevProps.moveSource !== this.props.moveSource) {
if(prevProps.moveSource !== this.props.moveSource)
this.sourceJump();
};
if(this.props.liveScroll) {
if(prevProps.currentBrewRendererPageNum !== this.props.currentBrewRendererPageNum) {
this.sourceJump(this.props.currentBrewRendererPageNum, false);
} else if(prevProps.currentEditorViewPageNum !== this.props.currentEditorViewPageNum) {
this.brewJump(this.props.currentEditorViewPageNum, false);
} else if(prevProps.currentEditorCursorPageNum !== this.props.currentEditorCursorPageNum) {
this.brewJump(this.props.currentEditorCursorPageNum, false);
}
}
},
handleControlKeys : function(e){
if(!(e.ctrlKey && e.metaKey)) return;
if(!(e.ctrlKey && e.metaKey && e.shiftKey)) return;
const LEFTARROW_KEY = 37;
const RIGHTARROW_KEY = 39;
if (e.shiftKey && (e.keyCode == RIGHTARROW_KEY)) this.brewJump();
if (e.shiftKey && (e.keyCode == LEFTARROW_KEY)) this.sourceJump();
if ((e.keyCode == LEFTARROW_KEY) || (e.keyCode == RIGHTARROW_KEY)) {
if(e.keyCode == RIGHTARROW_KEY) this.brewJump();
if(e.keyCode == LEFTARROW_KEY) this.sourceJump();
if(e.keyCode == LEFTARROW_KEY || e.keyCode == RIGHTARROW_KEY) {
e.stopPropagation();
e.preventDefault();
}
},
updateEditorSize : function() {
if(this.codeEditor.current) {
let paneHeight = this.editor.current.parentNode.clientHeight;
@@ -105,6 +125,20 @@ 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 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 currentPage = lines.reduce((count, line)=>count + (pageRegex.test(line) ? 1 : 0), 1);
this.props.onViewPageChange(currentPage);
},
handleInject : function(injectText){
this.codeEditor.current?.injectText(injectText, false);
},
@@ -119,18 +153,6 @@ const Editor = createClass({
}); //TODO: not sure if updateeditorsize needed
},
getCurrentPage : function(){
const lines = this.props.brew.text.split('\n').slice(0, this.codeEditor.current.getCursorPosition().line + 1);
return _.reduce(lines, (r, line)=>{
if(
(this.props.renderer == 'legacy' && line.indexOf('\\page') !== -1)
||
(this.props.renderer == 'V3' && line.match(/^\\page$/))
) r++;
return r;
}, 1);
},
highlightCustomMarkdown : function(){
if(!this.codeEditor.current) return;
if(this.state.view === 'text') {
@@ -139,13 +161,13 @@ const Editor = createClass({
codeMirror.operation(()=>{ // Batch CodeMirror styling
const foldLines = [];
//reset custom text styles
const customHighlights = codeMirror.getAllMarks().filter((mark)=>{
// Record details of folded sections
if(mark.__isFold) {
const fold = mark.find();
foldLines.push({from: fold.from?.line, to: fold.to?.line});
foldLines.push({ from: fold.from?.line, to: fold.to?.line });
}
return !mark.__isFold;
}); //Don't undo code folding
@@ -163,7 +185,7 @@ const Editor = createClass({
// Don't process lines inside folded text
// If the current lineNumber is inside any folded marks, skip line styling
if (foldLines.some(fold => lineNumber >= fold.from && lineNumber <= fold.to))
if(foldLines.some((fold)=>lineNumber >= fold.from && lineNumber <= fold.to))
return;
// Styling for \page breaks
@@ -189,7 +211,7 @@ const Editor = createClass({
// definition lists
if(line.includes('::')){
if(/^:*$/.test(line) == true){ return };
if(/^:*$/.test(line) == true){ return; };
const regex = /^([^\n]*?:?\s?)(::[^\n]*)(?:\n|$)/ymd; // the `d` flag, for match indices, throws an ESLint error.
let match;
while ((match = regex.exec(line)) != null){
@@ -197,10 +219,10 @@ const Editor = createClass({
codeMirror.markText({ line: lineNumber, ch: match.indices[1][0] }, { line: lineNumber, ch: match.indices[1][1] }, { className: 'dt-highlight' });
codeMirror.markText({ line: lineNumber, ch: match.indices[2][0] }, { line: lineNumber, ch: match.indices[2][1] }, { className: 'dd-highlight' });
const ddIndex = match.indices[2][0];
let colons = /::/g;
let colonMatches = colons.exec(match[2]);
const colons = /::/g;
const colonMatches = colons.exec(match[2]);
if(colonMatches !== null){
codeMirror.markText({ line: lineNumber, ch: colonMatches.index + ddIndex }, { line: lineNumber, ch: colonMatches.index + colonMatches[0].length + ddIndex }, { className: 'dl-colon-highlight'} )
codeMirror.markText({ line: lineNumber, ch: colonMatches.index + ddIndex }, { line: lineNumber, ch: colonMatches.index + colonMatches[0].length + ddIndex }, { className: 'dl-colon-highlight' });
}
}
}
@@ -210,12 +232,12 @@ const Editor = createClass({
let startIndex = line.indexOf('^');
const superRegex = /\^(?!\s)(?=([^\n\^]*[^\s\^]))\1\^/gy;
const subRegex = /\^\^(?!\s)(?=([^\n\^]*[^\s\^]))\1\^\^/gy;
while (startIndex >= 0) {
superRegex.lastIndex = subRegex.lastIndex = startIndex;
let isSuper = false;
let match = subRegex.exec(line) || superRegex.exec(line);
if (match) {
const match = subRegex.exec(line) || superRegex.exec(line);
if(match) {
isSuper = !subRegex.lastIndex;
codeMirror.markText({ line: lineNumber, ch: match.index }, { line: lineNumber, ch: match.index + match[0].length }, { className: isSuper ? 'superscript' : 'subscript' });
}
@@ -265,18 +287,18 @@ const Editor = createClass({
while (startIndex >= 0) {
emojiRegex.lastIndex = startIndex;
let match = emojiRegex.exec(line);
if (match) {
const match = emojiRegex.exec(line);
if(match) {
let tokens = Markdown.marked.lexer(match[0]);
tokens = tokens[0].tokens.filter(t => t.type == 'emoji')
if (!tokens.length)
tokens = tokens[0].tokens.filter((t)=>t.type == 'emoji');
if(!tokens.length)
return;
let startPos = { line: lineNumber, ch: match.index };
let endPos = { line: lineNumber, ch: match.index + match[0].length };
const startPos = { line: lineNumber, ch: match.index };
const endPos = { line: lineNumber, ch: match.index + match[0].length };
// Iterate over conflicting marks and clear them
var marks = codeMirror.findMarks(startPos, endPos);
const marks = codeMirror.findMarks(startPos, endPos);
marks.forEach(function(marker) {
if(!marker.__isFold) marker.clear();
});
@@ -291,75 +313,93 @@ const Editor = createClass({
}
},
brewJump : function(targetPage=this.getCurrentPage()){
if(!window) return;
// console.log(`Scroll to: p${targetPage}`);
brewJump : function(targetPage=this.props.currentEditorCursorPageNum, smooth=true){
if(!window || isJumping)
return;
// Get current brewRenderer scroll position and calculate target position
const brewRenderer = window.frames['BrewRenderer'].contentDocument.getElementsByClassName('brewRenderer')[0];
const currentPos = brewRenderer.scrollTop;
const targetPos = window.frames['BrewRenderer'].contentDocument.getElementById(`p${targetPage}`).getBoundingClientRect().top;
const interimPos = targetPos >= 0 ? -30 : 30;
const bounceDelay = 100;
const scrollDelay = 500;
if(!this.throttleBrewMove) {
this.throttleBrewMove = _.throttle((currentPos, interimPos, targetPos)=>{
brewRenderer.scrollTo({ top: currentPos + interimPos, behavior: 'smooth' });
setTimeout(()=>{
brewRenderer.scrollTo({ top: currentPos + targetPos, behavior: 'smooth', block: 'start' });
}, bounceDelay);
}, scrollDelay, { leading: true, trailing: false });
const checkIfScrollComplete = ()=>{
let scrollingTimeout;
clearTimeout(scrollingTimeout); // Reset the timer every time a scroll event occurs
scrollingTimeout = setTimeout(()=>{
isJumping = false;
brewRenderer.removeEventListener('scroll', checkIfScrollComplete);
}, 150); // If 150 ms pass without a brewRenderer scroll event, assume scrolling is done
};
this.throttleBrewMove(currentPos, interimPos, targetPos);
// const hashPage = (page != 1) ? `p${page}` : '';
// window.location.hash = hashPage;
isJumping = true;
checkIfScrollComplete();
brewRenderer.addEventListener('scroll', checkIfScrollComplete);
if(smooth) {
const bouncePos = targetPos >= 0 ? -30 : 30; //Do a little bounce before scrolling
const bounceDelay = 100;
const scrollDelay = 500;
if(!this.throttleBrewMove) {
this.throttleBrewMove = _.throttle((currentPos, bouncePos, targetPos)=>{
brewRenderer.scrollTo({ top: currentPos + bouncePos, behavior: 'smooth' });
setTimeout(()=>{
brewRenderer.scrollTo({ top: currentPos + targetPos, behavior: 'smooth', block: 'start' });
}, bounceDelay);
}, scrollDelay, { leading: true, trailing: false });
};
this.throttleBrewMove(currentPos, bouncePos, targetPos);
} else {
brewRenderer.scrollTo({ top: currentPos + targetPos, behavior: 'instant', block: 'start' });
}
},
sourceJump : function(targetLine=null){
if(this.isText()) {
if(targetLine == null) {
targetLine = 0;
sourceJump : function(targetPage=this.props.currentBrewRendererPageNum, smooth=true){
if(!this.isText || isJumping)
return;
const pageCollection = window.frames['BrewRenderer'].contentDocument.getElementsByClassName('page');
const brewRendererHeight = window.frames['BrewRenderer'].contentDocument.getElementsByClassName('brewRenderer').item(0).getBoundingClientRect().height;
const textSplit = this.props.renderer == 'V3' ? /^\\page$/gm : /\\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;
let currentPage = 1;
for (const page of pageCollection) {
if(page.getBoundingClientRect().bottom > (brewRendererHeight / 2)) {
currentPage = parseInt(page.id.slice(1)) || 1;
break;
}
let currentY = this.codeEditor.current.codeMirror.getScrollInfo().top;
let targetY = this.codeEditor.current.codeMirror.heightAtLine(targetLine, 'local', true);
const checkIfScrollComplete = ()=>{
let scrollingTimeout;
clearTimeout(scrollingTimeout); // Reset the timer every time a scroll event occurs
scrollingTimeout = setTimeout(()=>{
isJumping = false;
this.codeEditor.current.codeMirror.off('scroll', checkIfScrollComplete);
}, 150); // If 150 ms pass without a scroll event, assume scrolling is done
};
isJumping = true;
checkIfScrollComplete();
this.codeEditor.current.codeMirror.on('scroll', checkIfScrollComplete);
if(smooth) {
//Scroll 1/10 of the way every 10ms until 1px off.
const incrementalScroll = setInterval(()=>{
currentY += (targetY - currentY) / 10;
this.codeEditor.current.codeMirror.scrollTo(null, currentY);
// Update target: target height is not accurate until within +-10 lines of the visible window
if(Math.abs(targetY - currentY > 100))
targetY = this.codeEditor.current.codeMirror.heightAtLine(targetLine, 'local', true);
// End when close enough
if(Math.abs(targetY - currentY) < 1) {
this.codeEditor.current.codeMirror.scrollTo(null, targetY); // Scroll any remaining difference
this.codeEditor.current.setCursorPosition({ line: targetLine + 1, ch: 0 });
this.codeEditor.current.codeMirror.addLineClass(targetLine + 1, 'wrap', 'sourceMoveFlash');
clearInterval(incrementalScroll);
}
const textSplit = this.props.renderer == 'V3' ? /^\\page$/gm : /\\page/;
const textString = this.props.brew.text.split(textSplit).slice(0, currentPage-1).join(textSplit);
const textPosition = textString.length;
const lineCount = textString.match('\n') ? textString.slice(0, textPosition).split('\n').length : 0;
targetLine = lineCount - 1; //Scroll to `\page`, which is one line back.
let currentY = this.codeEditor.current.codeMirror.getScrollInfo().top;
let targetY = this.codeEditor.current.codeMirror.heightAtLine(targetLine, 'local', true);
//Scroll 1/10 of the way every 10ms until 1px off.
const incrementalScroll = setInterval(()=>{
currentY += (targetY - currentY) / 10;
this.codeEditor.current.codeMirror.scrollTo(null, currentY);
// Update target: target height is not accurate until within +-10 lines of the visible window
if(Math.abs(targetY - currentY > 100))
targetY = this.codeEditor.current.codeMirror.heightAtLine(targetLine, 'local', true);
// End when close enough
if(Math.abs(targetY - currentY) < 1) {
this.codeEditor.current.codeMirror.scrollTo(null, targetY); // Scroll any remaining difference
this.codeEditor.current.setCursorPosition({ line: targetLine + 1, ch: 0 });
this.codeEditor.current.codeMirror.addLineClass(targetLine + 1, 'wrap', 'sourceMoveFlash');
clearInterval(incrementalScroll);
}
}, 10);
}
}, 10);
} else {
this.codeEditor.current.codeMirror.scrollTo(null, targetY); // Scroll any remaining difference
this.codeEditor.current.setCursorPosition({ line: targetLine + 1, ch: 0 });
this.codeEditor.current.codeMirror.addLineClass(targetLine + 1, 'wrap', 'sourceMoveFlash');
}
},
@@ -460,7 +500,9 @@ const Editor = createClass({
currentEditorTheme={this.state.editorTheme}
updateEditorTheme={this.updateEditorTheme}
snippetBundle={this.props.snippetBundle}
cursorPos={this.codeEditor.current?.getCursorPosition() || {}} />
cursorPos={this.codeEditor.current?.getCursorPosition() || {}}
updateBrew={this.props.updateBrew}
/>
{this.renderEditor()}
</div>

View File

@@ -304,17 +304,14 @@ const MetadataEditor = createClass({
onChange={(e)=>this.handleRenderer('V3', e)} />
V3
</label>
<a href='/legacy' target='_blank' rel='noopener noreferrer'>
Click here to see the demo page for the old Legacy renderer!
</a>
<small><a href='/legacy' target='_blank' rel='noopener noreferrer'>Click here to see the demo page for the old Legacy renderer!</a></small>
</div>
</div>;
},
render : function(){
return <div className='metadataEditor'>
<h1 className='sectionHead'>Brew</h1>
<h1>Properties Editor</h1>
<div className='field title'>
<label>title</label>
@@ -362,9 +359,7 @@ const MetadataEditor = createClass({
{this.renderRenderOptions()}
<hr/>
<h1 className='sectionHead'>Authors</h1>
<h2>Authors</h2>
{this.renderAuthors()}
@@ -375,15 +370,13 @@ const MetadataEditor = createClass({
notes={['Invited author usernames are case sensitive.', 'After adding an invited author, send them the edit link. There, they can choose to accept or decline the invitation.']}
onChange={(e)=>this.handleFieldChange('invitedAuthors', e)}/>
<hr/>
<h1 className='sectionHead'>Privacy</h1>
<h2>Privacy</h2>
<div className='field publish'>
<label>publish</label>
<div className='value'>
{this.renderPublish()}
<small>Published homebrews will be publicly viewable and searchable (eventually...)</small>
<small>Published brews are searchable in <a href='/vault'>the Vault</a> and visible on your user page. Unpublished brews are not indexed in the Vault or visible on your user page, but can still be shared and indexed by search engines. You can unpublish a brew any time.</small>
</div>
</div>

View File

@@ -1,5 +1,6 @@
@import 'naturalcrit/styles/colors.less';
.metadataEditor {
position : absolute;
z-index : 5;
@@ -9,12 +10,19 @@
padding : 25px;
overflow-y : auto;
background-color : #999999;
font-size : 13px;
.sectionHead {
h1 {
margin: 0 0 40px;
font-weight: bold;
text-transform: uppercase;
}
h2 {
margin : 20px 0;
font-weight : 1000;
&:first-of-type { margin-top : 0; }
font-weight : bold;
border-bottom: 2px solid gray;
color: #555;
}
& > div { margin-bottom : 10px; }
@@ -43,15 +51,21 @@
min-width : 200px;
& > label {
width : 80px;
font-size : 11px;
font-weight : 800;
line-height : 1.8em;
text-transform : uppercase;
font-size: .9em;
}
& > .value {
flex : 1 1 auto;
width : 50px;
&:invalid { background : #FFB9B9; }
small {
display : block;
font-size : 0.9em;
font-style : italic;
line-height : 1.4em;
}
}
input[type='text'], textarea {
border : 1px solid gray;
@@ -78,7 +92,6 @@
textarea.value {
height : auto;
font-family : 'Open Sans', sans-serif;
font-size : 0.8em;
resize : none;
}
}
@@ -87,12 +100,6 @@
z-index : 200;
max-width : 150px;
}
small {
display : inline-block;
font-size : 0.6em;
font-style : italic;
line-height : 1.4em;
}
}
@@ -113,18 +120,13 @@
display : inline-flex;
align-items : center;
margin-right : 15px;
font-size : 0.7em;
font-size : 0.9em;
font-weight : 800;
white-space : nowrap;
vertical-align : middle;
cursor : pointer;
user-select : none;
}
a {
display : inline-flex;
font-size : 0.7em;
font-weight : 800;
}
input {
margin : 3px;
vertical-align : middle;
@@ -149,12 +151,10 @@
}
}
.authors.field .value {
font-size : 0.8em;
line-height : 1.5em;
}
.themes.field {
font-size : 13.33px;
.navDropdownContainer {
position : relative;
z-index : 100;
@@ -165,9 +165,9 @@
background-color : darkgray;
}
& > div:first-child {
padding : 6px 3px;
padding : 3px 3px;
background-color : inherit;
border : 2px solid rgb(118,118,118);
border : 1px solid gray;
i { float : right; }
&:hover {
color : white;
@@ -240,6 +240,7 @@
}
}
}
.field .list {
display : flex;
flex : 1 0;
@@ -258,15 +259,15 @@
color : white;
text-align : center;
cursor : pointer;
i {
position : relative;
top : 50%;
transform : translateY(-50%);
}
&:not(:last-child) { border-right : 1px solid black; }
&:last-child { border-radius : 0 0.5em 0.5em 0; }
}
@@ -277,8 +278,7 @@
background-color : #DDDDDD;
border-radius : 0.5em;
.icon {
#groupedIcon; }
.icon { #groupedIcon; }
}
.input-group {
@@ -294,17 +294,30 @@
height : 100%;
}
.invalid:focus { background-color : pink; }
.input-group {
height : ~'calc(.9em + 4px + .6em)';
.icon {
#groupedIcon;
top : -0.54em;
right : 1px;
height : 97%;
font-size : 0.8em;
input { border-radius : 0.5em 0 0 0.5em; }
i { font-size : 1.125em; }
input:last-child { border-radius : 0.5em; }
.value {
width : 7.5vw;
min-width : 75px;
height : 100%;
}
.invalid:focus { background-color : pink; }
.icon {
#groupedIcon;
top : -0.54em;
right : 1px;
height : 97%;
i { font-size : 1.125em; }
}
}
}
}
}
}

View File

@@ -1,10 +1,12 @@
/*eslint max-lines: ["warn", {"max": 250, "skipBlankLines": true, "skipComments": true}]*/
/*eslint max-lines: ["warn", {"max": 350, "skipBlankLines": true, "skipComments": true}]*/
require('./snippetbar.less');
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
import { loadHistory } from '../../utils/versionHistory.js';
//Import all themes
const ThemeSnippets = {};
ThemeSnippets['Legacy_5ePHB'] = require('themes/Legacy/5ePHB/snippets.js');
@@ -38,7 +40,8 @@ const Snippetbar = createClass({
unfoldCode : ()=>{},
updateEditorTheme : ()=>{},
cursorPos : {},
snippetBundle : []
snippetBundle : [],
updateBrew : ()=>{}
};
},
@@ -46,31 +49,54 @@ const Snippetbar = createClass({
return {
renderer : this.props.renderer,
themeSelector : false,
snippets : []
snippets : [],
showHistory : false,
historyExists : false,
historyItems : []
};
},
componentDidMount : async function() {
componentDidMount : async function(prevState) {
const snippets = this.compileSnippets();
this.setState({
snippets : snippets
});
},
componentDidUpdate : async function(prevProps) {
componentDidUpdate : async function(prevProps, prevState) {
if(prevProps.renderer != this.props.renderer || prevProps.theme != this.props.theme || prevProps.snippetBundle != this.props.snippetBundle) {
const snippets = this.compileSnippets();
this.setState({
snippets : snippets
snippets : this.compileSnippets()
});
};
// Update history list if it has changed
const checkHistoryItems = await loadHistory(this.props.brew);
// If all items have the noData property, there is no saved data
const checkHistoryExists = !checkHistoryItems.every((historyItem)=>{
return historyItem?.noData;
});
if(prevState.historyExists != checkHistoryExists){
this.setState({
historyExists : checkHistoryExists
});
}
// If any history items have changed, update the list
if(checkHistoryExists && checkHistoryItems.some((historyItem, index)=>{
return index >= prevState.historyItems.length || !_.isEqual(historyItem, prevState.historyItems[index]);
})){
this.setState({
historyItems : checkHistoryItems
});
}
},
mergeCustomizer : function(oldValue, newValue, key) {
if(key == 'snippets') {
const result = _.reverse(_.unionBy(_.reverse(newValue), _.reverse(oldValue), 'name')); // Join snippets together, with preference for the child theme over the parent theme
return _.filter(result, 'gen'); //Only keep snippets with a 'gen' property.
return result.filter((snip)=>snip.gen || snip.subsnippets);
}
},
@@ -138,6 +164,42 @@ const Snippetbar = createClass({
});
},
replaceContent : function(item){
return this.props.updateBrew(item);
},
toggleHistoryMenu : function(){
this.setState({
showHistory : !this.state.showHistory
});
},
renderHistoryItems : function() {
if(!this.state.historyExists) return;
return <div className='dropdown'>
{_.map(this.state.historyItems, (item, index)=>{
if(item.noData || !item.savedAt) return;
const saveTime = new Date(item.savedAt);
const diffMs = new Date() - saveTime;
const diffSecs = Math.floor(diffMs / 1000);
let diffString = `about ${diffSecs} seconds ago`;
if(diffSecs > 60) diffString = `about ${Math.floor(diffSecs / 60)} minutes ago`;
if(diffSecs > (60 * 60)) diffString = `about ${Math.floor(diffSecs / (60 * 60))} hours ago`;
if(diffSecs > (24 * 60 * 60)) diffString = `about ${Math.floor(diffSecs / (24 * 60 * 60))} days ago`;
if(diffSecs > (7 * 24 * 60 * 60)) diffString = `about ${Math.floor(diffSecs / (7 * 24 * 60 * 60))} weeks ago`;
return <div className='snippet' key={index} onClick={()=>{this.replaceContent(item);}} >
<i className={`fas fa-${index+1}`} />
<span className='name' title={saveTime.toISOString()}>v{item.version} : {diffString}</span>
</div>;
})}
</div>;
},
renderEditorButtons : function(){
if(!this.props.showEditButtons) return;
@@ -158,6 +220,11 @@ const Snippetbar = createClass({
}
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' />

View File

@@ -53,6 +53,21 @@
font-size : 0.75em;
color : inherit;
}
&.history {
.tooltipLeft('History');
font-size : 0.75em;
color : grey;
position : relative;
&.active {
color : inherit;
}
&>.dropdown{
right : -1px;
&>.snippet{
padding-right : 10px;
}
}
}
&.editorTheme {
.tooltipLeft('Editor Themes');
font-size : 0.75em;

View File

@@ -128,7 +128,7 @@ const StringArrayEditor = createClass({
return <div className='field'>
<label>{this.props.label}</label>
<div style={{ flex: '1 0' }}>
<div style={{ flex: '1 0' }} className='value'>
<div className='list'>
{valueElements}
<div className='input-group'>

View File

@@ -1,34 +0,0 @@
const React = require('react');
const createClass = require('create-react-class');
const cx = require('classnames');
const Nav = require('naturalcrit/nav/nav.jsx');
const MAX_TITLE_LENGTH = 50;
const EditTitle = createClass({
displayName : 'EditTitleNavItem',
getDefaultProps : function() {
return {
title : '',
onChange : function(){}
};
},
handleChange : function(e){
if(e.target.value.length > MAX_TITLE_LENGTH) return;
this.props.onChange(e.target.value);
},
render : function(){
return <Nav.item className='editTitle'>
<input placeholder='Brew Title' type='text' value={this.props.title} onChange={this.handleChange} />
<div className={cx('charCount', { 'max': this.props.title.length >= MAX_TITLE_LENGTH })}>
{this.props.title.length}/{MAX_TITLE_LENGTH}
</div>
</Nav.item>;
},
});
module.exports = EditTitle;

View File

@@ -111,7 +111,7 @@ const ErrorNavItem = createClass({
Looks like there was a problem retreiving
the theme, or a theme that it inherits,
for this brew. Verify that brew <a className='lowercase' target='_blank' rel='noopener noreferrer' href={`/share/${response.body.brewId}`}>
{response.body.brewId}</a> still exists!
{response.body.brewId}</a> still exists!
</div>
</Nav.item>;
}

View File

@@ -35,6 +35,11 @@
display : flex;
align-items : center;
&:last-child .navItem { border-left : 1px solid #666666; }
&:has(.brewTitle) {
flex-grow : 1;
min-width : 300px;
}
}
// "NaturalCrit" logo
.navLogo {
@@ -69,6 +74,10 @@
.navItem {
#backgroundColorsHover;
.animate(background-color);
display : flex;
align-items : center;
justify-content : center;
height : 100%;
padding : 8px 12px;
font-size : 10px;
font-weight : 800;
@@ -94,39 +103,20 @@
animation-duration : 2s;
}
}
&.editTitle { // this is not needed at all currently - you used to be able to edit the title via the navbar.
padding : 2px 12px;
input {
width : 250px;
padding : 2px;
margin : 0;
font-family : 'Open Sans', sans-serif;
font-size : 12px;
font-weight : 800;
color : white;
text-align : center;
background-color : transparent;
border : 1px solid @blue;
outline : none;
}
.charCount {
display : inline-block;
margin-left : 8px;
color : #666666;
text-align : right;
vertical-align : bottom;
&.max { color : @red; }
}
}
&.brewTitle {
flex-grow : 1;
display : block;
width : 100%;
overflow : hidden;
font-size : 12px;
font-weight : 800;
color : white;
text-align : center;
text-transform : initial;
background-color : transparent;
text-overflow : ellipsis;
text-transform : initial;
white-space : nowrap;
background-color : transparent;
}
// "The Homebrewery" logo
&.homebrewLogo {
.animate(color);
@@ -240,23 +230,25 @@
}
.navDropdownContainer {
position : relative;
height : 100%;
.navDropdown {
position: absolute;
top: 28px;
right: 0px;
z-index: 10000;
width: max-content;
min-width:100%;
max-height: calc(100vh - 28px);
overflow: hidden auto;
display: flex;
flex-direction: column;
align-items: flex-end;
position : absolute;
//top: 28px;
right : 0px;
z-index : 10000;
display : flex;
flex-direction : column;
align-items : flex-end;
width : max-content;
min-width : 100%;
max-height : calc(100vh - 28px);
overflow : hidden auto;
.navItem {
position : relative;
display : flex;
justify-content : space-between;
align-items : center;
justify-content : space-between;
width : 100%;
border : 1px solid #888888;
border-bottom : 0;
@@ -278,10 +270,10 @@
overflow : hidden auto;
color : white;
text-decoration : none;
background-color : #333333;
border-top : 1px solid #888888;
scrollbar-color : #666666 #333333;
scrollbar-width : thin;
background-color : #333333;
border-top : 1px solid #888888;
.clear {
position : absolute;
top : 50%;

View File

@@ -36,7 +36,7 @@ const RecentItems = createClass({
//== Add current brew to appropriate recent items list (depending on storageKey) ==//
if(this.props.storageKey == 'edit'){
let editId = this.props.brew.editId;
if(this.props.brew.googleId){
if(this.props.brew.googleId && !this.props.brew.stubbed){
editId = `${this.props.brew.googleId}${this.props.brew.editId}`;
}
edited = _.filter(edited, (brew)=>{
@@ -51,7 +51,7 @@ const RecentItems = createClass({
}
if(this.props.storageKey == 'view'){
let shareId = this.props.brew.shareId;
if(this.props.brew.googleId){
if(this.props.brew.googleId && !this.props.brew.stubbed){
shareId = `${this.props.brew.googleId}${this.props.brew.shareId}`;
}
viewed = _.filter(viewed, (brew)=>{
@@ -83,7 +83,7 @@ const RecentItems = createClass({
let edited = JSON.parse(localStorage.getItem(EDIT_KEY) || '[]');
if(this.props.storageKey == 'edit') {
let prevEditId = prevProps.brew.editId;
if(prevProps.brew.googleId){
if(prevProps.brew.googleId && !this.props.brew.stubbed){
prevEditId = `${prevProps.brew.googleId}${prevProps.brew.editId}`;
}
@@ -91,7 +91,7 @@ const RecentItems = createClass({
return brew.id !== prevEditId;
});
let editId = this.props.brew.editId;
if(this.props.brew.googleId){
if(this.props.brew.googleId && !this.props.brew.stubbed){
editId = `${this.props.brew.googleId}${this.props.brew.editId}`;
}
edited.unshift({

View File

@@ -1,44 +0,0 @@
const React = require('react');
const createClass = require('create-react-class');
const Nav = require('naturalcrit/nav/nav.jsx');
const MAIN_URL = 'https://www.reddit.com/r/UnearthedArcana/submit?selftext=true';
const RedditShare = createClass({
displayName : 'RedditShareNavItem',
getDefaultProps : function() {
return {
brew : {
title : '',
sharedId : '',
text : ''
}
};
},
getText : function(){
},
handleClick : function(){
const url = [
MAIN_URL,
`title=${encodeURIComponent(this.props.brew.title ? this.props.brew.title : 'Check out my brew!')}`,
`text=${encodeURIComponent(this.props.brew.text)}`
].join('&');
window.open(url, '_blank');
},
render : function(){
return <Nav.item icon='fa-reddit-alien' color='red' onClick={this.handleClick}>
share on reddit
</Nav.item>;
},
});
module.exports = RedditShare;

View File

@@ -1,8 +1,9 @@
/* eslint-disable max-lines */
require('./editPage.less');
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const createClass = require('create-react-class');
const request = require('../../utils/request-middleware.js');
const { Meta } = require('vitreum/headtags');
@@ -27,9 +28,11 @@ const Markdown = require('naturalcrit/markdown.js');
const { DEFAULT_BREW_LOAD } = require('../../../../server/brewDefaults.js');
const { printCurrentBrew, fetchThemeBundle } = require('../../../../shared/helpers.js');
import { updateHistory, versionHistoryGarbageCollection } from '../../utils/versionHistory.js';
const googleDriveIcon = require('../../googleDrive.svg');
const SAVE_TIMEOUT = 3000;
const SAVE_TIMEOUT = 10000;
const EditPage = createClass({
displayName : 'EditPage',
@@ -41,22 +44,24 @@ const EditPage = createClass({
getInitialState : function() {
return {
brew : this.props.brew,
isSaving : false,
isPending : false,
alertTrashedGoogleBrew : this.props.brew.trashed,
alertLoginToTransfer : false,
saveGoogle : this.props.brew.googleId ? true : false,
confirmGoogleTransfer : false,
error : null,
htmlErrors : Markdown.validate(this.props.brew.text),
url : '',
autoSave : true,
autoSaveWarning : false,
unsavedTime : new Date(),
currentEditorPage : 0,
displayLockMessage : this.props.brew.lock || false,
themeBundle : {}
brew : this.props.brew,
isSaving : false,
isPending : false,
alertTrashedGoogleBrew : this.props.brew.trashed,
alertLoginToTransfer : false,
saveGoogle : this.props.brew.googleId ? true : false,
confirmGoogleTransfer : false,
error : null,
htmlErrors : Markdown.validate(this.props.brew.text),
url : '',
autoSave : true,
autoSaveWarning : false,
unsavedTime : new Date(),
currentEditorViewPageNum : 1,
currentEditorCursorPageNum : 1,
currentBrewRendererPageNum : 1,
displayLockMessage : this.props.brew.lock || false,
themeBundle : {}
};
},
@@ -113,16 +118,27 @@ const EditPage = createClass({
this.editor.current.update();
},
handleEditorViewPageChange : function(pageNumber){
this.setState({ currentEditorViewPageNum: pageNumber });
},
handleEditorCursorPageChange : function(pageNumber){
this.setState({ currentEditorCursorPageNum: pageNumber });
},
handleBrewRendererPageChange : function(pageNumber){
this.setState({ currentBrewRendererPageNum: pageNumber });
},
handleTextChange : function(text){
//If there are errors, run the validator on every change to give quick feedback
let htmlErrors = this.state.htmlErrors;
if(htmlErrors.length) htmlErrors = Markdown.validate(text);
this.setState((prevState)=>({
brew : { ...prevState.brew, text: text },
isPending : true,
htmlErrors : htmlErrors,
currentEditorPage : this.editor.current.getCurrentPage() - 1 //Offset index since Marked starts pages at 0
brew : { ...prevState.brew, text: text },
isPending : true,
htmlErrors : htmlErrors,
}), ()=>{if(this.state.autoSave) this.trySave();});
},
@@ -150,6 +166,16 @@ const EditPage = createClass({
return !_.isEqual(this.state.brew, this.savedBrew);
},
updateBrew : function(newData){
this.setState((prevState)=>({
brew : {
...prevState.brew,
style : newData.style,
text : newData.text
}
}));
},
trySave : function(immediate=false){
if(!this.debounceSave) this.debounceSave = _.debounce(this.save, SAVE_TIMEOUT);
if(this.hasChanges()){
@@ -202,6 +228,9 @@ const EditPage = createClass({
htmlErrors : Markdown.validate(prevState.brew.text)
}));
await updateHistory(this.state.brew);
await versionHistoryGarbageCollection();
const transfer = this.state.saveGoogle == _.isNil(this.state.brew.googleId);
const brew = this.state.brew;
@@ -413,6 +442,12 @@ const EditPage = createClass({
renderer={this.state.brew.renderer}
userThemes={this.props.userThemes}
snippetBundle={this.state.themeBundle.snippets}
updateBrew={this.updateBrew}
onCursorPageChange={this.handleEditorCursorPageChange}
onViewPageChange={this.handleEditorViewPageChange}
currentEditorViewPageNum={this.state.currentEditorViewPageNum}
currentEditorCursorPageNum={this.state.currentEditorCursorPageNum}
currentBrewRendererPageNum={this.state.currentBrewRendererPageNum}
/>
<BrewRenderer
text={this.state.brew.text}
@@ -422,7 +457,10 @@ const EditPage = createClass({
themeBundle={this.state.themeBundle}
errors={this.state.htmlErrors}
lang={this.state.brew.lang}
currentEditorPage={this.state.currentEditorPage}
onPageChange={this.handleBrewRendererPageChange}
currentEditorViewPageNum={this.state.currentEditorViewPageNum}
currentEditorCursorPageNum={this.state.currentEditorCursorPageNum}
currentBrewRendererPageNum={this.state.currentBrewRendererPageNum}
allowPrint={true}
/>
</SplitPane>

View File

@@ -172,6 +172,11 @@ const errorIndex = (props)=>{
**Brew Title:** ${props.brew.brewTitle}`,
// ####### Admin page error #######
'52': dedent`
## Access Denied
You need to provide correct administrator credentials to access this page.`,
'90' : dedent` An unexpected error occurred while looking for these brews.
Try again in a few minutes.`,

View File

@@ -1,7 +1,6 @@
require('./homePage.less');
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
const request = require('../../utils/request-middleware.js');
const { Meta } = require('vitreum/headtags');
@@ -32,11 +31,13 @@ const HomePage = createClass({
},
getInitialState : function() {
return {
brew : this.props.brew,
welcomeText : this.props.brew.text,
error : undefined,
currentEditorPage : 0,
themeBundle : {}
brew : this.props.brew,
welcomeText : this.props.brew.text,
error : undefined,
currentEditorViewPageNum : 1,
currentEditorCursorPageNum : 1,
currentBrewRendererPageNum : 1,
themeBundle : {}
};
},
@@ -61,10 +62,22 @@ const HomePage = createClass({
handleSplitMove : function(){
this.editor.current.update();
},
handleEditorViewPageChange : function(pageNumber){
this.setState({ currentEditorViewPageNum: pageNumber });
},
handleEditorCursorPageChange : function(pageNumber){
this.setState({ currentEditorCursorPageNum: pageNumber });
},
handleBrewRendererPageChange : function(pageNumber){
this.setState({ currentBrewRendererPageNum: pageNumber });
},
handleTextChange : function(text){
this.setState((prevState)=>({
brew : { ...prevState.brew, text: text },
currentEditorPage : this.editor.current.getCurrentPage() - 1 //Offset index since Marked starts pages at 0
brew : { ...prevState.brew, text: text },
}));
},
renderNavbar : function(){
@@ -97,12 +110,20 @@ const HomePage = createClass({
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}
currentEditorPage={this.state.currentEditorPage}
onPageChange={this.handleBrewRendererPageChange}
currentEditorViewPageNum={this.state.currentEditorViewPageNum}
currentEditorCursorPageNum={this.state.currentEditorCursorPageNum}
currentBrewRendererPageNum={this.state.currentBrewRendererPageNum}
themeBundle={this.state.themeBundle}
/>
</SplitPane>

View File

@@ -39,13 +39,15 @@ const NewPage = createClass({
const brew = this.props.brew;
return {
brew : brew,
isSaving : false,
saveGoogle : (global.account && global.account.googleId ? true : false),
error : null,
htmlErrors : Markdown.validate(brew.text),
currentEditorPage : 0,
themeBundle : {}
brew : brew,
isSaving : false,
saveGoogle : (global.account && global.account.googleId ? true : false),
error : null,
htmlErrors : Markdown.validate(brew.text),
currentEditorViewPageNum : 1,
currentEditorCursorPageNum : 1,
currentBrewRendererPageNum : 1,
themeBundle : {}
};
},
@@ -108,15 +110,26 @@ const NewPage = createClass({
this.editor.current.update();
},
handleEditorViewPageChange : function(pageNumber){
this.setState({ currentEditorViewPageNum: pageNumber });
},
handleEditorCursorPageChange : function(pageNumber){
this.setState({ currentEditorCursorPageNum: pageNumber });
},
handleBrewRendererPageChange : function(pageNumber){
this.setState({ currentBrewRendererPageNum: pageNumber });
},
handleTextChange : function(text){
//If there are errors, run the validator on every change to give quick feedback
let htmlErrors = this.state.htmlErrors;
if(htmlErrors.length) htmlErrors = Markdown.validate(text);
this.setState((prevState)=>({
brew : { ...prevState.brew, text: text },
htmlErrors : htmlErrors,
currentEditorPage : this.editor.current.getCurrentPage() - 1 //Offset index since Marked starts pages at 0
brew : { ...prevState.brew, text: text },
htmlErrors : htmlErrors,
}));
localStorage.setItem(BREWKEY, text);
},
@@ -221,6 +234,11 @@ const NewPage = createClass({
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}
@@ -230,7 +248,10 @@ const NewPage = createClass({
themeBundle={this.state.themeBundle}
errors={this.state.htmlErrors}
lang={this.state.brew.lang}
currentEditorPage={this.state.currentEditorPage}
onPageChange={this.handleBrewRendererPageChange}
currentEditorViewPageNum={this.state.currentEditorViewPageNum}
currentEditorCursorPageNum={this.state.currentEditorCursorPageNum}
currentBrewRendererPageNum={this.state.currentBrewRendererPageNum}
allowPrint={true}
/>
</SplitPane>

View File

@@ -25,7 +25,8 @@ const SharePage = createClass({
getInitialState : function() {
return {
themeBundle : {}
themeBundle : {},
currentBrewRendererPageNum : 1
};
},
@@ -39,6 +40,10 @@ const SharePage = createClass({
document.removeEventListener('keydown', this.handleControlKeys);
},
handleBrewRendererPageChange : function(pageNumber){
this.setState({ currentBrewRendererPageNum: pageNumber });
},
handleControlKeys : function(e){
if(!(e.ctrlKey || e.metaKey)) return;
const P_KEY = 80;
@@ -114,9 +119,12 @@ const SharePage = createClass({
<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}
allowPrint={true}
/>
</div>

View File

@@ -1,3 +1,5 @@
/*eslint max-lines: ["warn", {"max": 400, "skipBlankLines": true, "skipComments": true}]*/
/*eslint max-params:["warn", { max: 10 }], */
require('./vaultPage.less');
const React = require('react');
@@ -18,13 +20,15 @@ const request = require('../../utils/request-middleware.js');
const VaultPage = (props)=>{
const [pageState, setPageState] = useState(parseInt(props.query.page) || 1);
const [sortState, setSort] = useState(props.query.sort || 'title');
const [dirState, setdir] = useState(props.query.dir || 'asc');
//Response state
const [brewCollection, setBrewCollection] = useState(null);
const [totalBrews, setTotalBrews] = useState(null);
const [searching, setSearching] = useState(false);
const [error, setError] = useState(null);
const titleRef = useRef(null);
const authorRef = useRef(null);
const countRef = useRef(null);
@@ -34,7 +38,7 @@ const VaultPage = (props)=>{
useEffect(()=>{
disableSubmitIfFormInvalid();
loadPage(pageState, true);
loadPage(pageState, true, props.query.sort, props.query.dir);
}, []);
const updateStateWithBrews = (brews, page)=>{
@@ -43,7 +47,7 @@ const VaultPage = (props)=>{
setSearching(false);
};
const updateUrl = (titleValue, authorValue, countValue, v3Value, legacyValue, page)=>{
const updateUrl = (titleValue, authorValue, countValue, v3Value, legacyValue, page, sort, dir)=>{
const url = new URL(window.location.href);
const urlParams = new URLSearchParams(url.search);
@@ -53,21 +57,23 @@ const VaultPage = (props)=>{
urlParams.set('v3', v3Value);
urlParams.set('legacy', legacyValue);
urlParams.set('page', page);
urlParams.set('sort', sort);
urlParams.set('dir', dir);
url.search = urlParams.toString();
window.history.replaceState(null, '', url.toString());
};
const performSearch = async (title, author, count, v3, legacy, page)=>{
updateUrl(title, author, count, v3, legacy, page);
const performSearch = async (title, author, count, v3, legacy, page, sort, dir)=>{
updateUrl(title, author, count, v3, legacy, page, sort, dir);
const response = await request.get(
`/api/vault?title=${title}&author=${author}&v3=${v3}&legacy=${legacy}&count=${count}&page=${page}`
).catch((error)=>{
console.log('error at loadPage: ', error);
setError(error);
updateStateWithBrews([], 1);
});
const response = await request
.get(`/api/vault?title=${title}&author=${author}&v3=${v3}&legacy=${legacy}&count=${count}&page=${page}&sort=${sort}&dir=${dir}`)
.catch((error)=>{
console.log('error at loadPage: ', error);
setError(error);
updateStateWithBrews([], 1);
});
if(response.ok)
updateStateWithBrews(response.body.brews, page);
@@ -76,9 +82,8 @@ const VaultPage = (props)=>{
const loadTotal = async (title, author, v3, legacy)=>{
setTotalBrews(null);
const response = await request.get(
`/api/vault/total?title=${title}&author=${author}&v3=${v3}&legacy=${legacy}`
).catch((error)=>{
const response = await request.get(`/api/vault/total?title=${title}&author=${author}&v3=${v3}&legacy=${legacy}`)
.catch((error)=>{
console.log('error at loadTotal: ', error);
setError(error);
updateStateWithBrews([], 1);
@@ -88,9 +93,8 @@ const VaultPage = (props)=>{
setTotalBrews(response.body.totalBrews);
};
const loadPage = async (page, updateTotal)=>{
if(!validateForm())
return;
const loadPage = async (page, updateTotal, sort, dir)=>{
if(!validateForm()) return;
setSearching(true);
setError(null);
@@ -100,8 +104,14 @@ const VaultPage = (props)=>{
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;
performSearch(title, author, count, v3, legacy, page);
setSort(sortOption);
setdir(dirOption);
performSearch(title, author, count, v3, legacy, pageProp, sortOption, dirOption);
if(updateTotal)
loadTotal(title, author, v3, legacy);
@@ -248,6 +258,33 @@ const VaultPage = (props)=>{
</div>
);
const renderSortOption = (optionTitle, optionValue)=>{
const oppositeDir = dirState === 'asc' ? 'desc' : 'asc';
return (
<div className={`sort-option ${sortState === optionValue ? `active` : ''}`}>
<button onClick={()=>loadPage(1, false, optionValue, oppositeDir)}>
{optionTitle}
</button>
{sortState === optionValue && (
<i className={`sortDir fas ${dirState === 'asc' ? 'fa-sort-up' : 'fa-sort-down'}`} />
)}
</div>
);
};
const renderSortBar = ()=>{
return (
<div className='sort-container'>
{renderSortOption('Title', 'title', props.query.dir)}
{renderSortOption('Created Date', 'createdAt', props.query.dir)}
{renderSortOption('Updated Date', 'updatedAt', props.query.dir)}
{renderSortOption('Views', 'views', props.query.dir)}
</div>
);
};
const renderPaginationControls = ()=>{
if(!totalBrews) return null;
@@ -271,10 +308,8 @@ const VaultPage = (props)=>{
.map((_, index)=>(
<a
key={startPage + index}
className={`pageNumber ${
pageState === startPage + index ? 'currentPage' : ''
}`}
onClick={()=>loadPage(startPage + index, false)}
className={`pageNumber ${pageState === startPage + index ? 'currentPage' : ''}`}
onClick={()=>loadPage(startPage + index, false, sortState, dirState)}
>
{startPage + index}
</a>
@@ -284,7 +319,7 @@ const VaultPage = (props)=>{
<div className='paginationControls'>
<button
className='previousPage'
onClick={()=>loadPage(pageState - 1, false)}
onClick={()=>loadPage(pageState - 1, false, sortState, dirState)}
disabled={pageState === startPage}
>
<i className='fa-solid fa-chevron-left'></i>
@@ -293,7 +328,7 @@ const VaultPage = (props)=>{
{startPage > 1 && (
<a
className='pageNumber firstPage'
onClick={()=>loadPage(1, false)}
onClick={()=>loadPage(1, false, sortState, dirState)}
>
1 ...
</a>
@@ -302,7 +337,7 @@ const VaultPage = (props)=>{
{endPage < totalPages && (
<a
className='pageNumber lastPage'
onClick={()=>loadPage(totalPages, false)}
onClick={()=>loadPage(totalPages, false, sortState, dirState)}
>
... {totalPages}
</a>
@@ -310,7 +345,7 @@ const VaultPage = (props)=>{
</ol>
<button
className='nextPage'
onClick={()=>loadPage(pageState + 1, false)}
onClick={()=>loadPage(pageState + 1, false, sortState, dirState)}
disabled={pageState === totalPages}
>
<i className='fa-solid fa-chevron-right'></i>
@@ -330,7 +365,7 @@ const VaultPage = (props)=>{
if(error) {
const errorText = ErrorIndex()[error.HBErrorCode.toString()] || '';
return (
<div className='foundBrews noBrews'>
<h3>Error: {errorText}</h3>
@@ -385,6 +420,7 @@ const VaultPage = (props)=>{
<div className='form dataGroup'>{renderForm()}</div>
<div className='resultsContainer dataGroup'>
{renderSortBar()}
{renderFoundBrews()}
</div>
</SplitPane>

View File

@@ -1,31 +1,12 @@
body {
height : 100vh;
.content { height : 100%; }
small {
font-size : 10pt;
color : #555555;
a { color : #333333; }
}
code {
padding-inline : 5px;
background : lightgrey;
border-radius : 5px;
}
*:not(input) { user-select : none; }
}
.vaultPage {
height : 100%;
overflow-y : hidden;
background-color : #2C3E50;
*:not(input) { user-select : none; }
.content {
height : 100%;
background : #2C3E50;
.dataGroup {
@@ -37,11 +18,24 @@ body {
position : relative;
padding : 50px clamp(20px, 4vw, 50px);
small {
font-size : 10pt;
color : #555555;
a { color : #333333; }
}
code {
padding-inline : 5px;
font-family : monospace;
background : lightgrey;
border-radius : 5px;
}
h1, h2, h3, h4 {
font-family : 'CodeBold';
letter-spacing : 2px;
}
legend {
h3 {
@@ -144,8 +138,6 @@ body {
}
}
#searchButton {
position : absolute;
right : 20px;
@@ -166,7 +158,6 @@ body {
overflow-y : auto;
font-family : 'BookInsanityRemake';
font-size : 0.34cm;
h3 {
font-family : 'Open Sans';
@@ -174,6 +165,48 @@ body {
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; }
}
}
button {
padding : 0;
font-size : 11px;
font-weight : normal;
color : #CCCCCC;
text-transform : uppercase;
background-color : transparent;
&:hover { background : none; }
}
}
}
.foundBrews {
position : relative;
width : 100%;
@@ -245,15 +278,15 @@ body {
width : 47%;
margin-right : 40px;
color : black;
isolation:isolate;
isolation : isolate;
&:after {
position:absolute;
inset:0;
display:block;
content:'';
&::after {
position : absolute;
inset : 0;
z-index : -2;
display : block;
content : '';
background-image : url('/assets/parchmentBackground.jpg');
z-index:-1;
}
&:nth-child(even of .brewItem) { margin-right : 0; }
@@ -266,28 +299,24 @@ body {
color : var(--HB_Color_HeaderText);
}
.info {
position : relative;
z-index : 2;
font-family : 'ScalySansRemake';
font-size : 1.2em;
position:relative;
z-index:2;
>span {
margin-right : 12px;
line-height : 1.5em;
}
}
.links {
z-index:2;
}
.links { z-index : 2; }
hr {
margin: 0px;
visibility: hidden;
margin : 0px;
visibility : hidden;
}
.thumbnail {
z-index:1;
}
.thumbnail { z-index : -1; }
}
.paginationControls {

View File

@@ -0,0 +1,119 @@
import * as IDB from 'idb-keyval/dist/index.js';
export const HISTORY_PREFIX = 'HOMEBREWERY-HISTORY';
export const HISTORY_SLOTS = 5;
// History values in minutes
const HISTORY_SAVE_DELAYS = {
'0' : 0,
'1' : 2,
'2' : 10,
'3' : 60,
'4' : 12 * 60,
'5' : 2 * 24 * 60
};
// const HISTORY_SAVE_DELAYS = {
// '0' : 0,
// '1' : 1,
// '2' : 2,
// '3' : 3,
// '4' : 4,
// '5' : 5
// };
const HB_DB = 'HOMEBREWERY-DB';
const HB_STORE = 'HISTORY';
const GARBAGE_COLLECT_DELAY = 28 * 24 * 60;
// const GARBAGE_COLLECT_DELAY = 10;
function getKeyBySlot(brew, slot){
// Return a string representing the key for this brew and history slot
return `${HISTORY_PREFIX}-${brew.shareId}-${slot}`;
};
function parseBrewForStorage(brew, slot = 0) {
// Strip out unneeded object properties
// Returns an array of [ key, brew ]
const archiveBrew = {
title : brew.title,
text : brew.text,
style : brew.style,
version : brew.version,
shareId : brew.shareId,
savedAt : brew?.savedAt || new Date(),
expireAt : new Date()
};
archiveBrew.expireAt.setMinutes(archiveBrew.expireAt.getMinutes() + HISTORY_SAVE_DELAYS[slot]);
const key = getKeyBySlot(brew, slot);
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 };
const historyKeys = [];
// Create array of all history keys
for (let i = 1; i <= HISTORY_SLOTS; i++){
historyKeys.push(getKeyBySlot(brew, i));
};
// Load all keys from IDB at once
const dataArray = await IDB.getMany(historyKeys, await createHBStore());
return dataArray.map((data)=>{ return data ?? DEFAULT_HISTORY_ITEM; });
}
export async function updateHistory(brew) {
const history = await loadHistory(brew);
// Walk each version position
for (let slot = HISTORY_SLOTS - 1; slot >= 0; slot--){
const storedVersion = history[slot];
// If slot has expired, update all lower slots and break
if(new Date() >= new Date(storedVersion.expireAt)){
// Create array of arrays : [ [key1, value1], [key2, value2], ..., [keyN, valueN] ]
// to pass to IDB.setMany
const historyUpdate = [];
for (let updateSlot = slot; updateSlot > 0; updateSlot--){
// Move data from updateSlot to updateSlot + 1
if(!history[updateSlot - 1]?.noData) {
historyUpdate.push(parseBrewForStorage(history[updateSlot - 1], updateSlot + 1));
}
};
// Update the most recent brew
historyUpdate.push(parseBrewForStorage(brew, 1));
await IDB.setMany(historyUpdate, await createHBStore());
// Break out of data checks because we found an expired value
break;
}
};
};
export async function versionHistoryGarbageCollection(){
const entries = await IDB.entries(await createHBStore());
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());
};
};
};

View File

@@ -6,5 +6,7 @@
"enable_v3" : true,
"enable_themes" : true,
"local_environments" : ["docker", "local"],
"publicUrl" : "https://homebrewery.naturalcrit.com"
"publicUrl" : "https://homebrewery.naturalcrit.com",
"hb_images" : null,
"hb_fonts" : null
}

1740
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,17 +4,17 @@
"version": "3.15.0",
"engines": {
"npm": "^10.2.x",
"node": "^20.8.x"
"node": "^20.17.x"
},
"repository": {
"type": "git",
"url": "git://github.com/naturalcrit/homebrewery.git"
},
"scripts": {
"dev": "node scripts/dev.js",
"quick": "node scripts/quick.js",
"build": "node scripts/buildHomebrew.js && node scripts/buildAdmin.js",
"builddev": "node scripts/buildHomebrew.js --dev",
"dev": "node --experimental-require-module scripts/dev.js",
"quick": "node --experimental-require-module scripts/quick.js",
"build": "node --experimental-require-module scripts/buildHomebrew.js && node --experimental-require-module scripts/buildAdmin.js",
"builddev": "node --experimental-require-module scripts/buildHomebrew.js --dev",
"lint": "eslint --fix",
"lint:dry": "eslint",
"stylelint": "stylelint --fix **/*.{less}",
@@ -25,6 +25,7 @@
"test:api-unit": "jest \"server/.*.spec.js\" --verbose",
"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:coverage": "jest --coverage --silent --runInBand",
"test:dev": "jest --verbose --watch",
"test:basic": "jest tests/markdown/basic.test.js --verbose",
@@ -37,10 +38,10 @@
"test:hard-breaks": "jest tests/markdown/hard-breaks.test.js --verbose --noStackTrace",
"test:emojis": "jest tests/markdown/emojis.test.js --verbose --noStackTrace",
"test:route": "jest tests/routes/static-pages.test.js --verbose",
"phb": "node scripts/phb.js",
"phb": "node --experimental-require-module scripts/phb.js",
"prod": "set NODE_ENV=production && npm run build",
"postinstall": "npm run build",
"start": "node server.js"
"start": "node --experimental-require-module server.js"
},
"author": "stolksdorf",
"license": "MIT",
@@ -85,23 +86,24 @@
]
},
"dependencies": {
"@babel/core": "^7.25.2",
"@babel/plugin-transform-runtime": "^7.25.4",
"@babel/preset-env": "^7.25.4",
"@babel/preset-react": "^7.24.7",
"@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",
"body-parser": "^1.20.2",
"classnames": "^2.5.1",
"codemirror": "^5.65.6",
"cookie-parser": "^1.4.6",
"cookie-parser": "^1.4.7",
"create-react-class": "^15.7.0",
"dedent-tabs": "^0.10.3",
"dompurify": "^3.1.6",
"dompurify": "^3.1.7",
"expr-eval": "^2.0.2",
"express": "^4.19.2",
"express": "^4.21.1",
"express-async-handler": "^1.2.0",
"express-static-gzip": "2.1.7",
"express-static-gzip": "2.1.8",
"fs-extra": "11.2.0",
"idb-keyval": "^6.2.1",
"js-yaml": "^4.1.0",
"jwt-simple": "^0.5.6",
"less": "^3.13.1",
@@ -113,28 +115,28 @@
"marked-smartypants-lite": "^1.0.2",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.30.1",
"mongoose": "^8.6.0",
"mongoose": "^8.7.1",
"nanoid": "3.3.4",
"nconf": "^0.12.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-frame-component": "^4.1.3",
"react-router-dom": "6.26.1",
"react-router-dom": "6.26.2",
"sanitize-filename": "1.6.3",
"superagent": "^10.1.0",
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
},
"devDependencies": {
"@stylistic/stylelint-plugin": "^3.0.1",
"eslint": "^9.9.1",
"eslint-plugin-jest": "^28.8.2",
"eslint-plugin-react": "^7.35.1",
"globals": "^15.9.0",
"@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",
"jest": "^29.7.0",
"jest-expect-message": "^1.1.3",
"postcss-less": "^6.0.0",
"stylelint": "^16.9.0",
"stylelint-config-recess-order": "^5.1.0",
"stylelint-config-recess-order": "^5.1.1",
"stylelint-config-recommended": "^14.0.1",
"supertest": "^7.0.0"
}

View File

@@ -1,7 +1,7 @@
const HomebrewModel = require('./homebrew.model.js').model;
const NotificationModel = require('./notifications.model.js').model;
const router = require('express').Router();
const Moment = require('moment');
//const render = require('vitreum/steps/render');
const templateFn = require('../client/template.js');
const zlib = require('zlib');
@@ -22,7 +22,7 @@ const mw = {
if(process.env.ADMIN_USER === username && process.env.ADMIN_PASS === password){
return next();
}
return res.status(401).send('Access denied');
throw { HBErrorCode: '52', code: 401, message: 'Access denied' };
}
};
@@ -138,12 +138,48 @@ router.get('/admin/stats', mw.adminOnly, async (req, res)=>{
}
});
// ####################### NOTIFICATIONS
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 });
}
});
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);
} catch (error) {
console.log('Error adding notification: ', error.message);
return res.status(500).json({ message: error.message });
}
});
router.delete('/admin/notification/delete/:id', mw.adminOnly, async (req, res, next)=>{
try {
const notification = await NotificationModel.deleteNotification(req.params.id);
return res.json(notification);
} catch (error) {
console.error('Error deleting notification: { key: ', req.params.id, ' error: ', error.message, ' }');
return res.status(500).json({ message: error.message });
}
});
router.get('/admin', mw.adminOnly, (req, res)=>{
templateFn('admin', {
url : req.originalUrl
})
.then((page)=>res.send(page))
.catch((err)=>res.sendStatus(500));
.catch((err)=>{
console.log(err);
res.sendStatus(500);
});
});
module.exports = router;

116
server/admin.api.spec.js Normal file
View File

@@ -0,0 +1,116 @@
const supertest = require('supertest');
const app = supertest.agent(require('app.js').app)
.set('X-Forwarded-Proto', 'https');
const NotificationModel = require('./notifications.model.js').model;
describe('Tests for admin api', ()=>{
afterEach(()=>{
jest.resetAllMocks();
});
describe('Notifications', ()=>{
it('should return list of all notifications', async ()=>{
const testNotifications = ['a', 'b'];
jest.spyOn(NotificationModel, 'find')
.mockImplementationOnce(() => {
return { exec: jest.fn().mockResolvedValue(testNotifications) };
});
const response = await app
.get('/admin/notification/all')
.set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`);
expect(response.status).toBe(200);
expect(response.body).toEqual(testNotifications);
});
it('should add a new notification', async ()=>{
const inputNotification = {
title : 'Test Notification',
text : 'This is a test notification',
startAt : new Date().toISOString(),
stopAt : new Date().toISOString(),
dismissKey : 'testKey'
};
const savedNotification = {
...inputNotification,
_id : expect.any(String),
createdAt : expect.any(String),
startAt : inputNotification.startAt,
stopAt : inputNotification.stopAt,
};
jest.spyOn(NotificationModel.prototype, 'save')
.mockImplementationOnce(function() {
return Promise.resolve(this);
});
const response = await app
.post('/admin/notification/add')
.set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`)
.send(inputNotification);
expect(response.status).toBe(201);
expect(response.body).toEqual(savedNotification);
});
it('should handle error adding a notification without dismissKey', async () => {
const inputNotification = {
title : 'Test Notification',
text : 'This is a test notification',
startAt : new Date().toISOString(),
stopAt : new Date().toISOString()
};
//Change 'save' function to just return itself instead of actually interacting with the database
jest.spyOn(NotificationModel.prototype, 'save')
.mockImplementationOnce(function() {
return Promise.resolve(this);
});
const response = await app
.post('/admin/notification/add')
.set('Authorization', 'Basic ' + Buffer.from('admin:password3').toString('base64'))
.send(inputNotification);
expect(response.status).toBe(500);
expect(response.body).toEqual({ message: 'Dismiss key is required!' });
});
it('should delete a notification based on its dismiss key', async ()=>{
const dismissKey = 'testKey';
jest.spyOn(NotificationModel, 'findOneAndDelete')
.mockImplementationOnce((key) => {
return { exec: jest.fn().mockResolvedValue(key) };
});
const response = await app
.delete(`/admin/notification/delete/${dismissKey}`)
.set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`);
expect(NotificationModel.findOneAndDelete).toHaveBeenCalledWith({'dismissKey': 'testKey'});
expect(response.status).toBe(200);
expect(response.body).toEqual({ dismissKey: 'testKey' });
});
it('should handle error deleting a notification that doesnt exist', async ()=>{
const dismissKey = 'testKey';
jest.spyOn(NotificationModel, 'findOneAndDelete')
.mockImplementationOnce(() => {
return { exec: jest.fn().mockResolvedValue() };
});
const response = await app
.delete(`/admin/notification/delete/${dismissKey}`)
.set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`);
expect(NotificationModel.findOneAndDelete).toHaveBeenCalledWith({'dismissKey': 'testKey'});
expect(response.status).toBe(500);
expect(response.body).toEqual({ message: 'Notification not found' });
});
});
});

View File

@@ -8,6 +8,7 @@ const express = require('express');
const yaml = require('js-yaml');
const app = express();
const config = require('./config.js');
const fs = require('fs-extra');
const { homebrewApi, getBrew, getUsersBrewThemes, getCSS } = require('./homebrew.api.js');
const GoogleActions = require('./googleActions.js');
@@ -30,6 +31,8 @@ const sanitizeBrew = (brew, accessType)=>{
return brew;
};
app.set('trust proxy', 1 /* number of proxies between user and server */)
app.use('/', serveCompressedStaticAssets(`build`));
app.use(require('./middleware/content-negotiation.js'));
app.use(require('body-parser').json({ limit: '25mb' }));
@@ -202,6 +205,23 @@ app.get('/download/:id', asyncHandler(getBrew('share')), (req, res)=>{
res.status(200).send(brew.text);
});
//Serve brew metadata
app.get('/metadata/:id', asyncHandler(getBrew('share')), (req, res)=>{
const { brew } = req;
sanitizeBrew(brew, 'share');
const fields = ['title', 'pageCount', 'description', 'authors', 'lang',
'published', 'views', 'shareId', 'createdAt', 'updatedAt',
'lastViewed', 'thumbnail', 'tags'
];
const metadata = fields.reduce((acc, field)=>{
if(brew[field] !== undefined) acc[field] = brew[field];
return acc;
}, {});
res.status(200).json(metadata);
});
//Serve brew styling
app.get('/css/:id', asyncHandler(getBrew('share')), (req, res)=>{getCSS(req, res);});
@@ -238,6 +258,8 @@ app.get('/user/:username', async (req, res, next)=>{
console.log(err);
});
brews.forEach(brew => brew.stubbed = true); //All brews from MongoDB are "stubbed"
if(ownAccount && req?.account?.googleId){
const auth = await GoogleActions.authCheck(req.account, res);
let googleBrews = await GoogleActions.listGoogleBrews(auth)
@@ -245,12 +267,12 @@ app.get('/user/:username', async (req, res, next)=>{
console.error(err);
});
// If stub matches file from Google, use Google metadata over stub metadata
if(googleBrews && googleBrews.length > 0) {
for (const brew of brews.filter((brew)=>brew.googleId)) {
const match = googleBrews.findIndex((b)=>b.editId === brew.editId);
if(match !== -1) {
brew.googleId = googleBrews[match].googleId;
brew.stubbed = true;
brew.pageCount = googleBrews[match].pageCount;
brew.renderer = googleBrews[match].renderer;
brew.version = googleBrews[match].version;
@@ -259,6 +281,7 @@ app.get('/user/:username', async (req, res, next)=>{
}
}
//Remaining unstubbed google brews display current user as author
googleBrews = googleBrews.map((brew)=>({ ...brew, authors: [req.account.username] }));
brews = _.concat(brews, googleBrews);
}
@@ -375,22 +398,12 @@ app.get('/account', asyncHandler(async (req, res, next)=>{
let googleCount = [];
if(req.account) {
if(req.account.googleId) {
try {
auth = await GoogleActions.authCheck(req.account, res, false);
} catch (e) {
auth = undefined;
console.log('Google auth check failed!');
console.log(e);
}
if(auth.credentials.access_token) {
try {
googleCount = await GoogleActions.listGoogleBrews(auth);
} catch (e) {
googleCount = undefined;
console.log('List Google files failed!');
console.log(e);
}
}
auth = await GoogleActions.authCheck(req.account, res, false)
googleCount = await GoogleActions.listGoogleBrews(auth)
.catch((err)=>{
console.error(err);
});
}
const query = { authors: req.account.username, googleId: { $exists: false } };
@@ -404,7 +417,7 @@ app.get('/account', asyncHandler(async (req, res, next)=>{
username : req.account.username,
issued : req.account.issued,
googleId : Boolean(req.account.googleId),
authCheck : Boolean(req.account.googleId && auth.credentials.access_token),
authCheck : Boolean(req.account.googleId && auth?.credentials.access_token),
mongoCount : mongoCount,
googleCount : googleCount?.length
};
@@ -434,8 +447,16 @@ if(isLocalEnvironment){
});
}
// Add Static Local Paths
app.use('/staticImages', express.static(config.get('hb_images') && fs.existsSync(config.get('hb_images')) ? config.get('hb_images') :'staticImages'));
app.use('/staticFonts', express.static(config.get('hb_fonts') && fs.existsSync(config.get('hb_fonts')) ? config.get('hb_fonts'):'staticFonts'));
//Vault Page
app.get('/vault', asyncHandler(async(req, res, next)=>{
req.ogMeta = { ...defaultMetaTags,
title : 'The Vault',
description : 'Search for Brews'
};
return next();
}));
@@ -454,7 +475,8 @@ const renderPage = async (req, res)=>{
const configuration = {
local : isLocalEnvironment,
publicUrl : config.get('publicUrl') ?? '',
environment : nodeEnv
environment : nodeEnv,
deployment : config.get('heroku_app_name') ?? ''
};
const props = {
version : require('./../package.json').version,
@@ -498,7 +520,7 @@ app.use(async (err, req, res, next)=>{
err.originalUrl = req.originalUrl;
console.error(err);
if(err.originalUrl?.startsWith('/api/')) {
if(err.originalUrl?.startsWith('/api')) {
// console.log('API error');
res.status(err.status || err.response?.status || 500).send(err);
return;

View File

@@ -25,6 +25,15 @@ if(!config.get('service_account')){
const defaultAuth = serviceAuth || config.get('google_api_key');
const retryConfig = {
retry: 3, // Number of retry attempts
retryDelay: 100, // Initial delay in milliseconds
retryDelayMultiplier: 2, // Multiplier for exponential backoff
maxRetryDelay: 32000, // Maximum delay in milliseconds
httpMethodsToRetry: ['PATCH'], // Only retry PATCH requests
statusCodesToRetry: [[429, 429]], // Only retry on 429 status code
};
const GoogleActions = {
authCheck : (account, res, updateTokens=true)=>{
@@ -112,9 +121,7 @@ const GoogleActions = {
})
.catch((err)=>{
console.log(`Error Listing Google Brews`);
console.error(err);
throw (err);
//TODO: Should break out here, but continues on for some reason.
});
fileList.push(...obj.data.files);
NextPageToken = obj.data.nextPageToken;
@@ -147,8 +154,9 @@ const GoogleActions = {
return brews;
},
updateGoogleBrew : async (brew)=>{
const drive = googleDrive.drive({ version: 'v3', auth: defaultAuth });
updateGoogleBrew : async (brew, auth = defaultAuth, userIp)=>{
const drive = googleDrive.drive({ version: 'v3', auth: auth });
console.log(auth == defaultAuth ? 'UPDATE w SERVICEACC' : 'UPDATE w USERACC')
await drive.files.update({
fileId : brew.googleId,
@@ -168,11 +176,14 @@ const GoogleActions = {
media : {
mimeType : 'text/plain',
body : brew.text
}
},
headers: {
'X-Forwarded-For': userIp, // Set the X-Forwarded-For header
},
retryConfig
})
.catch((err)=>{
console.log('Error saving to google');
console.error(err);
throw (err);
});
@@ -211,7 +222,6 @@ const GoogleActions = {
})
.catch((err)=>{
console.log('Error while creating new Google brew');
console.error(err);
throw (err);
});

View File

@@ -242,11 +242,8 @@ const api = {
let googleId, saved;
if(saveToGoogle) {
googleId = await api.newGoogleBrew(req.account, newHomebrew, res)
.catch((err)=>{
console.error(err);
res.status(err?.status || err?.response?.status || 500).send(err?.message || err);
});
googleId = await api.newGoogleBrew(req.account, newHomebrew, res);
if(!googleId) return;
api.excludeStubProps(newHomebrew);
newHomebrew.googleId = googleId;
@@ -351,19 +348,13 @@ const api = {
brew.googleId = undefined;
} else if(!brew.googleId && saveToGoogle) {
// If we don't have a google id and the user wants to save to google, create the google brew and set the google id on the brew
brew.googleId = await api.newGoogleBrew(req.account, api.excludeGoogleProps(brew), res)
.catch((err)=>{
console.error(err);
res.status(err.status || err.response.status).send(err.message || err);
});
brew.googleId = await api.newGoogleBrew(req.account, api.excludeGoogleProps(brew), res);
if(!brew.googleId) return;
} else if(brew.googleId) {
// If the google id exists and no other actions are being performed, update the google brew
const updated = await GoogleActions.updateGoogleBrew(api.excludeGoogleProps(brew))
.catch((err)=>{
console.error(err);
res.status(err?.response?.status || 500).send(err);
});
const updated = await GoogleActions.updateGoogleBrew(api.excludeGoogleProps(brew));
if(!updated) return;
}

View File

@@ -560,16 +560,6 @@ brew`);
views : 0
});
});
it('should handle google error', async()=>{
google.newGoogleBrew = jest.fn(()=>{
throw 'err';
});
await api.newBrew({ body: { text: 'asdf', title: '' }, query: { saveToGoogle: true }, account: { username: 'test user' } }, res);
expect(res.status).toHaveBeenCalledWith(500);
expect(res.send).toHaveBeenCalledWith('err');
});
});
describe('deleteGoogleBrew', ()=>{
@@ -934,7 +924,7 @@ brew`);
expect(req.brew).toEqual(testBrew);
expect(req.brew).toHaveProperty('style', '\nI Have a style!\n');
expect(res.status).toHaveBeenCalledWith(200);
expect(res.send).toHaveBeenCalledWith("\nI Have a style!\n");
expect(res.send).toHaveBeenCalledWith('\nI Have a style!\n');
expect(res.set).toHaveBeenCalledWith({
'Cache-Control' : 'no-cache',
'Content-Type' : 'text/css'

View File

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

View File

@@ -0,0 +1,62 @@
const mongoose = require('mongoose');
const _ = require('lodash');
const NotificationSchema = new mongoose.Schema({
dismissKey : { type: String, unique: true, required: true },
title : { type: String, default: '' },
text : { type: String, default: '' },
createdAt : { type: Date, default: Date.now },
startAt : { type: Date, default: Date.now },
stopAt : { type: Date, default: Date.now },
}, { versionKey: false });
NotificationSchema.statics.addNotification = async function(data) {
if(!data.dismissKey) throw { message: 'Dismiss key is required!' };
const defaults = {
title : '',
text : '',
startAt : new Date(),
stopAt : new Date(),
};
const notificationData = _.defaults(data, defaults);
try {
const newNotification = new this(notificationData);
const savedNotification = await newNotification.save();
return savedNotification;
} catch (err) {
throw { message: err.message || 'Error saving notification' };
}
};
NotificationSchema.statics.deleteNotification = async function(dismissKey) {
if(!dismissKey) throw { message: 'Dismiss key is required!' };
try {
const deletedNotification = await this.findOneAndDelete({ dismissKey }).exec();
if(!deletedNotification) {
throw { message: 'Notification not found' };
}
return deletedNotification;
} catch (err) {
throw { message: err.message || 'Error deleting notification' };
}
};
NotificationSchema.statics.getAll = async function() {
try {
const notifications = await this.find().exec();
return notifications;
} catch (err) {
throw { message: err.message || 'Error retrieving notifications' };
}
};
const Notification = mongoose.model('Notification', NotificationSchema);
module.exports = {
schema : NotificationSchema,
model : Notification,
};

View File

@@ -29,12 +29,18 @@ const rendererConditions = (legacy, v3)=>{
return {}; // If all renderers selected, renderer field not needed in query for speed
};
const sortConditions = (sort, dir) => {
return { [sort]: dir === 'asc' ? 1 : -1 };
};
const findBrews = async (req, res)=>{
const title = req.query.title || '';
const author = req.query.author || '';
const page = Math.max(parseInt(req.query.page) || 1, 1);
const count = Math.max(parseInt(req.query.count) || 20, 10);
const skip = (page - 1) * count;
const sort = req.query.sort || 'title';
const dir = req.query.dir || 'asc';
const combinedQuery = {
$and : [
@@ -54,6 +60,7 @@ const findBrews = async (req, res)=>{
};
await HomebrewModel.find(combinedQuery, projection)
.sort(sortConditions(sort, dir))
.skip(skip)
.limit(count)
.maxTimeMS(5000)

View File

@@ -397,6 +397,11 @@ const CodeEditor = createClass({
getCursorPosition : function(){
return this.codeMirror.getCursor();
},
getTopVisibleLine : function(){
const rect = this.codeMirror.getWrapperElement().getBoundingClientRect();
const topVisibleLine = this.codeMirror.lineAtHeight(rect.top, 'window');
return topVisibleLine;
},
updateSize : function(){
this.codeMirror.refresh();
},

View File

@@ -105,16 +105,16 @@ renderer.link = function (href, title, text) {
// Expose `src` attribute as `--HB_src` to make the URL accessible via CSS
renderer.image = function (href, title, text) {
href = cleanUrl(href);
if (href === null)
if(href === null)
return text;
let out = `<img src="${href}" alt="${text}" style="--HB_src:url(${href});"`;
if (title)
if(title)
out += ` title="${title}"`;
out += '>';
return out;
}
};
// Disable default reflink behavior, as it steps on our variables extension
tokenizer.def = function () {
@@ -745,7 +745,7 @@ const tableTerminators = [
`:+\\n`, // hardBreak
` *{[^\n]+}`, // blockInjector
` *{{[^{\n]*\n.*?\n}}` // mustacheDiv
]
];
Marked.use(MarkedVariables());
Marked.use({ extensions : [definitionListsMultiLine, definitionListsSingleLine, forcedParagraphBreaks, superSubScripts,
@@ -755,12 +755,12 @@ Marked.use({ renderer: renderer, tokenizer: tokenizer, mangle: false });
Marked.use(MarkedExtendedTables(tableTerminators), MarkedGFMHeadingId({ globalSlugs: true }), MarkedSmartypantsLite(), MarkedEmojis(MarkedEmojiOptions));
function cleanUrl(href) {
try {
href = encodeURI(href).replace(/%25/g, '%');
} catch {
return null;
}
return href;
try {
href = encodeURI(href).replace(/%25/g, '%');
} catch {
return null;
}
return href;
}
const escapeTest = /[&<>"']/;

View File

@@ -19,7 +19,8 @@ const SplitPane = createClass({
windowWidth : 0,
isDragging : false,
moveSource : false,
moveBrew : false
moveBrew : false,
showMoveArrows : true
};
},
@@ -41,6 +42,10 @@ const SplitPane = createClass({
});
}
window.addEventListener('resize', this.handleWindowResize);
// This lives here instead of in the initial render because you cannot touch localStorage until the componant mounts.
const loadLiveScroll = window.localStorage.getItem('liveScroll') === 'true';
this.setState({ liveScroll: loadLiveScroll });
},
componentWillUnmount : function() {
@@ -88,6 +93,11 @@ const SplitPane = createClass({
userSetDividerPos : newSize
});
},
liveScrollToggle : function() {
window.localStorage.setItem('liveScroll', String(!this.state.liveScroll));
this.setState({ liveScroll: !this.state.liveScroll });
},
/*
unFocus : function() {
if(document.selection){
@@ -119,13 +129,18 @@ const SplitPane = createClass({
onClick={()=>this.setState({ moveBrew: !this.state.moveBrew })} >
<i className='fas fa-arrow-right' />
</div>
<div id='scrollToggleDiv' className={this.state.liveScroll ? 'arrow lock' : 'arrow unlock'}
style={{ left: this.state.currentDividerPos-4 }}
onClick={this.liveScrollToggle} >
<i id='scrollToggle' className={this.state.liveScroll ? 'fas fa-lock' : 'fas fa-unlock'} />
</div>
</>;
}
},
renderDivider : function(){
return <>
{this.renderMoveArrows()}
{this.props.showDividerButtons && this.renderMoveArrows()}
<div className='divider' onPointerDown={this.handleDown} >
<div className='dots'>
<i className='fas fa-circle' />
@@ -143,9 +158,10 @@ const SplitPane = createClass({
>
{React.cloneElement(this.props.children[0], {
...(this.props.showDividerButtons && {
moveBrew: this.state.moveBrew,
moveSource: this.state.moveSource,
setMoveArrows: this.setMoveArrows,
moveBrew : this.state.moveBrew,
moveSource : this.state.moveSource,
liveScroll : this.state.liveScroll,
setMoveArrows : this.setMoveArrows,
}),
})}
</Pane>

View File

@@ -53,6 +53,15 @@
.tooltipRight('Jump to location in Preview');
top : 60px;
}
&.lock{
.tooltipRight('De-sync Editor and Preview locations.');
top : 90px;
background: #666;
}
&.unlock{
.tooltipRight('Sync Editor and Preview locations');
top : 90px;
}
&:hover{
background-color: #666;
}

View File

@@ -27,35 +27,154 @@ module.exports = [
experimental : true,
subsnippets : [
{
name : 'Table of Contents',
name : 'Generate Table of Contents',
icon : 'fas fa-book',
gen : TableOfContentsGen,
experimental : true
},
{
name : 'Include in ToC up to H3',
icon : 'fas fa-dice-three',
name : 'Table of Contents Individual Inclusion',
icon : 'fas fa-book',
gen : dedent `\n{{tocInclude# CHANGE # to your header level
}}\n`,
subsnippets : [
{
name : 'Individual Inclusion H1',
icon : 'fas fa-book',
gen : dedent `\n{{tocIncludeH1 \n
}}\n`,
},
{
name : 'Individual Inclusion H2',
icon : 'fas fa-book',
gen : dedent `\n{{tocIncludeH2 \n
}}\n`,
},
{
name : 'Individual Inclusion H3',
icon : 'fas fa-book',
gen : dedent `\n{{tocIncludeH3 \n
}}\n`,
},
{
name : 'Individual Inclusion H4',
icon : 'fas fa-book',
gen : dedent `\n{{tocIncludeH4 \n
}}\n`,
},
{
name : 'Individual Inclusion H5',
icon : 'fas fa-book',
gen : dedent `\n{{tocIncludeH5 \n
}}\n`,
},
{
name : 'Individual Inclusion H6',
icon : 'fas fa-book',
gen : dedent `\n{{tocIncludeH6 \n
}}\n`,
}
]
},
{
name : 'Table of Contents Range Inclusion',
icon : 'fas fa-book',
gen : dedent `\n{{tocDepthH3
}}\n`,
subsnippets : [
{
name : 'Include in ToC up to H3',
icon : 'fas fa-dice-three',
gen : dedent `\n{{tocDepthH3
}}\n`,
},
{
name : 'Include in ToC up to H4',
icon : 'fas fa-dice-four',
gen : dedent `\n{{tocDepthH4
}}\n`,
},
{
name : 'Include in ToC up to H5',
icon : 'fas fa-dice-five',
gen : dedent `\n{{tocDepthH5
}}\n`,
},
{
name : 'Include in ToC up to H6',
icon : 'fas fa-dice-six',
gen : dedent `\n{{tocDepthH6
}}\n`,
},
]
},
{
name : 'Include in ToC up to H4',
icon : 'fas fa-dice-four',
gen : dedent `\n{{tocDepthH4
name : 'Table of Contents Individual Exclusion',
icon : 'fas fa-book',
gen : dedent `\n{{tocExcludeH1 \n
}}\n`,
subsnippets : [
{
name : 'Individual Exclusion H1',
icon : 'fas fa-book',
gen : dedent `\n{{tocExcludeH1 \n
}}\n`,
},
{
name : 'Individual Exclusion H2',
icon : 'fas fa-book',
gen : dedent `\n{{tocExcludeH2 \n
}}\n`,
},
{
name : 'Individual Exclusion H3',
icon : 'fas fa-book',
gen : dedent `\n{{tocExcludeH3 \n
}}\n`,
},
{
name : 'Individual Exclusion H4',
icon : 'fas fa-book',
gen : dedent `\n{{tocExcludeH4 \n
}}\n`,
},
{
name : 'Individual Exclusion H5',
icon : 'fas fa-book',
gen : dedent `\n{{tocExcludeH5 \n
}}\n`,
},
{
name : 'Individual Exclusion H6',
icon : 'fas fa-book',
gen : dedent `\n{{tocExcludeH6 \n
}}\n`,
},
]
},
{
name : 'Include in ToC up to H5',
icon : 'fas fa-dice-five',
gen : dedent `\n{{tocDepthH5
}}\n`,
},
{
name : 'Include in ToC up to H6',
icon : 'fas fa-dice-six',
gen : dedent `\n{{tocDepthH6
}}\n`,
name : 'Table of Contents Toggles',
icon : 'fas fa-book',
gen : `{{tocGlobalH4}}\n\n`,
subsnippets : [
{
name : 'Enable H1-H4 all pages',
icon : 'fas fa-dice-four',
gen : `{{tocGlobalH4}}\n\n`,
},
{
name : 'Enable H1-H5 all pages',
icon : 'fas fa-dice-five',
gen : `{{tocGlobalH5}}\n\n`,
},
{
name : 'Enable H1-H6 all pages',
icon : 'fas fa-dice-six',
gen : `{{tocGlobalH6}}\n\n`,
},
]
}
]
},
@@ -94,7 +213,7 @@ module.exports = [
background-image: linear-gradient(-45deg, #322814, #998250, #322814);
line-height: 1em;
}\n\n`
}
},
]
},

View File

@@ -1,77 +1,78 @@
const _ = require('lodash');
const dedent = require('dedent-tabs').default;
const getTOC = (pages)=>{
// Map each actual page to its footer label, accounting for skips or numbering resets
const mapPages = (pages)=>{
let actualPage = 0;
let mappedPage = 0; // Number displayed in footer
const pageMap = [];
const recursiveAdd = (title, page, targetDepth, child, curDepth=0)=>{
if(curDepth > 5) return; // Something went wrong.
if(curDepth == targetDepth) {
child.push({
title : title,
page : page,
children : []
});
} else {
if(child.length == 0) {
child.push({
title : null,
page : page,
children : []
});
pages.forEach((page)=>{
actualPage++;
const doSkip = page.querySelector('.skipCounting');
const doReset = page.querySelector('.resetCounting');
if(doReset)
mappedPage = 1;
if(!doSkip && !doReset)
mappedPage++;
pageMap[actualPage] = {
mappedPage : mappedPage,
showPage : !doSkip
};
});
return pageMap;
};
const getMarkdown = (headings, pageMap)=>{
const levelPad = ['- ###', ' - ####', ' -', ' -', ' -', ' -'];
const allMarkdown = [];
const depthChain = [0];
headings.forEach((heading)=>{
const page = parseInt(heading.closest('.page').id?.replace(/^p/, ''));
const mappedPage = pageMap[page].mappedPage;
const showPage = pageMap[page].showPage;
const title = heading.textContent.trim();
const ToCExclude = getComputedStyle(heading).getPropertyValue('--TOC');
const depth = parseInt(heading.tagName.substring(1));
if(!title || !showPage || ToCExclude == 'exclude')
return;
//If different header depth than last, remove indents until nearest higher-level header, then indent once
if(depth !== depthChain[depthChain.length -1]) {
while (depth <= depthChain[depthChain.length - 1]) {
depthChain.pop();
}
recursiveAdd(title, page, targetDepth, _.last(child).children, curDepth+1,);
depthChain.push(depth);
}
};
const res = [];
const markdown = `${levelPad[depthChain.length - 2]} [{{ ${title}}}{{ ${mappedPage}}}](#p${page})`;
allMarkdown.push(markdown);
});
return allMarkdown.join('\n');
};
const getTOC = ()=>{
const iframe = document.getElementById('BrewRenderer');
const iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
const headings = iframeDocument.querySelectorAll('h1, h2, h3, h4, h5, h6');
const headerDepth = ['H1', 'H2', 'H3', 'H4', 'H5', 'H6'];
const pages = iframeDocument.querySelectorAll('.page');
_.each(headings, (heading)=>{
const onPage = parseInt(heading.closest('.page').id?.replace(/^p/, ''));
const ToCExclude = getComputedStyle(heading).getPropertyValue('--TOC');
if(ToCExclude != 'exclude') {
recursiveAdd(heading.textContent.trim(), onPage, headerDepth.indexOf(heading.tagName), res);
}
});
return res;
};
const ToCIterate = (entries, curDepth=0)=>{
const levelPad = ['- ###', ' - ####', ' - ', ' - ', ' - ', ' - '];
const toc = [];
if(entries.title !== null){
toc.push(`${levelPad[curDepth]} [{{ ${entries.title}}}{{ ${entries.page}}}](#p${entries.page})`);
}
if(entries.children.length) {
_.each(entries.children, (entry, idx)=>{
const children = ToCIterate(entry, entry.title == null ? curDepth : curDepth+1);
if(children.length) {
toc.push(...children);
}
});
}
return toc;
const pageMap = mapPages(pages);
return getMarkdown(headings, pageMap);
};
module.exports = function(props){
const pages = props.brew.text.split('\\page');
const TOC = getTOC(pages);
const markdown = _.reduce(TOC, (r, g1, idx1)=>{
r.push(ToCIterate(g1).join('\n'));
return r;
}, []).join('\n');
const TOC = getTOC();
return dedent`
{{toc,wide
# Contents
${markdown}
${TOC}
}}
\n`;
};
};

View File

@@ -11,6 +11,7 @@
--HB_Color_CaptionText : #766649; // Brown
--HB_Color_WatercolorStain : #BBAD82; // Light brown
--HB_Color_Footnotes : #C9AD6A; // Gold
--TOC : 'include';
}
.useSansSerif() {
@@ -797,7 +798,7 @@
// *****************************/
// Default Exclusions
// Anything not exlcuded is included, default Headers are H1, H2, and H3.
// Anything not excluded is included, default Headers are H1, H2, and H3.
h4,
h5,
h6,
@@ -808,12 +809,23 @@ h6,
.noToC,
.toc { --TOC: exclude; }
.tocDepthH2 :is(h1, h2) {--TOC: include; }
.tocDepthH3 :is(h1, h2, h3) {--TOC: include; }
.tocDepthH4 :is(h1, h2, h3, h4) {--TOC: include; }
.tocDepthH5 :is(h1, h2, h3, h4, h5) {--TOC: include; }
.tocDepthH6 :is(h1, h2, h3, h4, h5, h6) {--TOC: include; }
// Brew level default inclusion changes.
// These add Headers 'back' to inclusion.
.pages:has(.tocGlobalH4) {
h4 {--TOC: include; }
}
.pages:has(.tocGlobalH5) {
h4, h5 {--TOC: include; }
}
.pages:has(.tocGlobalH6) {
h4, h5, h6 {--TOC: include; }
}
// Block level inclusion changes
// These include either a single (include) or a range (depth)
.tocIncludeH1 h1 {--TOC: include; }
.tocIncludeH2 h2 {--TOC: include; }
.tocIncludeH3 h3 {--TOC: include; }
@@ -821,6 +833,21 @@ h6,
.tocIncludeH5 h5 {--TOC: include; }
.tocIncludeH6 h6 {--TOC: include; }
.tocDepthH2 :is(h1, h2) {--TOC: include; }
.tocDepthH3 :is(h1, h2, h3) {--TOC: include; }
.tocDepthH4 :is(h1, h2, h3, h4) {--TOC: include; }
.tocDepthH5 :is(h1, h2, h3, h4, h5) {--TOC: include; }
.tocDepthH6 :is(h1, h2, h3, h4, h5, h6) {--TOC: include; }
// Block level exclusion changes
// These exclude a single block level
.tocExcludeH1 h1 {--TOC: exclude; }
.tocExcludeH2 h2 {--TOC: exclude; }
.tocExcludeH3 h3 {--TOC: exclude; }
.tocExcludeH4 h4 {--TOC: exclude; }
.tocExcludeH5 h5 {--TOC: exclude; }
.tocExcludeH6 h6 {--TOC: exclude; }
.page:has(.partCover) {
--TOC: exclude;
& h1 {

View File

@@ -23,14 +23,30 @@ module.exports = [
gen : '\n\\page\n'
},
{
name : 'Page Number',
icon : 'fas fa-bookmark',
gen : '{{pageNumber 1}}\n'
},
{
name : 'Auto-incrementing Page Number',
icon : 'fas fa-sort-numeric-down',
gen : '{{pageNumber,auto}}\n'
name : 'Page Numbering',
icon : 'fas fa-bookmark',
subsnippets : [
{
name : 'Page Number',
icon : 'fas fa-bookmark',
gen : '{{pageNumber 1}}\n'
},
{
name : 'Auto-incrementing Page Number',
icon : 'fas fa-sort-numeric-down',
gen : '{{pageNumber,auto}}\n'
},
{
name : 'Skip Page Number Increment this Page',
icon : 'fas fa-xmark',
gen : '{{skipCounting}}\n'
},
{
name : 'Restart Numbering',
icon : 'fas fa-arrow-rotate-left',
gen : '{{resetCounting}}\n'
},
]
},
{
name : 'Footer',
@@ -352,6 +368,11 @@ module.exports = [
icon : 'font MrEavesRemake',
gen : dedent`{{font-family:MrEavesRemake Dummy Text}}`
},
{
name : 'Pagella',
icon : 'font Pagella',
gen : dedent`{{font-family:Pagella Dummy Text}}`
},
{
name : 'Solbera Imitation',
icon : 'font SolberaImitationRemake',
@@ -410,22 +431,40 @@ module.exports = [
]
},
/**************** PAGE *************/
/**************** LAYOUT *************/
{
groupName : 'Print',
icon : 'fas fa-print',
view : 'style',
snippets : [
{
name : 'A3 Page Size',
icon : 'far fa-file',
gen : dedent`/* A3 Page Size */
.page {
width : 297mm;
height : 420mm;
}\n\n`,
},
{
name : 'A4 Page Size',
icon : 'far fa-file',
gen : dedent`/* A4 Page Size */
.page{
.page {
width : 210mm;
height : 296.8mm;
}\n\n`
},
{
name : 'A5 Page Size',
icon : 'far fa-file',
gen : dedent`/* A5 Page Size */
.page {
width : 148mm;
height : 210mm;
}\n\n`,
},
{
name : 'Square Page Size',
icon : 'far fa-file',
@@ -437,6 +476,17 @@ module.exports = [
columns : unset;
}\n\n`
},
{
name : 'Card Page Size',
icon : 'far fa-file',
gen : dedent`/* Card Size */
.page {
width : 63.5mm;
height : 88.9mm;
padding : 5mm;
columns : unset;
}\n\n`
},
{
name : 'Ink Friendly',
icon : 'fas fa-tint',
@@ -452,5 +502,5 @@ module.exports = [
}\n\n`
},
]
}
},
];

View File

@@ -1,3 +1,4 @@
@import (less) './themes/fonts/Blank/fonts.less';
@import (less) './themes/fonts/5e/fonts.less';
@import (less) './themes/assets/assets.less';
@import (less) './themes/fonts/iconFonts/elderberryInn.less';
@@ -12,7 +13,7 @@
}
@page { margin : 0; }
body { counter-reset : page-numbers; }
body { counter-reset : page-numbers 0; }
* { -webkit-print-color-adjust : exact; }
//*****************************
@@ -51,7 +52,6 @@ body { counter-reset : page-numbers; }
height : 279.4mm;
padding : 1.4cm 1.9cm 1.7cm;
overflow : hidden;
counter-increment : page-numbers;
background-color : var(--HB_Color_Background);
text-rendering : optimizeLegibility;
contain : size;
@@ -494,4 +494,13 @@ body { counter-reset : page-numbers; }
&:nth-child(even) {
.pageNumber { left : 30px; }
}
}
.resetCounting {
counter-set : page-numbers 1;
}
&:not(:has(.skipCounting)) {
counter-increment : page-numbers;
}
}

View File

@@ -0,0 +1,46 @@
/*
TeX Gyre Pagella
License:
% Copyright 2007--2018 for TeX Gyre extensions by B. Jackowski,
% J.M. Nowacki et al. (on behalf of TeX Users Groups). Vietnamese
% characters were added by Han The Thanh.
%
% This work can be freely used and distributed under
% the GUST Font License (GFL -- see GUST-FONT-LICENSE.txt)
% which is actually an instance of the LaTeX Project Public License
% (LPPL -- see http://www.latex-project.org/lppl.txt ).
%
% This work has the maintenance status "maintained". The Current Maintainer
% of this work is Bogus\l{}aw Jackowski and Janusz M. Nowacki.
%
% This work consists of the files listed
% in the MANIFEST-TeX-Gyre-Pagella.txt file.
*/
@font-face {
font-family: Pagella;
src: url('../../../fonts/Blank/texgyrepagella-regular.woff2');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: Pagella;
src: url('../../../fonts/Blank/texgyrepagella-bold.woff2');
font-weight: bold;
font-style: normal;
}
@font-face {
font-family: Pagella;
src: url('../../../fonts/Blank/texgyrepagella-italic.woff2');
font-weight: normal;
font-style: italic;
}
@font-face {
font-family: Pagella;
src: url('../../../fonts/Blank/texgyrepagella-bolditalic.woff2');
font-weight: bold;
font-style: italic;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.