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

Compare commits

..

356 Commits

Author SHA1 Message Date
G.Ambatte
2bd06250fc Add @import folding 2024-07-20 14:50:39 +12:00
David Bolack
c82b62f953 Add Code folding on CSS style tab 2024-07-19 16:03:44 -05:00
Trevor Buckner
4fe38e3929 Merge pull request #3567 from G-Ambatte/fixUglyDropCap-#3551
Add additional styles to SolberaImitationRemake font declaration
2024-07-11 09:47:26 -04:00
Trevor Buckner
b6d69173cd Merge branch 'master' into fixUglyDropCap-#3551 2024-07-11 09:46:45 -04:00
Trevor Buckner
8b085e1806 Merge pull request #3569 from G-Ambatte/fixBrewItemLinkUnderlining-#3568
Unset text-decoration on Brew Item links
2024-07-11 09:46:36 -04:00
G.Ambatte
cb9d24d5b4 Remove text-decoration from Brew Item links 2024-07-11 20:03:17 +12:00
G.Ambatte
23fd70e3c3 Add additional style to existing SolberaImitation 2024-07-11 18:10:26 +12:00
Trevor Buckner
5b02132e57 Merge pull request #3561 from naturalcrit/v3.13.1
Up Version to 3.13.1
2024-07-06 18:20:34 -04:00
Trevor Buckner
f8841c068f Up Version to 3.13.1 2024-07-06 18:20:11 -04:00
Trevor Buckner
da1d08f8a9 Merge pull request #3560 from G-Ambatte/fixAttributeLeaking-#3559
Limit htmlString to the first element ONLY
2024-07-06 18:01:26 -04:00
Trevor Buckner
0a199e750f Simplify string splitting code
String.split will return the substring before > or the whole string if no > exists.
2024-07-06 18:00:18 -04:00
Trevor Buckner
5433cda52f Add test case 2024-07-06 17:05:23 -04:00
G.Ambatte
9c4de58161 Limit htmlString to the first element ONLY 2024-07-06 13:22:47 +12:00
Trevor Buckner
1b96dae27f Merge pull request #3543 from naturalcrit/dependabot/npm_and_yarn/googleapis/drive-8.11.0
Bump @googleapis/drive from 8.10.0 to 8.11.0
2024-07-05 18:09:10 -04:00
dependabot[bot]
1564bc7448 Bump @googleapis/drive from 8.10.0 to 8.11.0
Bumps [@googleapis/drive](https://github.com/googleapis/google-api-nodejs-client) from 8.10.0 to 8.11.0.
- [Release notes](https://github.com/googleapis/google-api-nodejs-client/releases)
- [Changelog](https://github.com/googleapis/google-api-nodejs-client/blob/main/release-please-config.json)
- [Commits](https://github.com/googleapis/google-api-nodejs-client/compare/drive-v8.10.0...drive-v8.11.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-05 18:59:10 +00:00
Trevor Buckner
8e20d3ba10 Merge pull request #3539 from naturalcrit/dependabot/npm_and_yarn/eslint-plugin-react-7.34.3
Bump eslint-plugin-react from 7.34.2 to 7.34.3
2024-07-05 14:57:59 -04:00
dependabot[bot]
450baee66a Bump eslint-plugin-react from 7.34.2 to 7.34.3
Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.34.2 to 7.34.3.
- [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.34.2...v7.34.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-05 18:55:32 +00:00
Trevor Buckner
4b588786c4 Merge pull request #3538 from naturalcrit/dependabot/npm_and_yarn/ws-7.5.10
Bump ws from 7.5.9 to 7.5.10
2024-07-05 14:54:32 -04:00
dependabot[bot]
e07a04ebfa Bump ws from 7.5.9 to 7.5.10
Bumps [ws](https://github.com/websockets/ws) from 7.5.9 to 7.5.10.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.5.9...7.5.10)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-05 18:53:33 +00:00
Trevor Buckner
f707752c26 Merge pull request #3558 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.4.5
Bump mongoose from 8.4.1 to 8.4.5
2024-07-05 14:52:35 -04:00
dependabot[bot]
80e039b194 Bump mongoose from 8.4.1 to 8.4.5
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.4.1 to 8.4.5.
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Automattic/mongoose/compare/8.4.1...8.4.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-05 18:41:01 +00:00
Trevor Buckner
c888df28aa Merge pull request #3533 from naturalcrit/dependabot/npm_and_yarn/marked-emoji-1.4.1
Bump marked-emoji from 1.4.0 to 1.4.1
2024-07-05 14:39:58 -04:00
Trevor Buckner
94cc1c642c Merge branch 'master' into dependabot/npm_and_yarn/marked-emoji-1.4.1 2024-07-05 09:03:10 -04:00
Trevor Buckner
9a02a351fa Merge pull request #3528 from naturalcrit/dependabot/npm_and_yarn/marked-gfm-heading-id-3.2.0
Bump marked-gfm-heading-id from 3.1.3 to 3.2.0
2024-07-05 09:02:39 -04:00
dependabot[bot]
e8e7237a8e Bump marked-gfm-heading-id from 3.1.3 to 3.2.0
Bumps [marked-gfm-heading-id](https://github.com/markedjs/marked-gfm-heading-id) from 3.1.3 to 3.2.0.
- [Release notes](https://github.com/markedjs/marked-gfm-heading-id/releases)
- [Changelog](https://github.com/markedjs/marked-gfm-heading-id/blob/main/release.config.cjs)
- [Commits](https://github.com/markedjs/marked-gfm-heading-id/compare/v3.1.3...v3.2.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-04 03:21:44 +00:00
dependabot[bot]
086c4f74f6 Bump marked-emoji from 1.4.0 to 1.4.1
Bumps [marked-emoji](https://github.com/UziTech/marked-emoji) from 1.4.0 to 1.4.1.
- [Release notes](https://github.com/UziTech/marked-emoji/releases)
- [Changelog](https://github.com/UziTech/marked-emoji/blob/main/release.config.cjs)
- [Commits](https://github.com/UziTech/marked-emoji/compare/v1.4.0...v1.4.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-04 03:21:26 +00:00
Trevor Buckner
e987da498b Merge pull request #3557 from naturalcrit/dependabot/npm_and_yarn/react-router-dom-6.24.1
Bump react-router-dom from 6.23.1 to 6.24.1
2024-07-03 23:20:35 -04:00
dependabot[bot]
d12f644f5b Bump react-router-dom from 6.23.1 to 6.24.1
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.23.1 to 6.24.1.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.24.1/packages/react-router-dom)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-04 03:15:49 +00:00
Trevor Buckner
3eb071fbdc Merge pull request #3555 from G-Ambatte/fixToC-#3548
Fix ToC generator snippet
2024-07-02 11:55:39 -04:00
Trevor Buckner
81e17b420c Merge branch 'master' into fixToC-#3548 2024-07-02 11:55:31 -04:00
Trevor Buckner
e8ccd094e8 Merge pull request #3552 from naturalcrit/Allow=InAttributes
Allow `=` in attributes
2024-07-02 11:54:59 -04:00
G.Ambatte
7c60fbe655 Remove page + 1 from ToC generator snippet 2024-07-02 20:46:01 +12:00
Trevor Buckner
2d570924d1 Add tests 2024-07-01 12:21:36 -04:00
Trevor Buckner
8ee70b0928 Only split curly attributes on on first =, allow ?, = in attributes 2024-07-01 12:21:29 -04:00
Trevor Buckner
2cdd65b083 revert DOMPURIFY for now 2024-06-29 11:29:31 -04:00
Trevor Buckner
758a06e58a Merge pull request #3545 from naturalcrit/3.13.0
Up version to 3.13.0
2024-06-28 22:47:31 -04:00
Trevor Buckner
a87e420437 Up version to 3.13.0 2024-06-28 22:46:56 -04:00
Trevor Buckner
46085c8d44 Merge pull request #3544 from naturalcrit/unifyEmojiFontSpacing
Unify some emoji CSS across fonts
2024-06-28 22:02:19 -04:00
Trevor Buckner
179e21755c Unify some emoji CSS across fonts 2024-06-28 22:01:55 -04:00
Trevor Buckner
e9ca68e7d3 Merge pull request #3261 from dbolacksn/issue_2994_css_style
Table of Contents Snippet exclusion system
2024-06-28 11:05:14 -04:00
Trevor Buckner
9886200fa9 Fix partCover H1 inclusion rule 2024-06-28 09:39:49 -04:00
Trevor Buckner
9a1070bb06 Merge branch 'master' into issue_2994_css_style 2024-06-27 17:22:23 -04:00
Víctor Losada Hernández
3b8dbe8a04 Merge pull request #3522 from naturalcrit/tweakCMPageLineBrightness
Tweak CM page line brightness on dark themes
2024-06-15 18:03:08 +02:00
G.Ambatte
68f95f6130 Merge branch 'master' into tweakCMPageLineBrightness 2024-06-08 10:05:12 +12:00
Trevor Buckner
35ae5e09ee Merge branch 'master' into issue_2994_css_style 2024-06-07 15:04:26 -04:00
Trevor Buckner
552a23585b Merge pull request #3524 from naturalcrit/dependabot/npm_and_yarn/eslint-plugin-jest-28.6.0
Bump eslint-plugin-jest from 28.5.0 to 28.6.0
2024-06-07 13:56:12 -04:00
Trevor Buckner
e635877b66 Merge branch 'master' into dependabot/npm_and_yarn/eslint-plugin-jest-28.6.0 2024-06-07 13:53:49 -04:00
Trevor Buckner
954bcbdaf6 Merge pull request #3523 from naturalcrit/dependabot/npm_and_yarn/googleapis/drive-8.10.0
Bump @googleapis/drive from 8.8.0 to 8.10.0
2024-06-07 13:53:38 -04:00
dependabot[bot]
559de2527b Bump eslint-plugin-jest from 28.5.0 to 28.6.0
Bumps [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) from 28.5.0 to 28.6.0.
- [Release notes](https://github.com/jest-community/eslint-plugin-jest/releases)
- [Changelog](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jest-community/eslint-plugin-jest/compare/v28.5.0...v28.6.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-07 16:44:09 +00:00
dependabot[bot]
4c14774f1a Bump @googleapis/drive from 8.8.0 to 8.10.0
Bumps [@googleapis/drive](https://github.com/googleapis/google-api-nodejs-client) from 8.8.0 to 8.10.0.
- [Release notes](https://github.com/googleapis/google-api-nodejs-client/releases)
- [Changelog](https://github.com/googleapis/google-api-nodejs-client/blob/main/release-please-config.json)
- [Commits](https://github.com/googleapis/google-api-nodejs-client/compare/drive-v8.8.0...drive-v8.10.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-07 16:44:07 +00:00
Trevor Buckner
ea380ae6a9 Merge pull request #3521 from naturalcrit/dependabot/npm_and_yarn/babel/preset-env-7.24.7
Bump @babel/preset-env from 7.24.5 to 7.24.7
2024-06-07 12:43:17 -04:00
dependabot[bot]
e2a946674f Bump @babel/preset-env from 7.24.5 to 7.24.7
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.24.5 to 7.24.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.24.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-06-07 16:27:54 +00:00
Trevor Buckner
75926e34a2 Merge pull request #3520 from naturalcrit/dependabot/npm_and_yarn/babel/core-7.24.7
Bump @babel/core from 7.24.5 to 7.24.7
2024-06-07 12:27:07 -04:00
dependabot[bot]
37bc37bd94 Bump @babel/core from 7.24.5 to 7.24.7
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.24.5 to 7.24.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.24.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-06-07 16:05:03 +00:00
Trevor Buckner
528359dd9f Merge pull request #3519 from naturalcrit/dependabot/npm_and_yarn/babel/plugin-transform-runtime-7.24.7
Bump @babel/plugin-transform-runtime from 7.24.3 to 7.24.7
2024-06-07 12:04:28 -04:00
dependabot[bot]
f745fdefb3 Bump @babel/plugin-transform-runtime from 7.24.3 to 7.24.7
Bumps [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-runtime) from 7.24.3 to 7.24.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.24.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-06-07 15:59:39 +00:00
Trevor Buckner
2d9b80a81e Merge pull request #3510 from naturalcrit/dependabot/npm_and_yarn/dompurify-3.1.5
Bump dompurify from 3.1.4 to 3.1.5
2024-06-07 11:58:48 -04:00
Trevor Buckner
299acfb92c Merge branch 'master' into dependabot/npm_and_yarn/dompurify-3.1.5 2024-06-07 11:53:17 -04:00
Trevor Buckner
8fc97493c5 Merge pull request #3500 from naturalcrit/dependabot/npm_and_yarn/eslint-plugin-react-7.34.2
Bump eslint-plugin-react from 7.34.1 to 7.34.2
2024-06-07 11:53:05 -04:00
dependabot[bot]
7c7c6341f9 Bump dompurify from 3.1.4 to 3.1.5
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.1.4 to 3.1.5.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.1.4...3.1.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-07 15:45:45 +00:00
dependabot[bot]
227ab192c4 Bump eslint-plugin-react from 7.34.1 to 7.34.2
Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.34.1 to 7.34.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.34.1...v7.34.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-06-07 15:45:42 +00:00
Trevor Buckner
ad48c0cd76 Merge pull request #3509 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.4.1
Bump mongoose from 8.4.0 to 8.4.1
2024-06-07 11:44:53 -04:00
Trevor Buckner
958b168906 Merge branch 'master' into dependabot/npm_and_yarn/mongoose-8.4.1 2024-06-07 11:37:17 -04:00
Trevor Buckner
51d4b5042c Merge pull request #3518 from naturalcrit/dependabot/npm_and_yarn/babel/preset-react-7.24.7
Bump @babel/preset-react from 7.24.1 to 7.24.7
2024-06-07 11:37:02 -04:00
Trevor Buckner
371ac9680c Merge branch 'master' into dependabot/npm_and_yarn/babel/preset-react-7.24.7 2024-06-07 11:32:45 -04:00
Trevor Buckner
f68af555de Merge pull request #3382 from G-Ambatte/addLockNotification-#3326
Add blocking notification to EditPage
2024-06-07 11:32:07 -04:00
Trevor Buckner
66fdf808a6 Lint renderWarnings.less 2024-06-07 11:29:02 -04:00
Trevor Buckner
65770782c2 Lint lockNotification.less 2024-06-07 11:28:30 -04:00
Trevor Buckner
fdf6acd80a Lint notificationPopup.less 2024-06-07 11:27:51 -04:00
Trevor Buckner
08b61a6bb4 Cleanup comments. Fix Indentation. 2024-06-07 11:26:47 -04:00
G.Ambatte
33c2bee873 Remove unused useState 2024-06-07 16:05:14 +12:00
G.Ambatte
8bbf2e1ce4 Dim background while Modal displayed 2024-06-07 11:25:34 +12:00
G.Ambatte
476002ae4d Tweak notificationPopup.less
Stop the notification from covering the renderWarning when both are present
2024-06-07 11:01:47 +12:00
G.Ambatte
54ec1b8827 Comment out dialog.less reference 2024-06-07 10:50:57 +12:00
Trevor Buckner
7bb92bc790 Refactor slightly 2024-06-06 18:10:04 -04:00
G.Ambatte
a87d62c9c2 Tweak page line brightness
As per Reddit report (https://redd.it/1d8opte), on dark CodeMirror themes, it can be difficult to read the folded text between the bright backgrounds of `\page` lines.
This PR tweaks the brightness down slightly by reducing opacity of the background from 75% to 50%.
2024-06-07 09:30:09 +12:00
G.Ambatte
8c315980e9 Revert dismiss styling to opacity change on hover 2024-06-06 22:37:01 +12:00
G.Ambatte
359a64968c Nudge popups left 2024-06-06 22:31:05 +12:00
G.Ambatte
866548deec Move renderWarnings to use Dialog 2024-06-06 22:12:13 +12:00
G.Ambatte
ed39852a8f Move dialog[open] to Dialog component styling 2024-06-06 22:00:28 +12:00
G.Ambatte
38fc647495 Change NotificationPopup to inline-block from block 2024-06-06 21:46:34 +12:00
G.Ambatte
fa7b3ea2a0 Shift dismiss button, tweak local storage check 2024-06-06 21:41:33 +12:00
G.Ambatte
9e041d26bd Fix display property on dialog causing close() to not work 2024-06-06 21:40:54 +12:00
dependabot[bot]
978c0c4c7b Bump @babel/preset-react from 7.24.1 to 7.24.7
Bumps [@babel/preset-react](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-react) from 7.24.1 to 7.24.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.24.7/packages/babel-preset-react)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-06 03:01:32 +00:00
G.Ambatte
4f4cef0f6c Tweak LockNotification styling 2024-06-06 12:02:07 +12:00
G.Ambatte
556ded9b08 Tweak Dialog to work with showModal and show LockNotifications 2024-06-06 12:01:55 +12:00
G.Ambatte
0efcd5d258 Shift LockNotification to use Dialog 2024-06-05 13:03:26 +12:00
G.Ambatte
31b6e0c4f6 Show dialog when dismissKey prop is not specified 2024-06-05 12:33:13 +12:00
Trevor Buckner
423413e41b Merge branch 'master' into addLockNotification-#3326 2024-06-04 16:23:00 -04:00
G.Ambatte
ec514cdb51 Set local storage only if dismissKey prop exists 2024-06-05 07:49:29 +12:00
Trevor Buckner
7272544724 Convert LockNotification.jsx to functional component 2024-06-04 14:53:19 -04:00
Trevor Buckner
99ff7fdf14 linting 2024-06-04 12:32:21 -04:00
Trevor Buckner
491b38c330 Small cleanup of Dialog component
Reduce number of `useEffects` needed
2024-06-04 12:29:13 -04:00
Trevor Buckner
4033d3ad99 Merge pull request #3513 from naturalcrit/propagateEventsToNavButtons
Pass click events to click handler on Nav items
2024-06-04 10:24:14 -04:00
Trevor Buckner
9285d355b2 Merge branch 'master' into propagateEventsToNavButtons 2024-06-04 10:22:12 -04:00
G.Ambatte
24e67e2270 Restore Info Circle to notification 2024-06-04 17:47:17 +12:00
G.Ambatte
5f6d5f53cc Change dismiss button to use fa-dismiss 2024-06-04 17:38:06 +12:00
G.Ambatte
865c5678bc Change all Modal references to Dialog 2024-06-04 17:34:26 +12:00
G.Ambatte
05ba7b41d1 Tweak NotificationPopup 2024-06-04 17:29:34 +12:00
G.Ambatte
e7735e242a Add closeText prop 2024-06-04 17:28:29 +12:00
G.Ambatte
1111d8275c Tweak dismiss button styling 2024-06-04 17:27:45 +12:00
G.Ambatte
f3b01bc75c Fix for modals 2024-06-04 16:51:43 +12:00
G.Ambatte
8685c5cae4 Break Dialog out of NotificationPopup, restore NotificationPopup to original position 2024-06-04 16:26:51 +12:00
dependabot[bot]
e0a457bf40 Bump mongoose from 8.4.0 to 8.4.1
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.4.0 to 8.4.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.4.0...8.4.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-06-03 03:05:35 +00:00
David Bolack
d20c9c502c Merge branch 'issue_2994_css_style' of github.com:dbolacksn/homebrewery-broken into issue_2994_css_style 2024-06-01 00:35:39 -05:00
David Bolack
8c5e68e571 Merge branch 'master' into issue_2994_css_style 2024-06-01 00:34:43 -05:00
David Bolack
fbe65a4e93 Resolve indentation errors in TOC Generation, adjust partCover class
This fixes an error in the recusion that was failing to add children under existing parents.
Index generation now does not overindent when levels are skipped.
PartCover less code as suggesred by CC.
2024-06-01 00:32:25 -05:00
David Bolack
3875dabfd2 Merge branch 'master' of github.com:naturalcrit/homebrewery 2024-05-31 23:32:39 -05:00
G.Ambatte
930709223a Lint fix 2024-06-01 12:42:40 +12:00
G.Ambatte
a6ce36689c Shift NotificationPopup to shared components & update BrewRenderer ref 2024-06-01 12:38:01 +12:00
G.Ambatte
2424d34682 Merge branch 'master' into addLockNotification-#3326 2024-06-01 12:14:04 +12:00
Trevor Buckner
8fc224e9a1 Update themes/V3/5ePHB/snippets.js 2024-05-28 17:33:52 -04:00
Trevor Buckner
98fc007efd Merge branch 'master' into issue_2994_css_style 2024-05-28 17:31:14 -04:00
Trevor Buckner
7fb23c7362 Pass click events to click handler 2024-05-28 16:25:39 -04:00
Trevor Buckner
a2f0546a6d Merge pull request #3491 from naturalcrit/Print-directly-from-edit/share-page
Print directly from Edit/Share/New pages
2024-05-28 16:14:08 -04:00
Trevor Buckner
8a55658bd7 Rename printPage function to printCurrentBrew()
Avoid confusion with other "page" components.
2024-05-28 16:11:18 -04:00
Trevor Buckner
01d60c4520 lint 2024-05-28 13:22:33 -04:00
Trevor Buckner
b4349a0476 iframe hotkey printing only works in Edit/Share/New
Default browser printing still works
2024-05-28 12:51:58 -04:00
Trevor Buckner
695b9916dd Remove old /print page 2024-05-28 12:39:43 -04:00
Trevor Buckner
ac3168e365 Move "printPage()" to helpers.js for reuse in multiple pages 2024-05-24 19:28:02 -04:00
Trevor Buckner
e396211f92 remove duplicate button 2024-05-23 17:13:44 -04:00
Trevor Buckner
4ce68b86ed Fix hotkey printing on focused iframe 2024-05-23 17:09:03 -04:00
Trevor Buckner
24769d69d4 Force browser repaint after closing Print dialog 2024-05-23 17:08:24 -04:00
David Bolack
fc22e6cd53 Smidge of documentation 2024-05-22 23:17:22 -05:00
David Bolack
62ed026757 Hopeflly final class renaming sessions. 2024-05-22 21:25:10 -05:00
David Bolack
7cef4316d7 Flag Table of Contents as "Experimental" 2024-05-22 21:04:32 -05:00
David Bolack
0df53daa4c Another attempt at clearer classnames for the Table of contents snippet 2024-05-22 17:25:52 -05:00
David Bolack
b496ef3597 Remove completely redundant checks for class based exclusion from ToC Snippet 2024-05-22 16:34:00 -05:00
David Bolack
3ae5d4c1e3 Slight reworking of style naming for Table of Contents
Also uses :is operator for cleaner? looking CSS

Lastly, removes {{partCover}} from automatic exclusion.
2024-05-22 16:30:12 -05:00
Trevor Buckner
a227a792c0 Replace print redirect with print contentWindow on all pages 2024-05-22 15:54:01 -04:00
David Bolack
d9d4d74b71 Add CR wrappers around addTOC snippet insertions. 2024-05-22 12:44:19 -05:00
David Bolack
af82d71e4f Merge branch 'master' into issue_2994_css_style 2024-05-22 11:52:43 -05:00
David Bolack
f897cbfdf4 Merge branch 'master' of github.com:naturalcrit/homebrewery 2024-05-22 11:51:45 -05:00
David Bolack
1773e77cb9 Fix missed issues with converting to delightfully recursive function 2024-05-22 11:47:12 -05:00
Trevor Buckner
dcd34ccdaf Merge pull request #3477 from Gazook89/fix-refs
Fix `ref` issues
2024-05-21 17:50:07 -04:00
Trevor Buckner
2453b623db tweak names in editor.jsx 2024-05-21 17:45:50 -04:00
Trevor Buckner
783e88b5e6 Merge branch 'master' into pr/3477 2024-05-21 17:42:03 -04:00
Trevor Buckner
77c0af42d0 Merge pull request #3489 from naturalcrit/dependabot/npm_and_yarn/dompurify-3.1.4
Bump dompurify from 3.1.1 to 3.1.4
2024-05-21 17:35:56 -04:00
Trevor Buckner
c21b4eb2d6 Merge branch 'master' into dependabot/npm_and_yarn/dompurify-3.1.4 2024-05-21 17:35:48 -04:00
Trevor Buckner
6043af81e4 Merge pull request #3470 from naturalcrit/dependabot/npm_and_yarn/react-router-dom-6.23.1
Bump react-router-dom from 6.23.0 to 6.23.1
2024-05-21 17:35:36 -04:00
Trevor Buckner
7c3321b62f Merge branch 'master' into dependabot/npm_and_yarn/react-router-dom-6.23.1 2024-05-21 17:34:17 -04:00
Trevor Buckner
d1955951e4 Merge pull request #3490 from naturalcrit/LintingPass
Lint a bunch of things
2024-05-21 17:33:45 -04:00
Trevor Buckner
e62e185214 Lint a bunch of things 2024-05-21 17:32:17 -04:00
Trevor Buckner
0c38415372 Merge pull request #3482 from 5e-Cleric/clean-up-unused-constants-and-requires
Clean up unused declarations
2024-05-21 17:29:28 -04:00
Trevor Buckner
73f879aa63 Merge branch 'master' into clean-up-unused-constants-and-requires 2024-05-21 17:28:51 -04:00
Trevor Buckner
f12de7d953 Undo Journal path change 2024-05-21 17:28:17 -04:00
Trevor Buckner
933ac41774 Merge pull request #3420 from Gazook89/RPG-Awesome-Redux
RPG Awesome Redux
2024-05-21 16:30:00 -04:00
Trevor Buckner
54b4d490f1 Adjust hyphenation 2024-05-21 16:21:24 -04:00
Trevor Buckner
193af61725 Merge branch 'master' into pr/3420 2024-05-21 14:50:02 -04:00
David Bolack
511c9ffada Merge branch 'master' into issue_2994_css_style 2024-05-20 14:51:19 -05:00
David Bolack
ea03538552 Merge branch 'master' of github.com:naturalcrit/homebrewery 2024-05-20 13:33:20 -05:00
dependabot[bot]
8fb9f3f823 Bump dompurify from 3.1.1 to 3.1.4
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.1.1 to 3.1.4.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.1.1...3.1.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-20 17:39:53 +00:00
dependabot[bot]
7af919afd3 Bump react-router-dom from 6.23.0 to 6.23.1
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.23.0 to 6.23.1.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.23.1/packages/react-router-dom)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-20 17:39:49 +00:00
Trevor Buckner
5bbe4016d6 Merge pull request #3488 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.4.0
Bump mongoose from 8.3.3 to 8.4.0
2024-05-20 13:39:00 -04:00
dependabot[bot]
0f3312a5d7 Bump mongoose from 8.3.3 to 8.4.0
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.3.3 to 8.4.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.3.3...8.4.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-05-20 17:38:10 +00:00
Trevor Buckner
0bf432dd76 Merge pull request #3486 from naturalcrit/dependabot/npm_and_yarn/vitreum-9d55fd6
Bump vitreum from `49994da` to `9d55fd6`
2024-05-20 13:37:27 -04:00
dependabot[bot]
27b3da0144 Bump vitreum from 49994da to 9d55fd6
Bumps [vitreum](https://github.com/calculuschild/vitreum) from `49994da` to `9d55fd6`.
- [Commits](49994da405...9d55fd6fb7)

---
updated-dependencies:
- dependency-name: vitreum
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-20 03:13:40 +00:00
Trevor Buckner
b8b1b9660f Merge pull request #3404 from MurdoMaclachlan/master
Add proficiency bonus to monster statblocks
2024-05-18 17:28:38 -04:00
Trevor Buckner
f40d851d49 Merge branch 'master' into master 2024-05-17 16:53:58 -04:00
Víctor Losada Hernández
b64c835706 Aparently it wasn't redundant as VSCode said
This reverts commit aef6605225.
2024-05-17 22:38:54 +02:00
Víctor Losada Hernández
b7717171b3 Server and shared folders 2024-05-17 22:34:40 +02:00
Víctor Losada Hernández
92e27cda6c "Removed unused imports of 'classnames' and 'create-react-class' from various JSX files. in the Client folder" 2024-05-17 22:31:55 +02:00
Víctor Losada Hernández
aef6605225 Remove redundant snippetBar import from editor.jsx 2024-05-17 22:28:01 +02:00
Gazook89
7c9cc25923 update editor ref's in edit, home, and new pages. 2024-05-16 23:29:30 -05:00
Gazook89
78ce8aa6e3 remove unused ref attributes
from editPage, homePage, newPage, and printPage, as well as splitPane.   The refs were declared, but never used.
2024-05-16 23:25:22 -05:00
Gazook89
8ae22bdc27 fix refs in codeEditor.jsx 2024-05-16 23:15:54 -05:00
Gazook89
46c14ef23b fix refs in editor.jsx
now has refs `editorWrapper` and `editor`-- the former includes the snippet bar and codemirror editor, and the latter includes only the codemirror editor.
2024-05-16 23:12:10 -05:00
Trevor Buckner
d3080c03a4 Merge pull request #3432 from 5e-Cleric/fix-icon-fonts
Fix icon fonts
2024-05-16 17:22:39 -04:00
Trevor Buckner
12eead3379 Small typos 2024-05-16 17:19:13 -04:00
Trevor Buckner
a2e065c5d8 Adjustments to match Emojis PR 2024-05-16 17:04:02 -04:00
Trevor Buckner
0d1a3d55cf Merge branch 'master' into fix-icon-fonts 2024-05-16 16:53:54 -04:00
Gazook89
b748a597d2 some fixes post merge. 2024-05-15 21:25:45 -05:00
Gazook89
5fb0e123e3 install new dependencies from merging master 2024-05-15 20:50:52 -05:00
Gazook89
9a4a14fa97 add license, rename files for clarity, update references 2024-05-15 20:48:58 -05:00
Gazook89
0c76a546e4 Merge branch 'master' into RPG-Awesome-Redux 2024-05-15 20:19:00 -05:00
Trevor Buckner
fb299f898e Merge pull request #3434 from G-Ambatte/experimentalHTMLSanitization
Add DOM Purify to BrewRenderer
2024-05-15 17:07:42 -04:00
David Bolack
afb5ccec81 Slight Rearrange of ToC theme names and menu
Reorders ToC inclusion options with slight relabel for clarity.
Changes assumptions on H4, H5, and H6 snippets to assume H1-H3 class should be explicitly stated.

change naming of addToToCH# to tocH#

more explicitly define .addToC to h1 to h3 changes for --TOC var.
2024-05-12 12:00:55 -05:00
David Bolack
c0beae6e46 Remove redundant class declaration for ToC 2024-05-12 11:49:30 -05:00
David Bolack
9c6ece3e7f Merge branch 'master' into issue_2994_css_style 2024-05-12 11:37:51 -05:00
David Bolack
5494c02f00 Merge branch 'master' of github.com:naturalcrit/homebrewery 2024-05-12 10:23:14 -05:00
G.Ambatte
b4ee62a1bd Merge branch 'master' into experimentalHTMLSanitization 2024-05-11 08:58:21 +12:00
G.Ambatte
632efe8b9f Add Share ID to lock notification 2024-05-10 08:17:09 +12:00
G.Ambatte
bf38f95d25 Pass ID to Lock Notification 2024-05-10 08:05:29 +12:00
G.Ambatte
f6daeb4acd Update error message 2024-05-10 08:05:09 +12:00
G.Ambatte
10a7f34abb Update lock message 2024-05-10 07:45:04 +12:00
G.Ambatte
3a054f1ae0 Merge branch 'master' into addLockNotification-#3326 2024-05-10 07:15:40 +12:00
Víctor Losada Hernández
25b4b3d906 Merge branch 'master' into master 2024-05-09 08:50:51 +02:00
Víctor Losada Hernández
f21d636846 changes as requested 2024-05-09 08:00:02 +02:00
Víctor Losada Hernández
8365841b89 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into fix-icon-fonts 2024-05-09 07:59:31 +02:00
Víctor Losada Hernández
e6bf8b59a1 fix further errors 2024-05-09 07:49:17 +02:00
Trevor Buckner
b4a4934c5c Merge pull request #3405 from naturalcrit/EmojiSyntax
Emoji syntax
2024-05-08 15:55:01 -04:00
Trevor Buckner
a6b2dab9cc Linting 2024-05-08 14:53:24 -04:00
Trevor Buckner
d692e88b96 Merge branch 'EmojiSyntax' of https://github.com/naturalcrit/homebrewery into EmojiSyntax 2024-05-08 14:24:19 -04:00
Trevor Buckner
62c9e081e6 typos 2024-05-08 14:24:15 -04:00
Trevor Buckner
5a52e76ff0 Merge branch 'master' into EmojiSyntax 2024-05-08 11:01:15 -04:00
Trevor Buckner
3b1f4a0d13 Add Tests for emoji markdown 2024-05-08 09:51:29 -04:00
G.Ambatte
cdad9af453 Merge branch 'master' into experimentalHTMLSanitization 2024-05-08 23:30:49 +12:00
Trevor Buckner
5fd92ee72d Remove redundant font inclusion 2024-05-07 15:55:34 -04:00
Trevor Buckner
5bcd3a1b01 Clear up steps 2024-05-07 15:54:08 -04:00
Trevor Buckner
d49d9fd755 typo 2024-05-07 15:35:00 -04:00
Trevor Buckner
41d817823b Don't autosuggest emojis inside injectors 2024-05-07 15:30:56 -04:00
Trevor Buckner
cfffb4961b Rename files, add some instructions to markdown.js 2024-05-07 15:28:05 -04:00
Trevor Buckner
6bd2f4d98d Add rest of Font-Awesome icons 2024-05-07 15:07:30 -04:00
David Bolack
9d6076f642 Merge branch 'master' of github.com:naturalcrit/homebrewery 2024-05-06 11:59:20 -05:00
Trevor Buckner
dd82a1bebd Merge pull request #3457 from 5e-Cleric/icons-for-share-dropdown
icon for edit link in sharepage
2024-05-06 07:54:41 -04:00
Víctor Losada Hernández
d3f1fde9d9 icon for edit link 2024-05-06 07:43:45 +02:00
Trevor Buckner
d83e7bce0a Merge pull request #3456 from 5e-Cleric/icons-for-share-dropdown
Adding icons to the share dropdown
2024-05-05 21:43:40 -04:00
Trevor Buckner
8cd4a58304 Merge branch 'master' into icons-for-share-dropdown 2024-05-05 21:43:12 -04:00
Trevor Buckner
0ef683222d Merge pull request #3447 from 5e-Cleric/link-to-edit-if-author
Add edit link to share page if user is author
2024-05-05 21:42:25 -04:00
Trevor Buckner
ebbf162318 Merge branch 'master' into link-to-edit-if-author 2024-05-05 21:25:43 -04:00
Víctor Losada Hernández
268d202562 initial commit 2024-05-06 00:32:38 +02:00
G.Ambatte
4e0ec75e58 Revert template.js changes for separate PR 2024-05-06 09:46:34 +12:00
G.Ambatte
1af989c4a3 Case insensitive matching 2024-05-06 07:27:22 +12:00
G.Ambatte
53480fdd5f Merge branch 'master' into experimentalHTMLSanitization 2024-05-05 20:50:46 +12:00
G.Ambatte
ffa90c397c Add script sanitization to template.js 2024-05-05 20:18:53 +12:00
Trevor Buckner
df3d1078f1 Add FontAwesome Solid to emoji list 2024-05-05 01:50:38 -04:00
Trevor Buckner
22bdb85dff Convert dicefont and elderberry icon names to snake_case 2024-05-04 00:40:51 -04:00
Trevor Buckner
2f5081156d Merge pull request #3438 from naturalcrit/dependabot/npm_and_yarn/react-dom-18.3.1
Bump react-dom from 18.2.0 to 18.3.1
2024-05-03 21:56:23 -04:00
dependabot[bot]
c3f153a5fa Bump react-dom from 18.2.0 to 18.3.1
Bumps [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom) from 18.2.0 to 18.3.1.
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v18.3.1/packages/react-dom)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-04 01:54:01 +00:00
Trevor Buckner
5e0dda1bde Merge pull request #3437 from naturalcrit/dependabot/npm_and_yarn/react-18.3.1
Bump react from 18.2.0 to 18.3.1
2024-05-03 21:52:58 -04:00
Trevor Buckner
b0379b0821 Merge branch 'master' into EmojiSyntax 2024-05-03 21:47:55 -04:00
dependabot[bot]
c506c9cee5 Bump react from 18.2.0 to 18.3.1
Bumps [react](https://github.com/facebook/react/tree/HEAD/packages/react) from 18.2.0 to 18.3.1.
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v18.3.1/packages/react)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-04 01:47:47 +00:00
Trevor Buckner
9184593bc0 Merge pull request #3442 from naturalcrit/dependabot/npm_and_yarn/babel/core-7.24.5
Bump @babel/core from 7.24.4 to 7.24.5
2024-05-03 21:46:46 -04:00
dependabot[bot]
1da70d54e8 Bump @babel/core from 7.24.4 to 7.24.5
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.24.4 to 7.24.5.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.24.5/packages/babel-core)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-04 01:45:56 +00:00
Trevor Buckner
55cdd016da Merge pull request #3455 from naturalcrit/addMarkedEmojiPackage
Just installs the marked-emoji package
2024-05-03 21:44:53 -04:00
Trevor Buckner
10997898b9 Just installs the marked-emoji package 2024-05-03 21:43:53 -04:00
Trevor Buckner
76b66977e9 Update with master 2024-05-03 21:41:41 -04:00
Trevor Buckner
d695648d9b Tweaks to Editor highlighting. Maybe still ugly. 2024-05-03 21:40:09 -04:00
Trevor Buckner
72160f5daf missed one commit 2024-05-03 21:40:09 -04:00
Trevor Buckner
0751da42b6 Add emoji highlighting to editor 2024-05-03 21:40:08 -04:00
Trevor Buckner
babe1f30a2 Prevent autosuggest inside curly span/div properties 2024-05-03 21:40:08 -04:00
Trevor Buckner
cd35e91ea2 add elderberryInn to emoji syntax 2024-05-03 21:40:08 -04:00
Trevor Buckner
8d8a965241 Rename font-icons to elderberryInn 2024-05-03 21:40:08 -04:00
Trevor Buckner
2309887c92 Change diceFont to camelCase to match existing naming convention 2024-05-03 21:40:08 -04:00
Trevor Buckner
d36e6e5834 Hack to avoid conflict with emojis 2024-05-03 21:40:07 -04:00
Trevor Buckner
dd205a14bc typo 2024-05-03 21:40:07 -04:00
Trevor Buckner
d854fe1202 Clean up redundant code 2024-05-03 21:40:07 -04:00
Trevor Buckner
58f487ac58 Sort alphabetically and numerically
i.e.,

"d2, d6, d8, d10, d12, d20", not "d10, d12, d2, d20, d6, d8"
2024-05-03 21:40:07 -04:00
Trevor Buckner
1761c506be Exclude : from the autocomplete trigger 2024-05-03 21:40:07 -04:00
Trevor Buckner
9f19514b03 CodeMirror Dropdown working 2024-05-03 21:40:07 -04:00
Trevor Buckner
ade1056a02 Include Dicefont 2024-05-03 21:40:07 -04:00
Trevor Buckner
e5fecaf9b6 Include marked-emoji package 2024-05-03 21:40:06 -04:00
Trevor Buckner
5b8b0aa641 Merge pull request #3443 from naturalcrit/dependabot/npm_and_yarn/superagent-9.0.2
Bump superagent from 9.0.1 to 9.0.2
2024-05-03 21:35:29 -04:00
Trevor Buckner
b7bc5cbad7 Merge branch 'master' into dependabot/npm_and_yarn/superagent-9.0.2 2024-05-03 21:33:37 -04:00
Trevor Buckner
f2fc47a719 Merge pull request #3454 from naturalcrit/cleanUpMustacheTests
Just linting and spacing for mustache-syntax.tests.js
2024-05-03 21:32:57 -04:00
Trevor Buckner
a5f9ab7897 Merge branch 'master' into cleanUpMustacheTests 2024-05-03 21:32:40 -04:00
Trevor Buckner
39368c1a38 Merge branch 'master' into fix-icon-fonts 2024-05-03 21:31:31 -04:00
Trevor Buckner
d879cf3cbb Merge pull request #3451 from naturalcrit/dependabot/npm_and_yarn/eslint-plugin-jest-28.5.0
Bump eslint-plugin-jest from 28.2.0 to 28.5.0
2024-05-03 21:31:15 -04:00
Trevor Buckner
ae59c56ddd Merge branch 'master' into dependabot/npm_and_yarn/eslint-plugin-jest-28.5.0 2024-05-03 21:30:40 -04:00
Trevor Buckner
35431384bd Merge pull request #3453 from naturalcrit/dependabot/npm_and_yarn/googleapis/drive-8.8.0
Bump @googleapis/drive from 8.7.0 to 8.8.0
2024-05-03 21:30:26 -04:00
dependabot[bot]
dd31c0138b Bump @googleapis/drive from 8.7.0 to 8.8.0
Bumps [@googleapis/drive](https://github.com/googleapis/google-api-nodejs-client) from 8.7.0 to 8.8.0.
- [Release notes](https://github.com/googleapis/google-api-nodejs-client/releases)
- [Changelog](https://github.com/googleapis/google-api-nodejs-client/blob/main/release-please-config.json)
- [Commits](https://github.com/googleapis/google-api-nodejs-client/compare/drive-v8.7.0...drive-v8.8.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-04 01:24:32 +00:00
dependabot[bot]
11f1e3fee8 Bump eslint-plugin-jest from 28.2.0 to 28.5.0
Bumps [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) from 28.2.0 to 28.5.0.
- [Release notes](https://github.com/jest-community/eslint-plugin-jest/releases)
- [Changelog](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jest-community/eslint-plugin-jest/compare/v28.2.0...v28.5.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-04 01:23:59 +00:00
Trevor Buckner
aaaa8ed693 Merge pull request #3446 from naturalcrit/makeCurlyInjectorsAppendNotOverwrite
Make Curly Injectors append properties, not overwrite
2024-05-03 21:23:01 -04:00
Víctor Losada Hernández
fec6bf290b Merge branch 'master' into makeCurlyInjectorsAppendNotOverwrite 2024-05-04 01:27:36 +02:00
Trevor Buckner
2418e42655 Align input texts for mustache tests 2024-05-03 17:10:12 -04:00
Trevor Buckner
dce86580ce Added additional tests for injection 2024-05-03 17:02:12 -04:00
Trevor Buckner
f6997871be Try to make tests work on both circleCI and windows 2024-05-03 15:01:21 -04:00
Trevor Buckner
660a586a7c Clarify comments 2024-05-03 15:01:04 -04:00
Trevor Buckner
193cde0925 Passes all tests 2024-05-03 14:31:34 -04:00
Trevor Buckner
1a33e6e631 Passing almost all tests 2024-05-03 12:48:19 -04:00
Trevor Buckner
bb8ade435d Now passing many previously failing tests 2024-05-03 12:40:03 -04:00
Trevor Buckner
94905f8151 Back to passing all tests (not the "failing" tests yet) 2024-05-03 12:12:55 -04:00
Víctor Losada Hernández
05a30f00e3 Merge branch 'master' into link-to-edit-if-author 2024-05-02 11:39:48 +02:00
Víctor Losada Hernández
3c1f8804af initial commit 2024-05-02 11:38:00 +02:00
Trevor Buckner
716e3d7143 Merge pull request #3428 from 5e-Cleric/paint-order-fix
drop shadow filter to text stroke
2024-05-01 17:21:15 -04:00
Víctor Losada Hernández
a0e6487a7b Merge branch 'master' into paint-order-fix 2024-05-01 21:58:31 +02:00
Víctor Losada Hernández
076599f05c to cm 2024-05-01 21:58:15 +02:00
Trevor Buckner
9fb0f37718 Pass CSS props from curly spans/divs as an object for finer control 2024-04-30 23:52:19 -04:00
David Bolack
b86502aec7 Merge branch 'master' of github.com:naturalcrit/homebrewery 2024-04-30 21:35:29 -05:00
dependabot[bot]
822f8a2cd0 Bump superagent from 9.0.1 to 9.0.2
Bumps [superagent](https://github.com/ladjs/superagent) from 9.0.1 to 9.0.2.
- [Release notes](https://github.com/ladjs/superagent/releases)
- [Changelog](https://github.com/ladjs/superagent/blob/master/HISTORY.md)
- [Commits](https://github.com/ladjs/superagent/compare/v9.0.1...v9.0.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-30 14:10:06 -04:00
Trevor Buckner
d2965e1122 Merge pull request #3444 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.3.3
Bump mongoose from 8.3.2 to 8.3.3
2024-04-30 14:09:57 -04:00
dependabot[bot]
37e211937c Bump mongoose from 8.3.2 to 8.3.3
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.3.2 to 8.3.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.3.2...8.3.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-04-30 14:08:20 -04:00
Trevor Buckner
e7a03dc7d6 Merge pull request #3445 from naturalcrit/dependabot/npm_and_yarn/babel/preset-env-7.24.5
Bump @babel/preset-env from 7.24.4 to 7.24.5
2024-04-30 14:07:57 -04:00
Trevor Buckner
a469b88fd2 Merge branch 'master' into dependabot/npm_and_yarn/babel/preset-env-7.24.5 2024-04-30 14:05:44 -04:00
Trevor Buckner
45244c8e5d Merge pull request #3407 from Gazook89/errorPage.jsx-cleanup
Convert errorPage.jsx to functional component.
2024-04-30 13:43:20 -04:00
Trevor Buckner
fad5817353 Merge branch 'master' into errorPage.jsx-cleanup 2024-04-30 13:41:10 -04:00
Trevor Buckner
c0a8b79acc Small tweak 2024-04-30 13:40:39 -04:00
dependabot[bot]
34a41fd610 Bump @babel/preset-env from 7.24.4 to 7.24.5
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.24.4 to 7.24.5.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.24.5/packages/babel-preset-env)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-30 03:58:07 +00:00
G.Ambatte
eb0440d36d Fix ID removal 2024-04-28 01:13:12 +12:00
G.Ambatte
cd82db16d5 Add DOMPurify config options 2024-04-28 00:49:03 +12:00
G.Ambatte
bdad601ebc Remove now-obsolete sanitization function 2024-04-27 23:58:55 +12:00
G.Ambatte
97a74902ef Add DOMPurify to BrewRenderer 2024-04-27 23:58:23 +12:00
G.Ambatte
ab30b6a799 Add DOM-Purify package 2024-04-27 23:38:55 +12:00
Víctor Losada Hernández
da6bc497fc eldeberry misstype rise dead 2024-04-26 23:07:06 +02:00
Trevor Buckner
06c3168868 Merge pull request #3429 from naturalcrit/dependabot/npm_and_yarn/multi-812b0dc3fc
Bump formidable, superagent and supertest
2024-04-25 10:45:55 -04:00
dependabot[bot]
86be90adb2 Bump formidable, superagent and supertest
Bumps [formidable](https://github.com/node-formidable/formidable) to 3.5.1 and updates ancestor dependencies [formidable](https://github.com/node-formidable/formidable), [superagent](https://github.com/ladjs/superagent) and [supertest](https://github.com/ladjs/supertest). These dependencies need to be updated together.


Updates `formidable` from 2.1.2 to 3.5.1
- [Release notes](https://github.com/node-formidable/formidable/releases)
- [Changelog](https://github.com/node-formidable/formidable/blob/master/CHANGELOG.md)
- [Commits](https://github.com/node-formidable/formidable/commits/v3.5.1)

Updates `superagent` from 8.1.2 to 9.0.1
- [Release notes](https://github.com/ladjs/superagent/releases)
- [Changelog](https://github.com/ladjs/superagent/blob/master/HISTORY.md)
- [Commits](https://github.com/ladjs/superagent/compare/v8.1.2...v9.0.1)

Updates `supertest` from 6.3.4 to 7.0.0
- [Release notes](https://github.com/ladjs/supertest/releases)
- [Commits](https://github.com/ladjs/supertest/compare/v6.3.4...v7.0.0)

---
updated-dependencies:
- dependency-name: formidable
  dependency-type: indirect
- dependency-name: superagent
  dependency-type: direct:production
- dependency-name: supertest
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-25 14:28:34 +00:00
Trevor Buckner
a296678d20 Merge pull request #3409 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.3.2
Bump mongoose from 8.3.1 to 8.3.2
2024-04-25 10:27:36 -04:00
Trevor Buckner
f768990fb1 Merge branch 'master' into dependabot/npm_and_yarn/mongoose-8.3.2 2024-04-25 09:39:13 -04:00
Trevor Buckner
313543d0d1 Merge pull request #3424 from naturalcrit/dependabot/npm_and_yarn/react-router-dom-6.23.0
Bump react-router-dom from 6.22.3 to 6.23.0
2024-04-25 09:39:03 -04:00
Víctor Losada Hernández
2ebe8d80e9 fix ei poison piercing 2024-04-25 15:15:07 +02:00
Víctor Losada Hernández
8c20422fef initial commit 2024-04-25 15:09:25 +02:00
dependabot[bot]
2197a9b782 Bump react-router-dom from 6.22.3 to 6.23.0
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.22.3 to 6.23.0.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.23.0/packages/react-router-dom)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-24 03:27:56 +00:00
Gazook89
928a8b351e Merge branch 'master' into RPG-Awesome-Redux 2024-04-21 20:12:56 -05:00
David Bolack
2a148cb138 Update Menus and standardize CSS Names
Update addh4, addh5, addh6 class names to addToCH4, addToCH5, addToCH6
Update menu items for Table of contents with better labels and addToC
2024-04-20 21:53:02 -05:00
David Bolack
9426c6acd9 Merge branch 'issue_2994_css_style' of github.com:dbolacksn/homebrewery-broken into issue_2994_css_style 2024-04-20 21:48:13 -05:00
David Bolack
90ce48b170 Adapt Recursive Toc function from 3254 2024-04-20 21:46:32 -05:00
David Bolack
448af683a0 Merge branch 'master' into issue_2994_css_style 2024-04-20 21:36:42 -05:00
David Bolack
ec5f8254f1 Merge branch 'master' of github.com:naturalcrit/homebrewery 2024-04-20 19:12:29 -05:00
Gazook89
7ca38b88ad add RPG awesome icons
This branch just does the same thing as the RPG Awesome repo, but more closely aligns with the code used in the other icon fonts and isn't an NPM package.
2024-04-19 23:15:02 -05:00
G.Ambatte
9f31a2c8a2 I can spell, honest 2024-04-20 14:06:33 +12:00
G.Ambatte
09cf5a9b04 Fix test 2024-04-20 14:02:46 +12:00
G.Ambatte
4c6953a4e0 Differentiate between Edit and Share messages 2024-04-20 13:57:33 +12:00
G.Ambatte
b4b4fbe375 Update fixed text and add REMOVAL button (NYI) 2024-04-20 13:50:10 +12:00
G.Ambatte
4bc07ceb4e Nudge line and button spacing 2024-04-20 13:49:36 +12:00
G.Ambatte
fde1706a0c Merge branch 'master' into addLockNotification-#3326 2024-04-20 12:55:44 +12:00
Trevor Buckner
1891d7c90a Merge branch 'master' into dependabot/npm_and_yarn/mongoose-8.3.2 2024-04-19 12:10:55 -04:00
Trevor Buckner
98d032913b Update pr-check.yml 2024-04-19 12:00:11 -04:00
Trevor Buckner
80bcf92fa3 Update pr-check.yml 2024-04-19 11:57:44 -04:00
Trevor Buckner
41d536b7ff Merge pull request #3418 from naturalcrit/calculuschild-patch-2
Rename limit-pull-requests.yml to action.yml
2024-04-19 11:50:14 -04:00
Trevor Buckner
83103a893a add elderberryInn to emoji syntax 2024-04-18 23:06:21 -04:00
Trevor Buckner
8cbc7a68e5 Rename font-icons to elderberryInn 2024-04-18 23:06:02 -04:00
Trevor Buckner
1177fd721c Change diceFont to camelCase to match existing naming convention 2024-04-18 16:57:35 -04:00
Trevor Buckner
2c8908850b Merge branch 'master' into EmojiSyntax 2024-04-18 16:52:38 -04:00
Trevor Buckner
4622a74786 Merge branch 'master' into EmojiSyntax 2024-04-17 01:08:19 -04:00
Trevor Buckner
72cfca1158 Hack to avoid conflict with emojis 2024-04-17 00:56:43 -04:00
dependabot[bot]
67d824cac9 Bump mongoose from 8.3.1 to 8.3.2
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.3.1 to 8.3.2.
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Automattic/mongoose/compare/8.3.1...8.3.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-17 03:56:30 +00:00
Trevor Buckner
4f010d77e8 typo 2024-04-14 16:06:43 -04:00
Trevor Buckner
3b1f9b10e7 Clean up redundant code 2024-04-14 16:06:12 -04:00
Trevor Buckner
5e33d8b6c4 Sort alphabetically and numerically
i.e.,

"d2, d6, d8, d10, d12, d20", not "d10, d12, d2, d20, d6, d8"
2024-04-14 16:02:04 -04:00
Trevor Buckner
f7a2509405 Exclude : from the autocomplete trigger 2024-04-14 15:38:01 -04:00
Gazook89
52904eea09 add a comment 2024-04-13 20:47:38 -05:00
Gazook89
ff84ded547 Convert page to functional component 2024-04-13 11:10:43 -05:00
Gazook89
6220e4f63f Remove unused defaultProps
The defaultProps are not used, and may be a relic of previous error page function.
2024-04-13 10:30:04 -05:00
Trevor Buckner
b0c2521101 CodeMirror Dropdown working 2024-04-12 14:12:30 -04:00
Murdo B. Maclachlan
30d2a03fd0 Added proficiency bonus to monster statblocks 2024-04-12 11:19:48 +01:00
Trevor Buckner
61a4b558a8 Include Dicefont 2024-04-10 18:25:45 -04:00
Trevor Buckner
3771d4bfd8 Include marked-emoji package 2024-04-10 17:50:33 -04:00
Trevor Buckner
b087e849b5 Merge branch 'master' into issue_2994_css_style 2024-04-10 17:27:12 -04:00
G.Ambatte
963ec282d3 Initial functionality pass 2024-03-29 20:06:16 +13:00
David Bolack
7690fb9287 Return .addToC for inline mustaches 2024-03-26 09:39:15 -05:00
David Bolack
2e54520b32 Merge branch 'master' into issue_2994_css_style 2024-03-25 19:39:01 -05:00
David Bolack
cdf5b29ac2 Remove !important from toc.h4/h5/h6 --TOC 2024-03-25 19:38:26 -05:00
David Bolack
733b929940 Integrate code recursion from 3254. 2024-03-25 19:36:30 -05:00
David Bolack
211fe48e29 Attempt to block H4-h6 from existing ToCs from showing up in a new ToC. 2024-03-25 19:06:38 -05:00
David Bolack
9d3f7fe556 Fix H3-H6 entries in ToC generation 2024-03-25 18:58:29 -05:00
David Bolack
5d87508d0e Merge branch 'master' of github.com:naturalcrit/homebrewery 2024-03-25 18:09:43 -05:00
David Bolack
40d0e7e90e Trim space off of ToC entries. 2024-03-25 16:32:03 -05:00
David Bolack
7ca10ff5a4 Add requested additions to code
Add snippet additions to handle Add h4, Add h4-h5, add h4-h6
Add collection of headers h4-h6 and rendering of h4 to h6.
2024-03-25 16:13:07 -05:00
dbolack
1705e66be2 Corrections per PR
Remove off by one error realted to change in page number detection.
Dewrap quotes from exclude screen.
2024-03-23 18:57:53 -05:00
dbolack
1e4f804542 Merge branch 'issue_2994_css_style' of github.com:dbolacksn/homebrewery-broken into issue_2994_css_style 2024-03-23 18:54:05 -05:00
dbolacksn
6a03be9d64 Merge branch 'master' into issue_2994_css_style 2024-03-23 18:53:52 -05:00
dbolack
591278862a Merge branch 'master' into issue_2994_css_style 2024-03-23 18:52:33 -05:00
David Bolack
9848e4b600 Merge branch 'master' of github.com:naturalcrit/homebrewery 2024-03-23 05:59:29 -05:00
David Bolack
f0a8020189 Merge branch 'master' of github.com:naturalcrit/homebrewery 2024-03-19 19:18:43 -05:00
David Bolack
a957ea37f6 Merge branch 'issue_2994_css_style' of github.com:dbolacksn/homebrewery-broken into issue_2994_css_style 2024-03-04 16:38:50 -06:00
David Bolack
a4d426bc00 Merge branch 'master' into issue_2994_css_style 2024-03-04 16:38:00 -06:00
David Bolack
41d43e84a5 Merge branch 'master' into issue_2994_css_style 2024-02-14 09:42:23 -06:00
David Bolack
bfd3eff6f2 Merge branch 'master' into issue_2994_css_style 2024-02-07 20:34:21 -06:00
David Bolack
75c41f4466 Merge branch 'issue_2994_css_style' of github.com:dbolacksn/homebrewery-broken into issue_2994_css_style 2024-01-29 20:18:01 -06:00
David Bolack
85caf0a892 Add fixes to account for no page numbers
Clear out manual toggles.
2024-01-29 20:14:52 -06:00
David Bolack
692205b0e6 Merge branch 'master' into issue_2994_css_style 2024-01-29 20:03:24 -06:00
David Bolack
02e6a3df99 Merge branch 'master' into issue_2994_css_style 2024-01-25 00:17:13 -06:00
David Bolack
b8ee696b69 Add manual exclusion classes for ToC exclusion. 2024-01-24 15:42:22 -06:00
David Bolack
26c4b1afa6 Add toggle-on classes. 2024-01-21 08:58:14 -06:00
David Bolack
622827efda Fix Exclusion examination 2024-01-20 20:47:27 -06:00
David Bolack
854c21639a CSS based ToC exclusion system
either I am building the lookup incorrectly or Chrome is not letting me
see variables via computedStyles.
2024-01-20 11:58:17 -06:00
83 changed files with 5830 additions and 1831 deletions

View File

@@ -14,11 +14,15 @@ jobs:
if: always() && github.repository_owner == 'naturalcrit'
runs-on: ubuntu-latest
steps:
- uses: ./.github/actions/limit-pull-requests
- name: Checkout
uses: actions/checkout@v2
- name : Run limit-pull-requests action
uses: ./.github/actions/limit-pull-requests
with:
except-users: |
dependabot
comment-limit: 1
comment-limit: 3
comment: |
Hi, thanks for your contribution to the Homebrewery! You already have >=3 open pull requests. Consider completing some of your existing PRs before opening new ones. Thanks!
close-limit: 5

View File

@@ -84,6 +84,55 @@ pre {
## changelog
For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery).
### Saturday 6/7/2024 - v3.13.1
{{taskList
##### calculuschild, G-Ambatte
* [x] Hotfixes for issues with v3.13.0
Fixes issues [#3559](https://github.com/naturalcrit/homebrewery/issues/3559), [#3552](https://github.com/naturalcrit/homebrewery/issues/3552), [#3554](https://github.com/naturalcrit/homebrewery/issues/3554)
}}
### Friday 28/6/2024 - v3.13.0
{{taskList
##### calculuschild
* [x] Add `:emoji:` Markdown syntax, with autosuggest; start typing after the first `:` for matching emojis from
:fab_font_awesome: FontAwesome, :df_d20: DiceFont, :ei_action: ElderberryInn, and a subset of :gi_broadsword: GameIcons
* [x] Fix `{curly injection}` to append to, rather than erase and replace target CSS
* [x] {{openSans **GET PDF**}} {{fa,fa-file-pdf}} now opens the print dialog directly, rather than redirecting to a separate page
##### Gazook
* [x] Several small style tweaks to the UI
* [x] Cleaning and refactoring several large pieces of code
##### 5e-Cleric
* [x] For error pages, add links to user account and `/share` page if available
Fixes issue [#3298](https://github.com/naturalcrit/homebrewery/issues/3298)
* [x] Change FrontCover title to use stroke outline instead of faking it with dozens of shadows
* [x] Cleaning and refactoring several large pieces of CSS
##### abquintic
* [x] Added additional {{openSans **TABLE OF CONTENTS**}} snippet options. Explicitly include or exclude items from the ToC generation via CSS properties
`--TOC:exclude` or `--TOC:include`, or change the included header depth from 3 to 6 (default 3) with `tocDepthH6`
##### MurdoMaclachlan *(new contributor!)*
* [x] Added "proficiency bonus" to Monster Stat Block snippet.
Fixes issue [#3397](https://github.com/naturalcrit/homebrewery/issues/3397)
}}
\column
### Monday 18/3/2024 - v3.12.0
{{taskList

View File

@@ -1,7 +1,6 @@
require('./brewCleanup.less');
const React = require('react');
const createClass = require('create-react-class');
const cx = require('classnames');
const request = require('superagent');

View File

@@ -1,7 +1,6 @@
require('./brewCompress.less');
const React = require('react');
const createClass = require('create-react-class');
const cx = require('classnames');
const request = require('superagent');

View File

@@ -1,7 +1,6 @@
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
require('./combobox.less');
const Combobox = createClass({

View File

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

View File

@@ -13,6 +13,10 @@ const RenderWarnings = require('homebrewery/renderWarnings/renderWarnings.jsx');
const NotificationPopup = require('./notificationPopup/notificationPopup.jsx');
const Frame = require('react-frame-component').default;
const dedent = require('dedent-tabs').default;
const { printCurrentBrew } = require('../../../shared/helpers.js');
const DOMPurify = require('dompurify');
const purifyConfig = { FORCE_BODY: true, SANITIZE_DOM: false };
const Themes = require('themes/themes.json');
@@ -33,8 +37,9 @@ const BrewPage = (props)=>{
index : 0,
...props
};
const cleanText = props.contents; //DOMPurify.sanitize(props.contents, purifyConfig);
return <div className={props.className} id={`p${props.index + 1}`} >
<div className='columnWrapper' dangerouslySetInnerHTML={{ __html: props.contents }} />
<div className='columnWrapper' dangerouslySetInnerHTML={{ __html: cleanText }} />
</div>;
};
@@ -102,13 +107,6 @@ const BrewRenderer = (props)=>{
return false;
};
const sanitizeScriptTags = (content)=>{
return content
?.replace(/<script/ig, '&lt;script')
.replace(/<\/script>/ig, '&lt;/script&gt;')
|| '';
};
const renderPageInfo = ()=>{
return <div className='pageInfo' ref={mainRef}>
<div>
@@ -128,19 +126,18 @@ const BrewRenderer = (props)=>{
const renderStyle = ()=>{
if(!props.style) return;
const cleanStyle = sanitizeScriptTags(props.style);
const cleanStyle = props.style; //DOMPurify.sanitize(props.style, purifyConfig);
//return <div style={{ display: 'none' }} dangerouslySetInnerHTML={{ __html: `<style>@layer styleTab {\n${sanitizeScriptTags(props.style)}\n} </style>` }} />;
return <div style={{ display: 'none' }} dangerouslySetInnerHTML={{ __html: `<style> ${cleanStyle} </style>` }} />;
};
const renderPage = (pageText, index)=>{
let cleanPageText = sanitizeScriptTags(pageText);
if(props.renderer == 'legacy') {
const html = MarkdownLegacy.render(cleanPageText);
const html = MarkdownLegacy.render(pageText);
return <BrewPage className='page phb' index={index} key={index} contents={html} />;
} else {
cleanPageText += `\n\n&nbsp;\n\\column\n&nbsp;`; //Artificial column break at page end to emulate column-fill:auto (until `wide` is used, when column-fill:balance will reappear)
const html = Markdown.render(cleanPageText, index);
pageText += `\n\n&nbsp;\n\\column\n&nbsp;`; //Artificial column break at page end to emulate column-fill:auto (until `wide` is used, when column-fill:balance will reappear)
const html = Markdown.render(pageText, index);
return <BrewPage className='page' index={index} key={index} contents={html} />;
}
};
@@ -163,6 +160,16 @@ const BrewRenderer = (props)=>{
return renderedPages;
};
const handleControlKeys = (e)=>{
if(!(e.ctrlKey || e.metaKey)) return;
const P_KEY = 80;
if(e.keyCode == P_KEY && props.allowPrint) printCurrentBrew();
if(e.keyCode == P_KEY) {
e.stopPropagation();
e.preventDefault();
}
};
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();
@@ -196,6 +203,12 @@ const BrewRenderer = (props)=>{
</div>
: null}
<ErrorBar errors={props.errors} />
<div className='popups'>
<RenderWarnings />
<NotificationPopup />
</div>
{/*render in iFrame so broken code doesn't crash the site.*/}
<Frame id='BrewRenderer' initialContent={INITIAL_CONTENT}
style={{ width: '100%', height: '100%', visibility: state.visibility }}
@@ -204,18 +217,15 @@ const BrewRenderer = (props)=>{
>
<div className={'brewRenderer'}
onScroll={handleScroll}
onKeyDown={handleControlKeys}
tabIndex={-1}
style={{ height: state.height }}>
<ErrorBar errors={props.errors} />
<div className='popups'>
<RenderWarnings />
<NotificationPopup />
</div>
<link href={`/themes/${rendererPath}/Blank/style.css`} type="text/css" rel='stylesheet'/>
<link href={`/themes/${rendererPath}/Blank/style.css`} type='text/css' rel='stylesheet'/>
{baseThemePath &&
<link href={`/themes/${rendererPath}/${baseThemePath}/style.css`} type="text/css" rel='stylesheet'/>
<link href={`/themes/${rendererPath}/${baseThemePath}/style.css`} type='text/css' rel='stylesheet'/>
}
<link href={`/themes/${rendererPath}/${themePath}/style.css`} type="text/css" rel='stylesheet'/>
<link href={`/themes/${rendererPath}/${themePath}/style.css`} type='text/css' rel='stylesheet'/>
{/* Apply CSS from Style tab and render pages from Markdown tab */}
{state.isMounted

View File

@@ -64,3 +64,16 @@
color : white;
background-color : #333333;
}
@media print {
.brewRenderer {
height: 100%;
overflow-y: unset;
.pages {
margin: 0px;
&>.page {
box-shadow: unset;
}
}
}
}

View File

@@ -2,7 +2,6 @@ require('./errorBar.less');
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
const ErrorBar = createClass({
displayName : 'ErrorBar',

View File

@@ -1,81 +1,45 @@
require('./notificationPopup.less');
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames'); //Unused variable
import Dialog from '../../../components/dialog.jsx';
const DISMISS_KEY = 'dismiss_notification12-04-23';
const DISMISS_BUTTON = <i className='fas fa-times dismiss' />;
const NotificationPopup = createClass({
displayName : 'NotificationPopup',
getInitialState : function() {
return {
notifications : {}
};
},
componentDidMount : function() {
this.checkNotifications();
window.addEventListener('resize', this.checkNotifications);
},
componentWillUnmount : function() {
window.removeEventListener('resize', this.checkNotifications);
},
notifications : {
psa : function(){
return (
<>
<li key='psa'>
<em>Don't store IMAGES in Google Drive</em><br />
Google Drive is not an image service, and will block images from being used
in brews if they get more views than expected. Google has confirmed they won't fix
this, so we recommend you look for another image hosting service such as imgur, ImgBB or Google Photos.
</li>
const NotificationPopup = ()=>{
return <Dialog className='notificationPopup' dismissKey={DISMISS_KEY} closeText={DISMISS_BUTTON} >
<div className='header'>
<i className='fas fa-info-circle info'></i>
<h3>Notice</h3>
<small>This website is always improving and we are still adding new features and squashing bugs. Keep the following in mind:</small>
</div>
<ul>
<li key='psa'>
<em>Don't store IMAGES in Google Drive</em><br />
Google Drive is not an image service, and will block images from being used
in brews if they get more views than expected. Google has confirmed they won't fix
this, so we recommend you look for another image hosting service such as imgur, ImgBB or Google Photos.
</li>
<li key='googleDriveFolder'>
<em>Don't delete your Homebrewery folder on Google Drive!</em> <br />
We have had several reports of users losing their brews, not realizing
that they had deleted the files on their Google Drive. If you have a Homebrewery folder
on your Google Drive with *.txt files inside, <em>do not delete it</em>!
We cannot help you recover files that you have deleted from your own
Google Drive.
</li>
<li key='googleDriveFolder'>
<em>Don't delete your Homebrewery folder on Google Drive!</em> <br />
We have had several reports of users losing their brews, not realizing
that they had deleted the files on their Google Drive. If you have a Homebrewery folder
on your Google Drive with *.txt files inside, <em>do not delete it</em>!
We cannot help you recover files that you have deleted from your own
Google Drive.
</li>
<li key='faq'>
<em>Protect your work! </em> <br />
If you opt not to use your Google Drive, keep in mind that we do not save a history of your projects. Please make frequent backups of your brews!&nbsp;
<a target='_blank' href='https://www.reddit.com/r/homebrewery/comments/adh6lh/faqs_psas_announcements/'>
See the FAQ
</a> to learn how to avoid losing your work!
</li>
</>
);
}
},
checkNotifications : function(){
const hideDismiss = localStorage.getItem(DISMISS_KEY);
if(hideDismiss) return this.setState({ notifications: {} });
this.setState({
notifications : _.mapValues(this.notifications, (fn)=>{ return fn(); }) //Convert notification functions into their return text value
});
},
dismiss : function(){
localStorage.setItem(DISMISS_KEY, true);
this.checkNotifications();
},
render : function(){
if(_.isEmpty(this.state.notifications)) return null;
return <div className='notificationPopup'>
<i className='fas fa-times dismiss' onClick={this.dismiss}/>
<i className='fas fa-info-circle info' />
<div className='header'>
<h3>Notice</h3>
<small>This website is always improving and we are still adding new features and squashing bugs. Keep the following in mind:</small>
</div>
<ul>{_.values(this.state.notifications)}</ul>
</div>;
}
});
<li key='faq'>
<em>Protect your work! </em> <br />
If you opt not to use your Google Drive, keep in mind that we do not save a history of your projects. Please make frequent backups of your brews!&nbsp;
<a target='_blank' href='https://www.reddit.com/r/homebrewery/comments/adh6lh/faqs_psas_announcements/'>
See the FAQ
</a> to learn how to avoid losing your work!
</li>
</ul>
</Dialog>;
};
module.exports = NotificationPopup;

View File

@@ -1,64 +1,60 @@
.popups{
.popups {
position : fixed;
top : @navbarHeight;
right : 15px;
right : 24px;
z-index : 10001;
width : 450px;
}
.notificationPopup{
.notificationPopup {
position : relative;
display : inline-block;
width : 100%;
padding : 15px;
padding-bottom : 10px;
padding-left : 25px;
background-color : @blue;
color : white;
a{
color : #e0e5c1;
background-color : @blue;
border : none;
&[open] { display : inline-block; }
a {
font-weight : 800;
color : #E0E5C1;
}
i.info{
i.info {
position : absolute;
top : 12px;
left : 12px;
opacity : 0.8;
font-size : 2.5em;
opacity : 0.8;
}
i.dismiss{
position : absolute;
top : 10px;
right : 10px;
cursor : pointer;
opacity : 0.6;
&:hover{
opacity : 1;
}
button.dismiss {
position : absolute;
top : 10px;
right : 10px;
cursor : pointer;
background-color : transparent;
opacity : 0.6;
&:hover { opacity : 1; }
}
.header {
padding-left : 50px;
}
small{
opacity : 0.7;
.header { padding-left : 50px; }
small {
font-size : 0.6em;
opacity : 0.7;
}
h3{
h3 {
font-size : 1.1em;
font-weight : 800;
}
ul{
ul {
margin-top : 15px;
font-size : 0.8em;
list-style-position : outside;
list-style-type : disc;
li{
li {
margin-top : 1.4em;
font-size : 0.8em;
line-height : 1.4em;
margin-top : 1.4em;
em{
font-weight : 800;
}
em { font-weight : 800; }
}
}
}

View File

@@ -5,6 +5,7 @@ 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');
const CodeEditor = require('naturalcrit/codeEditor/codeEditor.jsx');
const SnippetBar = require('./snippetbar/snippetbar.jsx');
@@ -47,6 +48,9 @@ const Editor = createClass({
};
},
editor : React.createRef(null),
codeEditor : React.createRef(null),
isText : function() {return this.state.view == 'text';},
isStyle : function() {return this.state.view == 'style';},
isMeta : function() {return this.state.view == 'meta';},
@@ -79,15 +83,15 @@ const Editor = createClass({
},
updateEditorSize : function() {
if(this.refs.codeEditor) {
let paneHeight = this.refs.main.parentNode.clientHeight;
if(this.codeEditor.current) {
let paneHeight = this.editor.current.parentNode.clientHeight;
paneHeight -= SNIPPETBAR_HEIGHT;
this.refs.codeEditor.codeMirror.setSize(null, paneHeight);
this.codeEditor.current.codeMirror.setSize(null, paneHeight);
}
},
handleInject : function(injectText){
this.refs.codeEditor?.injectText(injectText, false);
this.codeEditor.current?.injectText(injectText, false);
},
handleViewChange : function(newView){
@@ -98,7 +102,7 @@ const Editor = createClass({
},
getCurrentPage : function(){
const lines = this.props.brew.text.split('\n').slice(0, this.refs.codeEditor.getCursorPosition().line + 1);
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)
@@ -110,9 +114,9 @@ const Editor = createClass({
},
highlightCustomMarkdown : function(){
if(!this.refs.codeEditor) return;
if(!this.codeEditor.current) return;
if(this.state.view === 'text') {
const codeMirror = this.refs.codeEditor.codeMirror;
const codeMirror = this.codeEditor.current.codeMirror;
codeMirror.operation(()=>{ // Batch CodeMirror styling
//reset custom text styles
@@ -219,6 +223,34 @@ const Editor = createClass({
endCh = match.index+match[0].length;
codeMirror.markText({ line: lineNumber, ch: 0 }, { line: lineNumber, ch: endCh }, { className: 'block' });
}
// Emojis
if(line.match(/:[^\s:]+:/g)) {
let startIndex = line.indexOf(':');
const emojiRegex = /:[^\s:]+:/gy;
while (startIndex >= 0) {
emojiRegex.lastIndex = startIndex;
let 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)
return;
let startPos = { line: lineNumber, ch: match.index };
let endPos = { line: lineNumber, ch: match.index + match[0].length };
// Iterate over conflicting marks and clear them
var marks = codeMirror.findMarks(startPos, endPos);
marks.forEach(function(marker) {
marker.clear();
});
codeMirror.markText(startPos, endPos, { className: 'emoji' });
}
startIndex = line.indexOf(':', Math.max(startIndex + 1, emojiRegex.lastIndex));
}
}
}
});
});
@@ -273,23 +305,23 @@ const Editor = createClass({
targetLine = lineCount - 1; //Scroll to `\page`, which is one line back.
let currentY = this.refs.codeEditor.codeMirror.getScrollInfo().top;
let targetY = this.refs.codeEditor.codeMirror.heightAtLine(targetLine, 'local', true);
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.refs.codeEditor.codeMirror.scrollTo(null, currentY);
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.refs.codeEditor.codeMirror.heightAtLine(targetLine, 'local', true);
targetY = this.codeEditor.current.codeMirror.heightAtLine(targetLine, 'local', true);
// End when close enough
if(Math.abs(targetY - currentY) < 1) {
this.refs.codeEditor.codeMirror.scrollTo(null, targetY); // Scroll any remaining difference
this.refs.codeEditor.setCursorPosition({ line: targetLine + 1, ch: 0 });
this.refs.codeEditor.codeMirror.addLineClass(targetLine + 1, 'wrap', 'sourceMoveFlash');
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);
@@ -299,7 +331,7 @@ const Editor = createClass({
//Called when there are changes to the editor's dimensions
update : function(){
this.refs.codeEditor?.updateSize();
this.codeEditor.current?.updateSize();
},
updateEditorTheme : function(newTheme){
@@ -318,7 +350,7 @@ const Editor = createClass({
if(this.isText()){
return <>
<CodeEditor key='codeEditor'
ref='codeEditor'
ref={this.codeEditor}
language='gfm'
view={this.state.view}
value={this.props.brew.text}
@@ -330,12 +362,12 @@ const Editor = createClass({
if(this.isStyle()){
return <>
<CodeEditor key='codeEditor'
ref='codeEditor'
ref={this.codeEditor}
language='css'
view={this.state.view}
value={this.props.brew.style ?? DEFAULT_STYLE_TEXT}
onChange={this.props.onStyleChange}
enableFolding={false}
enableFolding={true}
editorTheme={this.state.editorTheme}
rerenderParent={this.rerenderParent} />
</>;
@@ -355,28 +387,28 @@ const Editor = createClass({
},
redo : function(){
return this.refs.codeEditor?.redo();
return this.codeEditor.current?.redo();
},
historySize : function(){
return this.refs.codeEditor?.historySize();
return this.codeEditor.current?.historySize();
},
undo : function(){
return this.refs.codeEditor?.undo();
return this.codeEditor.current?.undo();
},
foldCode : function(){
return this.refs.codeEditor?.foldAllCode();
return this.codeEditor.current?.foldAllCode();
},
unfoldCode : function(){
return this.refs.codeEditor?.unfoldAllCode();
return this.codeEditor.current?.unfoldAllCode();
},
render : function(){
return (
<div className='editor' ref='main'>
<div className='editor' ref={this.editor}>
<SnippetBar
brew={this.props.brew}
view={this.state.view}
@@ -392,7 +424,7 @@ const Editor = createClass({
historySize={this.historySize()}
currentEditorTheme={this.state.editorTheme}
updateEditorTheme={this.updateEditorTheme}
cursorPos={this.refs.codeEditor?.getCursorPosition() || {}} />
cursorPos={this.codeEditor.current?.getCursorPosition() || {}} />
{this.renderEditor()}
</div>

View File

@@ -43,6 +43,16 @@
font-weight : bold;
color : green;
}
.emoji:not(.cm-comment) {
margin-left : 2px;
color : #360034;
background : #ffc8ff;
border-radius : 6px;
font-weight : bold;
padding-bottom : 1px;
outline-offset : -2px;
outline : solid 2px #ff96fc;
}
.superscript:not(.cm-comment) {
font-weight : bold;
color : goldenrod;

View File

@@ -3,7 +3,6 @@ require('./metadataEditor.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 Nav = require('naturalcrit/nav/nav.jsx');
const Combobox = require('client/components/combobox.jsx');

View File

@@ -161,7 +161,7 @@ const Snippetbar = createClass({
onClick={this.props.unfoldCode} >
<i className='fas fa-expand-alt' />
</div>
</>
</>;
}
@@ -181,7 +181,7 @@ const Snippetbar = createClass({
<i className='fas fa-palette' />
{this.state.themeSelector && this.renderThemeSelector()}
</div>
<div className='divider'></div>
<div className={cx('text', { selected: this.props.view === 'text' })}
onClick={()=>this.props.onViewChange('text')}>

View File

@@ -10,7 +10,6 @@ const UserPage = require('./pages/userPage/userPage.jsx');
const SharePage = require('./pages/sharePage/sharePage.jsx');
const NewPage = require('./pages/newPage/newPage.jsx');
const ErrorPage = require('./pages/errorPage/errorPage.jsx');
const PrintPage = require('./pages/printPage/printPage.jsx');
const AccountPage = require('./pages/accountPage/accountPage.jsx');
const WithRoute = (props)=>{
@@ -72,15 +71,13 @@ const Homebrew = createClass({
<Route path='/new/:id' element={<WithRoute el={NewPage} brew={this.props.brew} />} />
<Route path='/new' element={<WithRoute el={NewPage}/>} />
<Route path='/user/:username' element={<WithRoute el={UserPage} brews={this.props.brews} />} />
<Route path='/print/:id' element={<WithRoute el={PrintPage} brew={this.props.brew} />} />
<Route path='/print' element={<WithRoute el={PrintPage} />} />
<Route path='/changelog' element={<WithRoute el={SharePage} brew={this.props.brew} />} />
<Route path='/faq' element={<WithRoute el={SharePage} brew={this.props.brew} />} />
<Route path='/account' element={<WithRoute el={AccountPage} brew={this.props.brew} accountDetails={this.props.brew.accountDetails} />} />
<Route path='/legacy' element={<WithRoute el={HomePage} brew={this.props.brew} />} />
<Route path='/error' element={<WithRoute el={ErrorPage} brew={this.props.brew} />} />
<Route path='/' element={<WithRoute el={HomePage} brew={this.props.brew} />} />
<Route path='/*' element={<WithRoute el={HomePage} brew={this.props.brew} />} />
<Route path='/' element={<WithRoute el={HomePage} brew={this.props.brew} />} />
<Route path='/*' element={<WithRoute el={HomePage} brew={this.props.brew} />} />
</Routes>
</div>
</Router>
@@ -88,15 +85,4 @@ const Homebrew = createClass({
}
});
module.exports = Homebrew;
//TODO: Nicer Error page instead of just "cant get that"
// '/share/:id' : (args)=>{
// if(!this.props.brew.shareId){
// return <ErrorPage errorId={args.id}/>;
// }
//
// return <SharePage
// id={args.id}
// brew={this.props.brew} />;
// },
module.exports = Homebrew;

View File

@@ -42,7 +42,7 @@ const ErrorNavItem = createClass({
</div>
</Nav.item>;
}
if(status === 412) {
return <Nav.item className='save error' icon='fas fa-exclamation-triangle'>
Oops!
@@ -51,7 +51,7 @@ const ErrorNavItem = createClass({
</div>
</Nav.item>;
}
if(HBErrorCode === '04') {
return <Nav.item className='save error' icon='fas fa-exclamation-triangle'>
Oops!
@@ -76,10 +76,10 @@ const ErrorNavItem = createClass({
if(response.body?.errors?.[0].reason == 'storageQuotaExceeded') {
return <Nav.item className='save error' icon='fas fa-exclamation-triangle'>
Oops!
<div className='errorContainer' onClick={clearError}>
<div className='errorContainer' onClick={clearError}>
Can't save because your Google Drive seems to be full!
</div>
</Nav.item>;
</div>
</Nav.item>;
}
if(response.req.url.match(/^\/api.*Google.*$/m)){

View File

@@ -1,6 +1,4 @@
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const dedent = require('dedent-tabs').default;
const Nav = require('naturalcrit/nav/nav.jsx');

View File

@@ -1,6 +1,5 @@
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const Moment = require('moment');
const Nav = require('naturalcrit/nav/nav.jsx');

View File

@@ -7,58 +7,58 @@ const BREWKEY = 'homebrewery-new';
const STYLEKEY = 'homebrewery-new-style';
const METAKEY = 'homebrewery-new-meta';
const NewBrew = () => {
const handleFileChange = (e) => {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
const fileContent = e.target.result;
const newBrew = {
text: fileContent,
style: ''
};
if(fileContent.startsWith('```metadata')) {
splitTextStyleAndMetadata(newBrew); // Modify newBrew directly
localStorage.setItem(BREWKEY, newBrew.text);
localStorage.setItem(STYLEKEY, newBrew.style);
localStorage.setItem(METAKEY, JSON.stringify(_.pick(newBrew, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang'])));
window.location.href = '/new';
} else {
alert('This file is invalid, please, enter a valid file');
}
};
reader.readAsText(file);
}
};
const NewBrew = ()=>{
const handleFileChange = (e)=>{
const file = e.target.files[0];
if(file) {
const reader = new FileReader();
reader.onload = (e)=>{
const fileContent = e.target.result;
const newBrew = {
text : fileContent,
style : ''
};
if(fileContent.startsWith('```metadata')) {
splitTextStyleAndMetadata(newBrew); // Modify newBrew directly
localStorage.setItem(BREWKEY, newBrew.text);
localStorage.setItem(STYLEKEY, newBrew.style);
localStorage.setItem(METAKEY, JSON.stringify(_.pick(newBrew, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang'])));
window.location.href = '/new';
} else {
alert('This file is invalid, please, enter a valid file');
}
};
reader.readAsText(file);
}
};
return (
<Nav.dropdown>
<Nav.item
className='new'
color='purple'
icon='fa-solid fa-plus-square'>
return (
<Nav.dropdown>
<Nav.item
className='new'
color='purple'
icon='fa-solid fa-plus-square'>
new
</Nav.item>
<Nav.item
className='fromBlank'
href='/new'
newTab={true}
color='purple'
icon='fa-solid fa-file'>
</Nav.item>
<Nav.item
className='fromBlank'
href='/new'
newTab={true}
color='purple'
icon='fa-solid fa-file'>
from blank
</Nav.item>
</Nav.item>
<Nav.item
className='fromFile'
color='purple'
icon='fa-solid fa-upload'
onClick={() => { document.getElementById('uploadTxt').click(); }}>
<input id="uploadTxt" className='newFromLocal' type="file" onChange={handleFileChange} style={{ display: 'none' }} />
<Nav.item
className='fromFile'
color='purple'
icon='fa-solid fa-upload'
onClick={()=>{ document.getElementById('uploadTxt').click(); }}>
<input id='uploadTxt' className='newFromLocal' type='file' onChange={handleFileChange} style={{ display: 'none' }} />
from file
</Nav.item>
</Nav.dropdown>
);
</Nav.item>
</Nav.dropdown>
);
};
module.exports = NewBrew;

View File

@@ -1,9 +1,9 @@
const React = require('react');
const createClass = require('create-react-class');
const Nav = require('naturalcrit/nav/nav.jsx');
const { printCurrentBrew } = require('../../../shared/helpers.js');
module.exports = function(props){
return <Nav.item newTab={true} href={`/print/${props.shareId}?dialog=true`} color='purple' icon='far fa-file-pdf'>
module.exports = function(){
return <Nav.item onClick={printCurrentBrew} color='purple' icon='far fa-file-pdf'>
get PDF
</Nav.item>;
};

View File

@@ -1,9 +1,7 @@
const React = require('react');
const createClass = require('create-react-class');
const cx = require('classnames');
const Nav = require('naturalcrit/nav/nav.jsx');
const MAX_URL_SIZE = 2083;
const MAIN_URL = 'https://www.reddit.com/r/UnearthedArcana/submit?selftext=true';

View File

@@ -1,8 +1,6 @@
require('./brewItem.less');
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
const moment = require('moment');
const request = require('../../../../utils/request-middleware.js');

View File

@@ -119,11 +119,12 @@
text-align : center;
a{
.animate(opacity);
display : block;
margin : 8px 0px;
opacity : 0.6;
font-size : 1.3em;
color : white;
display : block;
margin : 8px 0px;
opacity : 0.6;
font-size : 1.3em;
color : white;
text-decoration : unset;
&:hover{
opacity : 1;
}

View File

@@ -262,8 +262,8 @@ const ListPage = createClass({
render : function(){
return <div className='listPage sitePage'>
{/*<style>@layer V3_5ePHB, bundle;</style>*/}
<link href='/themes/V3/Blank/style.css' type="text/css" rel='stylesheet'/>
<link href='/themes/V3/5ePHB/style.css' type="text/css" rel='stylesheet'/>
<link href='/themes/V3/Blank/style.css' type='text/css' rel='stylesheet'/>
<link href='/themes/V3/5ePHB/style.css' type='text/css' rel='stylesheet'/>
{this.props.navItems}
{this.renderSortOptions()}
{this.renderTagsOptions()}

View File

@@ -11,7 +11,7 @@ const Navbar = require('../../navbar/navbar.jsx');
const NewBrew = require('../../navbar/newbrew.navitem.jsx');
const HelpNavItem = require('../../navbar/help.navitem.jsx');
const PrintLink = require('../../navbar/print.navitem.jsx');
const PrintNavItem = require('../../navbar/print.navitem.jsx');
const ErrorNavItem = require('../../navbar/error-navitem.jsx');
const Account = require('../../navbar/account.navitem.jsx');
const RecentNavItem = require('../../navbar/recent.navitem.jsx').both;
@@ -20,9 +20,12 @@ const SplitPane = require('naturalcrit/splitPane/splitPane.jsx');
const Editor = require('../../editor/editor.jsx');
const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
const LockNotification = require('./lockNotification/lockNotification.jsx');
const Markdown = require('naturalcrit/markdown.js');
const { DEFAULT_BREW_LOAD } = require('../../../../server/brewDefaults.js');
const { printCurrentBrew } = require('../../../../shared/helpers.js');
const googleDriveIcon = require('../../googleDrive.svg');
@@ -51,9 +54,12 @@ const EditPage = createClass({
autoSave : true,
autoSaveWarning : false,
unsavedTime : new Date(),
currentEditorPage : 0
currentEditorPage : 0,
displayLockMessage : this.props.brew.lock || false
};
},
editor : React.createRef(null),
savedBrew : null,
componentDidMount : function(){
@@ -93,7 +99,7 @@ const EditPage = createClass({
const S_KEY = 83;
const P_KEY = 80;
if(e.keyCode == S_KEY) this.trySave(true);
if(e.keyCode == P_KEY) window.open(`/print/${this.processShareId()}?dialog=true`, '_blank').focus();
if(e.keyCode == P_KEY) printCurrentBrew();
if(e.keyCode == P_KEY || e.keyCode == S_KEY){
e.stopPropagation();
e.preventDefault();
@@ -101,7 +107,7 @@ const EditPage = createClass({
},
handleSplitMove : function(){
this.refs.editor.update();
this.editor.current.update();
},
handleTextChange : function(text){
@@ -113,7 +119,7 @@ const EditPage = createClass({
brew : { ...prevState.brew, text: text },
isPending : true,
htmlErrors : htmlErrors,
currentEditorPage : this.refs.editor.getCurrentPage() - 1 //Offset index since Marked starts pages at 0
currentEditorPage : this.editor.current.getCurrentPage() - 1 //Offset index since Marked starts pages at 0
}), ()=>{if(this.state.autoSave) this.trySave();});
},
@@ -376,7 +382,7 @@ const EditPage = createClass({
post to reddit
</Nav.item>
</Nav.dropdown>
<PrintLink shareId={this.processShareId()} />
<PrintNavItem />
<RecentNavItem brew={this.state.brew} storageKey='edit' />
<Account />
</Nav.section>
@@ -390,9 +396,10 @@ const EditPage = createClass({
{this.renderNavbar()}
<div className='content'>
<SplitPane onDragFinish={this.handleSplitMove} ref='pane'>
{this.props.brew.lock && <LockNotification shareId={this.props.brew.shareId} message={this.props.brew.lock.editMessage} />}
<SplitPane onDragFinish={this.handleSplitMove}>
<Editor
ref='editor'
ref={this.editor}
brew={this.state.brew}
onTextChange={this.handleTextChange}
onStyleChange={this.handleStyleChange}
@@ -408,6 +415,7 @@ const EditPage = createClass({
errors={this.state.htmlErrors}
lang={this.state.brew.lang}
currentEditorPage={this.state.currentEditorPage}
allowPrint={true}
/>
</SplitPane>
</div>

View File

@@ -0,0 +1,30 @@
require('./lockNotification.less');
const React = require('react');
import Dialog from '../../../../components/dialog.jsx';
function LockNotification(props) {
props = {
shareId : 0,
disableLock : ()=>{},
message : '',
...props
};
const removeLock = ()=>{
alert(`Not yet implemented - ID ${props.shareId}`);
};
return <Dialog className='lockNotification' blocking closeText='CONTINUE TO EDITOR' >
<h1>BREW LOCKED</h1>
<p>This brew been locked by the Administrators. It will not be accessible by any method other than the Editor until the lock is removed.</p>
<hr />
<h3>LOCK REASON</h3>
<p>{props.message || 'Unable to retrieve Lock Message'}</p>
<hr />
<p>Once you have resolved this issue, click REQUEST LOCK REMOVAL to notify the Administrators for review.</p>
<p>Click CONTINUE TO EDITOR to temporarily hide this notification; it will reappear the next time the page is reloaded.</p>
<button onClick={removeLock}>REQUEST LOCK REMOVAL</button>
</Dialog>;
};
module.exports = LockNotification;

View File

@@ -0,0 +1,27 @@
.lockNotification {
z-index : 1;
width : 80%;
padding : 10px;
margin : 5% 10%;
line-height : 1.5em;
color : black;
text-align : center;
background-color : #CCCCCC;
&::backdrop { background-color : #000000AA; }
button {
margin : 10px;
color : white;
background-color : #333333;
&:hover { background-color : #777777; }
}
h1, h3 {
font-family : 'Open Sans', sans-serif;
font-weight : 800;
}
h1 { font-size : 24px; }
h3 { font-size : 18px; }
}

View File

@@ -1,41 +1,25 @@
require('./errorPage.less');
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
const UIPage = require('../basePages/uiPage/uiPage.jsx');
const Markdown = require('../../../../shared/naturalcrit/markdown.js');
const React = require('react');
const UIPage = require('../basePages/uiPage/uiPage.jsx');
const Markdown = require('../../../../shared/naturalcrit/markdown.js');
const ErrorIndex = require('./errors/errorIndex.js');
const ErrorPage = createClass({
displayName : 'ErrorPage',
const ErrorPage = ({ brew })=>{
// Retrieving the error text based on the brew's error code from ErrorIndex
const errorText = ErrorIndex({ brew })[brew.HBErrorCode.toString()] || '';
getDefaultProps : function() {
return {
ver : '0.0.0',
errorId : '',
text : '# Oops \n We could not find a brew with that id. **Sorry!**',
error : {}
};
},
render : function(){
const errorText = ErrorIndex(this.props)[this.props.brew.HBErrorCode.toString()] || '';
return <UIPage brew={{ title: 'Crit Fail!' }}>
return (
<UIPage brew={{ title: 'Crit Fail!' }}>
<div className='dataGroup'>
<div className='errorTitle'>
<h1>{`Error ${this.props.brew.status || '000'}`}</h1>
<h4>{this.props.brew.text || 'No error text'}</h4>
<h1>{`Error ${brew?.status || '000'}`}</h1>
<h4>{brew?.text || 'No error text'}</h4>
</div>
<hr />
<div dangerouslySetInnerHTML={{ __html: Markdown.render(errorText) }} />
</div>
</UIPage>;
}
});
</UIPage>
);
};
module.exports = ErrorPage;

View File

@@ -95,7 +95,7 @@ const errorIndex = (props)=>{
**Current Authors:** ${props.brew.authors?.map((author)=>{return `[${author}](/user/${author})`;}).join(', ') || 'Unable to list authors'}
[Click here to be redirected to the brew's share page.](/share/${props.brew.shareId})`,
// Brew load error
'05' : dedent`
@@ -140,7 +140,7 @@ const errorIndex = (props)=>{
'100' : dedent`
## This brew has been locked.
Please contact the Administrators to unlock this document.
Only an author may request that this lock is removed.
:

View File

@@ -1,12 +0,0 @@
//TODO: Depricate
module.exports = function(shareId){
return function(event){
event = event || window.event;
if((event.ctrlKey || event.metaKey) && event.keyCode == 80){
const win = window.open(`/homebrew/print/${shareId}?dialog=true`, '_blank');
win.focus();
event.preventDefault();
}
};
};

View File

@@ -37,6 +37,9 @@ const HomePage = createClass({
currentEditorPage : 0
};
},
editor : React.createRef(null),
handleSave : function(){
request.post('/api')
.send(this.state.brew)
@@ -50,12 +53,12 @@ const HomePage = createClass({
});
},
handleSplitMove : function(){
this.refs.editor.update();
this.editor.current.update();
},
handleTextChange : function(text){
this.setState((prevState)=>({
brew : { ...prevState.brew, text: text },
currentEditorPage : this.refs.editor.getCurrentPage() - 1 //Offset index since Marked starts pages at 0
currentEditorPage : this.editor.current.getCurrentPage() - 1 //Offset index since Marked starts pages at 0
}));
},
renderNavbar : function(){
@@ -79,9 +82,9 @@ const HomePage = createClass({
{this.renderNavbar()}
<div className='content'>
<SplitPane onDragFinish={this.handleSplitMove} ref='pane'>
<SplitPane onDragFinish={this.handleSplitMove}>
<Editor
ref='editor'
ref={this.editor}
brew={this.state.brew}
onTextChange={this.handleTextChange}
renderer={this.state.brew.renderer}

View File

@@ -2,12 +2,12 @@
require('./newPage.less');
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const request = require('../../utils/request-middleware.js');
const Markdown = require('naturalcrit/markdown.js');
const Nav = require('naturalcrit/nav/nav.jsx');
const PrintNavItem = require('../../navbar/print.navitem.jsx');
const Navbar = require('../../navbar/navbar.jsx');
const AccountNavItem = require('../../navbar/account.navitem.jsx');
const ErrorNavItem = require('../../navbar/error-navitem.jsx');
@@ -19,6 +19,7 @@ const Editor = require('../../editor/editor.jsx');
const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
const { DEFAULT_BREW } = require('../../../../server/brewDefaults.js');
const { printCurrentBrew } = require('../../../../shared/helpers.js');
const BREWKEY = 'homebrewery-new';
const STYLEKEY = 'homebrewery-new-style';
@@ -47,6 +48,8 @@ const NewPage = createClass({
};
},
editor : React.createRef(null),
componentDidMount : function() {
document.addEventListener('keydown', this.handleControlKeys);
@@ -88,7 +91,7 @@ const NewPage = createClass({
const S_KEY = 83;
const P_KEY = 80;
if(e.keyCode == S_KEY) this.save();
if(e.keyCode == P_KEY) this.print();
if(e.keyCode == P_KEY) printCurrentBrew();
if(e.keyCode == P_KEY || e.keyCode == S_KEY){
e.stopPropagation();
e.preventDefault();
@@ -96,7 +99,7 @@ const NewPage = createClass({
},
handleSplitMove : function(){
this.refs.editor.update();
this.editor.current.update();
},
handleTextChange : function(text){
@@ -107,7 +110,7 @@ const NewPage = createClass({
this.setState((prevState)=>({
brew : { ...prevState.brew, text: text },
htmlErrors : htmlErrors,
currentEditorPage : this.refs.editor.getCurrentPage() - 1 //Offset index since Marked starts pages at 0
currentEditorPage : this.editor.current.getCurrentPage() - 1 //Offset index since Marked starts pages at 0
}));
localStorage.setItem(BREWKEY, text);
},
@@ -179,16 +182,6 @@ const NewPage = createClass({
}
},
print : function(){
window.open('/print?dialog=true&local=print', '_blank');
},
renderLocalPrintButton : function(){
return <Nav.item color='purple' icon='far fa-file-pdf' onClick={this.print}>
get PDF
</Nav.item>;
},
renderNavbar : function(){
return <Navbar>
@@ -201,7 +194,7 @@ const NewPage = createClass({
<ErrorNavItem error={this.state.error} parent={this}></ErrorNavItem> :
this.renderSaveButton()
}
{this.renderLocalPrintButton()}
<PrintNavItem />
<HelpNavItem />
<RecentNavItem />
<AccountNavItem />
@@ -213,9 +206,9 @@ const NewPage = createClass({
return <div className='newPage sitePage'>
{this.renderNavbar()}
<div className='content'>
<SplitPane onDragFinish={this.handleSplitMove} ref='pane'>
<SplitPane onDragFinish={this.handleSplitMove}>
<Editor
ref='editor'
ref={this.editor}
brew={this.state.brew}
onTextChange={this.handleTextChange}
onStyleChange={this.handleStyleChange}
@@ -230,6 +223,7 @@ const NewPage = createClass({
errors={this.state.htmlErrors}
lang={this.state.brew.lang}
currentEditorPage={this.state.currentEditorPage}
allowPrint={true}
/>
</SplitPane>
</div>

View File

@@ -1,113 +0,0 @@
require('./printPage.less');
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
const { Meta } = require('vitreum/headtags');
const MarkdownLegacy = require('naturalcrit/markdownLegacy.js');
const Markdown = require('naturalcrit/markdown.js');
const Themes = require('themes/themes.json');
const BREWKEY = 'homebrewery-new';
const STYLEKEY = 'homebrewery-new-style';
const METAKEY = 'homebrewery-new-meta';
const PrintPage = createClass({
displayName : 'PrintPage',
getDefaultProps : function() {
return {
query : {},
brew : {
text : '',
style : '',
renderer : 'legacy',
lang : ''
}
};
},
getInitialState : function() {
return {
brew : {
text : this.props.brew.text || '',
style : this.props.brew.style || undefined,
renderer : this.props.brew.renderer || 'legacy',
theme : this.props.brew.theme || '5ePHB',
lang : this.props.brew.lang || 'en'
}
};
},
componentDidMount : function() {
if(this.props.query.local == 'print'){
const brewStorage = localStorage.getItem(BREWKEY);
const styleStorage = localStorage.getItem(STYLEKEY);
const metaStorage = JSON.parse(localStorage.getItem(METAKEY));
this.setState((prevState, prevProps)=>{
return {
brew : {
text : brewStorage,
style : styleStorage,
renderer : metaStorage?.renderer || 'legacy',
theme : metaStorage?.theme || '5ePHB',
lang : metaStorage?.lang || 'en'
}
};
});
}
if(this.props.query.dialog) window.print();
},
renderStyle : function() {
if(!this.state.brew.style) return;
//return <div style={{ display: 'none' }} dangerouslySetInnerHTML={{ __html: `<style>@layer styleTab {\n${this.state.brew.style}\n} </style>` }} />;
return <div style={{ display: 'none' }} dangerouslySetInnerHTML={{ __html: `<style>\n${this.state.brew.style}\n</style>` }} />;
},
renderPages : function(){
if(this.state.brew.renderer == 'legacy') {
return _.map(this.state.brew.text.split('\\page'), (pageText, index)=>{
return <div
className='phb page'
id={`p${index + 1}`}
dangerouslySetInnerHTML={{ __html: MarkdownLegacy.render(pageText) }}
key={index} />;
});
} else {
return _.map(this.state.brew.text.split(/^\\page$/gm), (pageText, index)=>{
pageText += `\n\n&nbsp;\n\\column\n&nbsp;`; //Artificial column break at page end to emulate column-fill:auto (until `wide` is used, when column-fill:balance will reappear)
return (
<div className='page' id={`p${index + 1}`} key={index} >
<div className='columnWrapper' dangerouslySetInnerHTML={{ __html: Markdown.render(pageText) }} />
</div>
);
});
}
},
render : function(){
const rendererPath = this.state.brew.renderer == 'V3' ? 'V3' : 'Legacy';
const themePath = this.state.brew.theme ?? '5ePHB';
const baseThemePath = Themes[rendererPath][themePath].baseTheme;
return <div>
<Meta name='robots' content='noindex, nofollow' />
<link href={`/themes/${rendererPath}/Blank/style.css`} type="text/css" rel='stylesheet'/>
{baseThemePath &&
<link href={`/themes/${rendererPath}/${baseThemePath}/style.css`} type="text/css" rel='stylesheet'/>
}
<link href={`/themes/${rendererPath}/${themePath}/style.css`} type="text/css" rel='stylesheet'/>
{/* Apply CSS from Style tab */}
{this.renderStyle()}
<div className='pages' ref='pages' lang={this.state.brew.lang}>
{this.renderPages()}
</div>
</div>;
}
});
module.exports = PrintPage;

View File

@@ -1,3 +0,0 @@
.printPage{
}

View File

@@ -6,14 +6,13 @@ const { Meta } = require('vitreum/headtags');
const Nav = require('naturalcrit/nav/nav.jsx');
const Navbar = require('../../navbar/navbar.jsx');
const MetadataNav = require('../../navbar/metadata.navitem.jsx');
const PrintLink = require('../../navbar/print.navitem.jsx');
const PrintNavItem = require('../../navbar/print.navitem.jsx');
const RecentNavItem = require('../../navbar/recent.navitem.jsx').both;
const Account = require('../../navbar/account.navitem.jsx');
const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
const { DEFAULT_BREW_LOAD } = require('../../../../server/brewDefaults.js');
const { printCurrentBrew } = require('../../../../shared/helpers.js');
const SharePage = createClass({
displayName : 'SharePage',
@@ -35,7 +34,7 @@ const SharePage = createClass({
if(!(e.ctrlKey || e.metaKey)) return;
const P_KEY = 80;
if(e.keyCode == P_KEY){
window.open(`/print/${this.processShareId()}?dialog=true`, '_blank').focus();
if(e.keyCode == P_KEY) printCurrentBrew();
e.stopPropagation();
e.preventDefault();
}
@@ -47,6 +46,19 @@ const SharePage = createClass({
this.props.brew.shareId;
},
renderEditLink : function(){
if(!this.props.brew.editId) return;
let editLink = this.props.brew.editId;
if(this.props.brew.googleId && !this.props.brew.stubbed) {
editLink = this.props.brew.googleId + editLink;
}
return <Nav.item color='orange' icon='fas fa-pencil-alt' href={`/edit/${editLink}`}>
edit
</Nav.item>;
},
render : function(){
return <div className='sharePage sitePage'>
<Meta name='robots' content='noindex, nofollow' />
@@ -59,18 +71,19 @@ const SharePage = createClass({
<Nav.section>
{this.props.brew.shareId && <>
<PrintLink shareId={this.processShareId()} />
<PrintNavItem/>
<Nav.dropdown>
<Nav.item color='red' icon='fas fa-code'>
source
</Nav.item>
<Nav.item color='blue' href={`/source/${this.processShareId()}`}>
<Nav.item color='blue' icon='fas fa-eye' href={`/source/${this.processShareId()}`}>
view
</Nav.item>
<Nav.item color='blue' href={`/download/${this.processShareId()}`}>
{this.renderEditLink()}
<Nav.item color='blue' icon='fas fa-download' href={`/download/${this.processShareId()}`}>
download
</Nav.item>
<Nav.item color='blue' href={`/new/${this.processShareId()}`}>
<Nav.item color='blue' icon='fas fa-clone' href={`/new/${this.processShareId()}`}>
clone to new
</Nav.item>
</Nav.dropdown>
@@ -81,7 +94,13 @@ const SharePage = createClass({
</Navbar>
<div className='content'>
<BrewRenderer text={this.props.brew.text} style={this.props.brew.style} renderer={this.props.brew.renderer} theme={this.props.brew.theme} />
<BrewRenderer
text={this.props.brew.text}
style={this.props.brew.style}
renderer={this.props.brew.renderer}
theme={this.props.brew.theme}
allowPrint={true}
/>
</div>
</div>;
}

View File

@@ -1,7 +1,6 @@
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
const ListPage = require('../basePages/listPage/listPage.jsx');

1723
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"name": "homebrewery",
"description": "Create authentic looking D&D homebrews using only markdown",
"version": "3.12.0",
"version": "3.13.1",
"engines": {
"npm": "^10.2.x",
"node": "^20.8.x"
@@ -27,11 +27,12 @@
"test:dev": "jest --verbose --watch",
"test:basic": "jest tests/markdown/basic.test.js --verbose",
"test:variables": "jest tests/markdown/variables.test.js --verbose",
"test:mustache-syntax": "jest '.*(mustache-syntax).*' --verbose --noStackTrace",
"test:mustache-syntax:inline": "jest '.*(mustache-syntax).*' -t '^Inline:.*' --verbose --noStackTrace",
"test:mustache-syntax:block": "jest '.*(mustache-syntax).*' -t '^Block:.*' --verbose --noStackTrace",
"test:mustache-syntax:injection": "jest '.*(mustache-syntax).*' -t '^Injection:.*' --verbose --noStackTrace",
"test:definition-lists": "jest tests/markdown/definition-lists.test.js --verbose --noStackTrace",
"test:mustache-syntax": "jest \".*(mustache-syntax).*\" --verbose --noStackTrace",
"test:mustache-syntax:inline": "jest \".*(mustache-syntax).*\" -t '^Inline:.*' --verbose --noStackTrace",
"test:mustache-syntax:block": "jest \".*(mustache-syntax).*\" -t '^Block:.*' --verbose --noStackTrace",
"test:mustache-syntax:injection": "jest \".*(mustache-syntax).*\" -t '^Injection:.*' --verbose --noStackTrace",
"test:definition-lists": "jest tests/markdown/definition-lists.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",
"prod": "set NODE_ENV=production && npm run build",
@@ -81,17 +82,18 @@
]
},
"dependencies": {
"@babel/core": "^7.24.4",
"@babel/plugin-transform-runtime": "^7.24.3",
"@babel/preset-env": "^7.24.4",
"@babel/preset-react": "^7.24.1",
"@googleapis/drive": "^8.7.0",
"@babel/core": "^7.24.7",
"@babel/plugin-transform-runtime": "^7.24.7",
"@babel/preset-env": "^7.24.7",
"@babel/preset-react": "^7.24.7",
"@googleapis/drive": "^8.11.0",
"body-parser": "^1.20.2",
"classnames": "^2.5.1",
"codemirror": "^5.65.6",
"cookie-parser": "^1.4.6",
"create-react-class": "^15.7.0",
"dedent-tabs": "^0.10.3",
"dompurify": "^3.1.5",
"expr-eval": "^2.0.2",
"express": "^4.19.2",
"express-async-handler": "^1.2.0",
@@ -102,26 +104,27 @@
"less": "^3.13.1",
"lodash": "^4.17.21",
"marked": "11.2.0",
"marked-emoji": "^1.4.1",
"marked-extended-tables": "^1.0.8",
"marked-gfm-heading-id": "^3.1.3",
"marked-gfm-heading-id": "^3.2.0",
"marked-smartypants-lite": "^1.0.2",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.30.1",
"mongoose": "^8.3.1",
"mongoose": "^8.4.5",
"nanoid": "3.3.4",
"nconf": "^0.12.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-frame-component": "^4.1.3",
"react-router-dom": "6.22.3",
"react-router-dom": "6.24.1",
"sanitize-filename": "1.6.3",
"superagent": "^8.1.2",
"superagent": "^9.0.2",
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
},
"devDependencies": {
"eslint": "^8.57.0",
"eslint-plugin-jest": "^28.2.0",
"eslint-plugin-react": "^7.34.1",
"eslint-plugin-jest": "^28.6.0",
"eslint-plugin-react": "^7.34.3",
"jest": "^29.7.0",
"jest-expect-message": "^1.1.3",
"postcss-less": "^6.0.0",
@@ -129,6 +132,6 @@
"stylelint-config-recess-order": "^4.6.0",
"stylelint-config-recommended": "^13.0.0",
"stylelint-stylistic": "^0.4.3",
"supertest": "^6.3.4"
"supertest": "^7.0.0"
}
}

View File

@@ -25,6 +25,7 @@
"codemirror/addon/edit/closetag.js",
"codemirror/addon/edit/trailingspace.js",
"codemirror/addon/selection/active-line.js",
"codemirror/addon/hint/show-hint.js",
"moment",
"superagent"
]

View File

@@ -14,7 +14,7 @@ DB.connect(config).then(()=>{
console.log(`\n\tserver started at: ${new Date().toLocaleString()}`);
console.log(`\tserver on port: ${PORT}`);
console.log(`\t${bright + cyan}Open in browser: ${reset}${underline + bright + cyan}http://localhost:${PORT}${reset}\n\n`)
console.log(`\t${bright + cyan}Open in browser: ${reset}${underline + bright + cyan}http://localhost:${PORT}${reset}\n\n`);
});
});

View File

@@ -30,7 +30,7 @@ const junkBrewPipeline = [
{ $match : {
updatedAt : { $lt: Moment().subtract(30, 'days').toDate() },
lastViewed : { $lt: Moment().subtract(30, 'days').toDate() }
}},
} },
{ $project: { textBinSize: { $binarySize: '$textBin' } } },
{ $match: { textBinSize: { $lt: 140 } } },
{ $limit: 100 }

View File

@@ -23,7 +23,7 @@ const { splitTextStyleAndMetadata } = require('../shared/helpers.js');
const sanitizeBrew = (brew, accessType)=>{
brew._id = undefined;
brew.__v = undefined;
if(accessType !== 'edit'){
if(accessType !== 'edit' && accessType !== 'shareAuthor') {
brew.editId = undefined;
}
return brew;
@@ -307,7 +307,6 @@ app.get('/new/:id', asyncHandler(getBrew('share')), (req, res, next)=>{
//Share Page
app.get('/share/:id', asyncHandler(getBrew('share')), asyncHandler(async (req, res, next)=>{
const { brew } = req;
req.ogMeta = { ...defaultMetaTags,
title : req.brew.title || 'Untitled Brew',
description : req.brew.description || 'No description.',
@@ -326,18 +325,12 @@ app.get('/share/:id', asyncHandler(getBrew('share')), asyncHandler(async (req, r
await HomebrewModel.increaseView({ shareId: brew.shareId });
}
};
sanitizeBrew(req.brew, 'share');
brew.authors.includes(req.account?.username) ? sanitizeBrew(req.brew, 'shareAuthor') : sanitizeBrew(req.brew, 'share');
splitTextStyleAndMetadata(req.brew);
return next();
}));
//Print Page
app.get('/print/:id', asyncHandler(getBrew('share')), (req, res, next)=>{
sanitizeBrew(req.brew, 'share');
splitTextStyleAndMetadata(req.brew);
next();
});
//Account Page
app.get('/account', asyncHandler(async (req, res, next)=>{
const data = {};

View File

@@ -1,5 +1,4 @@
/* eslint-disable max-lines */
const _ = require('lodash');
const googleDrive = require('@googleapis/drive');
const { nanoid } = require('nanoid');
const token = require('./token.js');

View File

@@ -55,7 +55,7 @@ const api = {
stub = stub?.toObject();
if(stub?.lock?.locked && accessType != 'edit') {
throw { HBErrorCode: '100', code: stub.lock.code, message: stub.lock.message, brewId: stub.shareId, brewTitle: stub.title };
throw { HBErrorCode: '100', code: stub.lock.code, message: stub.lock.shareMessage, brewId: stub.shareId, brewTitle: stub.title };
}
// If there is a google id, try to find the google brew
@@ -83,9 +83,9 @@ const api = {
if(accessType === 'edit' && (authorsExist && !(isAuthor || isInvited))) {
const accessError = { name: 'Access Error', status: 401 };
if(req.account){
throw { ...accessError, message: 'User is not an Author', HBErrorCode: '03', authors: stub.authors, brewTitle: stub.title, shareId: stub.shareId};
throw { ...accessError, message: 'User is not an Author', HBErrorCode: '03', authors: stub.authors, brewTitle: stub.title, shareId: stub.shareId };
}
throw { ...accessError, message: 'User is not logged in', HBErrorCode: '04', authors: stub.authors, brewTitle: stub.title, shareId: stub.shareId};
throw { ...accessError, message: 'User is not logged in', HBErrorCode: '04', authors: stub.authors, brewTitle: stub.title, shareId: stub.shareId };
}
// If after all of that we still don't have a brew, throw an exception

View File

@@ -300,7 +300,7 @@ describe('Tests for api', ()=>{
});
it('access is denied to a locked brew', async()=>{
const lockBrew = { title: 'test brew', shareId: '1', lock: { locked: true, code: 404, message: 'brew locked' } };
const lockBrew = { title: 'test brew', shareId: '1', lock: { locked: true, code: 404, shareMessage: 'brew locked' } };
model.get = jest.fn(()=>toBrewPromise(lockBrew));
api.getId = jest.fn(()=>({ id: '1', googleId: undefined }));

View File

@@ -1,22 +1,34 @@
const _ = require('lodash');
const yaml = require('js-yaml');
const splitTextStyleAndMetadata = (brew) => {
brew.text = brew.text.replaceAll('\r\n', '\n');
if (brew.text.startsWith('```metadata')) {
const index = brew.text.indexOf('```\n\n');
const metadataSection = brew.text.slice(12, index - 1);
const metadata = yaml.load(metadataSection);
Object.assign(brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang']));
brew.text = brew.text.slice(index + 5);
}
if (brew.text.startsWith('```css')) {
const index = brew.text.indexOf('```\n\n');
brew.style = brew.text.slice(7, index - 1);
brew.text = brew.text.slice(index + 5);
}
const splitTextStyleAndMetadata = (brew)=>{
brew.text = brew.text.replaceAll('\r\n', '\n');
if(brew.text.startsWith('```metadata')) {
const index = brew.text.indexOf('```\n\n');
const metadataSection = brew.text.slice(12, index - 1);
const metadata = yaml.load(metadataSection);
Object.assign(brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang']));
brew.text = brew.text.slice(index + 5);
}
if(brew.text.startsWith('```css')) {
const index = brew.text.indexOf('```\n\n');
brew.style = brew.text.slice(7, index - 1);
brew.text = brew.text.slice(index + 5);
}
};
const printCurrentBrew = ()=>{
if(window.typeof !== 'undefined') {
window.frames['BrewRenderer'].contentWindow.print();
//Force DOM reflow; Print dialog causes a repaint, and @media print CSS somehow makes out-of-view pages disappear
const node = window.frames['BrewRenderer'].contentDocument.getElementsByClassName('brewRenderer').item(0);
node.style.display='none';
node.offsetHeight; // accessing this is enough to trigger a reflow
node.style.display='';
}
};
module.exports = {
splitTextStyleAndMetadata
splitTextStyleAndMetadata,
printCurrentBrew
};

View File

@@ -2,9 +2,8 @@ require('./renderWarnings.less');
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
const DISMISS_KEY = 'dismiss_render_warning';
import Dialog from '../../../client/components/dialog.jsx';
const RenderWarnings = createClass({
displayName : 'RenderWarnings',
@@ -35,9 +34,6 @@ const RenderWarnings = createClass({
},
},
checkWarnings : function(){
const hideDismiss = localStorage.getItem(DISMISS_KEY);
if(hideDismiss) return this.setState({ warnings: {} });
this.setState({
warnings : _.reduce(this.warnings, (r, fn, type)=>{
const element = fn();
@@ -46,20 +42,18 @@ const RenderWarnings = createClass({
}, {})
});
},
dismiss : function(){
localStorage.setItem(DISMISS_KEY, true);
this.checkWarnings();
},
render : function(){
if(_.isEmpty(this.state.warnings)) return null;
return <div className='renderWarnings'>
<i className='fas fa-times dismiss' onClick={this.dismiss}/>
const DISMISS_KEY = 'dismiss_render_warning';
const DISMISS_TEXT = <i className='fas fa-times dismiss' />;
return <Dialog className='renderWarnings' dismissKey={DISMISS_KEY} closeText={DISMISS_TEXT}>
<i className='fas fa-exclamation-triangle ohno' />
<h3>Render Warnings</h3>
<small>If this homebrew is rendering badly if might be because of the following:</small>
<ul>{_.values(this.state.warnings)}</ul>
</div>;
</Dialog>;
}
});

View File

@@ -1,53 +1,48 @@
.renderWarnings{
position : relative;
float : right;
display : inline-block;
.renderWarnings {
position : relative;
float : right;
width : 350px;
padding : 20px;
padding-bottom : 10px;
padding-left : 85px;
margin-bottom : 10px;
background-color : @yellow;
color : white;
a{
font-weight : 800;
}
i.ohno{
background-color : @yellow;
border : none;
a { font-weight : 800; }
i.ohno {
position : absolute;
top : 24px;
left : 24px;
opacity : 0.8;
font-size : 2.5em;
opacity : 0.8;
}
i.dismiss{
position : absolute;
top : 10px;
right : 10px;
cursor : pointer;
opacity : 0.6;
&:hover{
opacity : 1;
}
button.dismiss {
position : absolute;
top : 10px;
right : 10px;
cursor : pointer;
background-color : transparent;
opacity : 0.6;
&:hover { opacity : 1; }
}
small{
opacity : 0.7;
small {
font-size : 0.6em;
opacity : 0.7;
}
h3{
h3 {
font-size : 1.1em;
font-weight : 800;
}
ul{
ul {
margin-top : 15px;
font-size : 0.8em;
list-style-position : outside;
list-style-type : disc;
li{
li {
font-size : 0.8em;
line-height : 1.6em;
em{
font-weight : 800;
}
em { font-weight : 800; }
}
}
}

View File

@@ -0,0 +1,84 @@
const diceFont = require('../../../themes/fonts/iconFonts/diceFont.js');
const elderberryInn = require('../../../themes/fonts/iconFonts/elderberryInn.js');
const fontAwesome = require('../../../themes/fonts/iconFonts/fontAwesome.js');
const gameIcons = require('../../../themes/fonts/iconFonts/gameIcons.js');
const emojis = {
...diceFont,
...elderberryInn,
...fontAwesome,
...gameIcons
};
const showAutocompleteEmoji = function(CodeMirror, editor) {
CodeMirror.commands.autocomplete = function(editor) {
editor.showHint({
completeSingle : false,
hint : function(editor) {
const cursor = editor.getCursor();
const line = cursor.line;
const lineContent = editor.getLine(line);
const start = lineContent.lastIndexOf(':', cursor.ch - 1) + 1;
const end = cursor.ch;
const currentWord = lineContent.slice(start, end);
const list = Object.keys(emojis).filter(function(emoji) {
return emoji.toLowerCase().indexOf(currentWord.toLowerCase()) >= 0;
}).sort((a, b)=>{
const lowerA = a.replace(/\d+/g, function(match) { // Temporarily convert any numbers in emoji string
return match.padStart(4, '0'); // to 4-digits, left-padded with 0's, to aid in
}).toLowerCase(); // sorting numbers, i.e., "d6, d10, d20", not "d10, d20, d6"
const lowerB = b.replace(/\d+/g, function(match) { // Also make lowercase for case-insensitive alpha sorting
return match.padStart(4, '0');
}).toLowerCase();
if(lowerA < lowerB)
return -1;
return 1;
}).map(function(emoji) {
return {
text : `${emoji}:`, // Text to output to editor when option is selected
render : function(element, self, data) { // How to display the option in the dropdown
const div = document.createElement('div');
div.innerHTML = `<i class="emojiPreview ${emojis[emoji]}"></i> ${emoji}`;
element.appendChild(div);
}
};
});
return {
list : list.length ? list : [],
from : CodeMirror.Pos(line, start),
to : CodeMirror.Pos(line, end)
};
}
});
};
editor.on('inputRead', function(instance, change) {
const cursor = editor.getCursor();
const line = editor.getLine(cursor.line);
// Get the text from the start of the line to the cursor
const textToCursor = line.slice(0, cursor.ch);
// Do not autosuggest emojis in curly span/div/injector properties
if(line.includes('{')) {
const curlyToCursor = textToCursor.slice(textToCursor.indexOf(`{`));
const curlySpanRegex = /{(?=((?:[:=](?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':={}\s]*)*))\1$/g;
if(curlySpanRegex.test(curlyToCursor))
return;
}
// Check if the text ends with ':xyz'
if(/:[^\s:]+$/.test(textToCursor)) {
CodeMirror.commands.autocomplete(editor);
}
});
};
module.exports = {
showAutocompleteEmoji
};

View File

@@ -3,8 +3,8 @@ require('./codeEditor.less');
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
const closeTag = require('./close-tag');
const autoCompleteEmoji = require('./autocompleteEmoji');
let CodeMirror;
if(typeof window !== 'undefined'){
@@ -36,9 +36,13 @@ if(typeof window !== 'undefined'){
//XML code folding is a requirement of the auto-closing tag feature and is not enabled
require('codemirror/addon/fold/xml-fold.js');
require('codemirror/addon/edit/closetag.js');
//Autocompletion
require('codemirror/addon/hint/show-hint.js');
const foldCode = require('./fold-code');
foldCode.registerHomebreweryHelper(CodeMirror);
const foldPagesCode = require('./fold-pages');
foldPagesCode.registerHomebreweryHelper(CodeMirror);
const foldCSSCode = require('./fold-css');
foldCSSCode.registerHomebreweryHelper(CodeMirror);
}
const CodeEditor = createClass({
@@ -60,6 +64,8 @@ const CodeEditor = createClass({
};
},
editor : React.createRef(null),
componentDidMount : function() {
this.buildEditor();
const newDoc = CodeMirror.Doc(this.props.value, this.props.language);
@@ -99,7 +105,7 @@ const CodeEditor = createClass({
},
buildEditor : function() {
this.codeMirror = CodeMirror(this.refs.editor, {
this.codeMirror = CodeMirror(this.editor.current, {
lineNumbers : true,
lineWrapping : this.props.wrap,
indentWithTabs : false,
@@ -177,7 +183,10 @@ const CodeEditor = createClass({
// return el;
// }
});
// Add custom behaviors (auto-close curlies and auto-complete emojis)
closeTag.autoCloseCurlyBraces(CodeMirror, this.codeMirror);
autoCompleteEmoji.showAutocompleteEmoji(CodeMirror, this.codeMirror);
// Note: codeMirror passes a copy of itself in this callback. cm === this.codeMirror. Either one works.
this.codeMirror.on('change', (cm)=>{this.props.onChange(cm.getValue());});
@@ -404,7 +413,7 @@ const CodeEditor = createClass({
foldOptions : function(cm){
return {
scanUp : true,
rangeFinder : CodeMirror.fold.homebrewery,
rangeFinder : this.props.language === 'css' ? CodeMirror.fold.homebrewerycss : CodeMirror.fold.homebrewery,
widget : (from, to)=>{
let text = '';
let currentLine = from.line;
@@ -436,10 +445,11 @@ const CodeEditor = createClass({
render : function(){
return <>
<link href={`../homebrew/cm-themes/${this.props.editorTheme}.css`} type="text/css" rel='stylesheet' />
<div className='codeEditor' ref='editor' style={this.props.style}/>
<link href={`../homebrew/cm-themes/${this.props.editorTheme}.css`} type='text/css' rel='stylesheet' />
<div className='codeEditor' ref={this.editor} style={this.props.style}/>
</>;
}
});
module.exports = CodeEditor;

View File

@@ -2,6 +2,13 @@
@import (less) 'codemirror/addon/fold/foldgutter.css';
@import (less) 'codemirror/addon/search/matchesonscrollbar.css';
@import (less) 'codemirror/addon/dialog/dialog.css';
@import (less) 'codemirror/addon/hint/show-hint.css';
//Icon fonts included so they can appear in emoji autosuggest dropdown
@import (less) './themes/fonts/iconFonts/diceFont.less';
@import (less) './themes/fonts/iconFonts/elderberryInn.less';
@import (less) './themes/fonts/iconFonts/gameIcons.less';
@import (less) './themes/fonts/iconFonts/fontAwesome.less';
@keyframes sourceMoveAnimation {
50% {background-color: red; color: white;}
@@ -34,6 +41,7 @@
}
}
//.cm-tab {
// background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAQAAACOs/baAAAARUlEQVR4nGJgIAG8JkXxUAcCtDWemcGR1lY4MvgzCEKY7jSBjgxBDAG09UEQzAe0AMwMHrSOAwEGRtpaMIwAAAAA//8DAG4ID9EKs6YqAAAAAElFTkSuQmCC) no-repeat right;
//}
@@ -44,3 +52,8 @@
// }
//}
}
.emojiPreview {
font-size: 1.5em;
line-height: 1.2em;
}

View File

@@ -0,0 +1,44 @@
module.exports = {
registerHomebreweryHelper : function(CodeMirror) {
CodeMirror.registerHelper('fold', 'homebrewerycss', function(cm, start) {
// BRACE FOLDING
const startMatcher = /\{[ \t]*$/;
const endMatcher = /\}[ \t]*$/;
const prevLine = cm.getLine(start.line);
if(prevLine.match(startMatcher)) {
const lastLineNo = cm.lastLine();
let end = start.line + 1;
let braceCount = 1;
while (end < lastLineNo) {
const curLine = cm.getLine(end);
if(curLine.match(startMatcher)) braceCount++;
if(curLine.match(endMatcher)) braceCount--;
if(braceCount == 0) break;
++end;
}
return {
from : CodeMirror.Pos(start.line, 0),
to : CodeMirror.Pos(end, cm.getLine(end).length)
};
}
// IMPORT FOLDING
const importMatcher = /^@import.*?[;]/;
if(prevLine.match(importMatcher)) {
return {
from : CodeMirror.Pos(start.line, 0),
to : CodeMirror.Pos(start.line, cm.getLine(start.line).length)
};
}
return null;
});
}
};

View File

@@ -4,6 +4,14 @@ const Marked = require('marked');
const MarkedExtendedTables = require('marked-extended-tables');
const { markedSmartypantsLite: MarkedSmartypantsLite } = require('marked-smartypants-lite');
const { gfmHeadingId: MarkedGFMHeadingId } = require('marked-gfm-heading-id');
const { markedEmoji: MarkedEmojis } = require('marked-emoji');
//Icon fonts included so they can appear in emoji autosuggest dropdown
const diceFont = require('../../themes/fonts/iconFonts/diceFont.js');
const elderberryInn = require('../../themes/fonts/iconFonts/elderberryInn.js');
const fontAwesome = require('../../themes/fonts/iconFonts/fontAwesome.js');
const gameIcons = require('../../themes/fonts/iconFonts/gameIcons.js');
const MathParser = require('expr-eval').Parser;
const renderer = new Marked.Renderer();
const tokenizer = new Marked.Tokenizer();
@@ -50,7 +58,7 @@ renderer.html = function (html) {
return html;
};
// Don't wrap {{ Divs or {{ empty Spans in <p> tags
// Don't wrap {{ Spans alone on a line, or {{ Divs in <p> tags
renderer.paragraph = function(text){
let match;
if(text.startsWith('<div') || text.startsWith('</div'))
@@ -94,18 +102,18 @@ const mustacheSpans = {
start(src) { return src.match(/{{[^{]/)?.index; }, // Hint to Marked.js to stop and check for a match
tokenizer(src, tokens) {
const completeSpan = /^{{[^\n]*}}/; // Regex for the complete token
const inlineRegex = /{{(?=((?:[:=](?:"['\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"=':{}\s]*)*))\1 *|}}/g;
const inlineRegex = /{{(?=((?:[:=](?:"['\w,\-()#%=?. ]*"|[\w\-()#%.]*)|[^"=':{}\s]*)*))\1 *|}}/g;
const match = completeSpan.exec(src);
if(match) {
//Find closing delimiter
let blockCount = 0;
let tags = '';
let tags = {};
let endTags = 0;
let endToken = 0;
let delim;
while (delim = inlineRegex.exec(match[0])) {
if(!tags) {
tags = `${processStyleTags(delim[0].substring(2))}`;
if(_.isEmpty(tags)) {
tags = processStyleTags(delim[0].substring(2));
endTags = delim[0].length;
}
if(delim[0].startsWith('{{')) {
@@ -134,7 +142,14 @@ const mustacheSpans = {
}
},
renderer(token) {
return `<span class="inline-block${token.tags}>${this.parser.parseInline(token.tokens)}</span>`; // parseInline to turn child tokens into HTML
const tags = token.tags;
tags.classes = ['inline-block', tags.classes].join(' ').trim();
return `<span` +
`${tags.classes ? ` class="${tags.classes}"` : ''}` +
`${tags.id ? ` id="${tags.id}"` : ''}` +
`${tags.styles ? ` style="${tags.styles}"` : ''}` +
`${tags.attributes ? ` ${Object.entries(tags.attributes).map(([key, value])=>`${key}="${value}"`).join(' ')}` : ''}` +
`>${this.parser.parseInline(token.tokens)}</span>`; // parseInline to turn child tokens into HTML
}
};
@@ -144,18 +159,18 @@ const mustacheDivs = {
start(src) { return src.match(/\n *{{[^{]/m)?.index; }, // Hint to Marked.js to stop and check for a match
tokenizer(src, tokens) {
const completeBlock = /^ *{{[^\n}]* *\n.*\n *}}/s; // Regex for the complete token
const blockRegex = /^ *{{(?=((?:[:=](?:"['\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"=':{}\s]*)*))\1 *$|^ *}}$/gm;
const blockRegex = /^ *{{(?=((?:[:=](?:"['\w,\-()#%=?. ]*"|[\w\-()#%.]*)|[^"=':{}\s]*)*))\1 *$|^ *}}$/gm;
const match = completeBlock.exec(src);
if(match) {
//Find closing delimiter
let blockCount = 0;
let tags = '';
let tags = {};
let endTags = 0;
let endToken = 0;
let delim;
while (delim = blockRegex.exec(match[0])?.[0].trim()) {
if(!tags) {
tags = `${processStyleTags(delim.substring(2))}`;
if(_.isEmpty(tags)) {
tags = processStyleTags(delim.substring(2));
endTags = delim.length + src.indexOf(delim);
}
if(delim.startsWith('{{')) {
@@ -183,7 +198,14 @@ const mustacheDivs = {
}
},
renderer(token) {
return `<div class="block${token.tags}>${this.parser.parse(token.tokens)}</div>`; // parseInline to turn child tokens into HTML
const tags = token.tags;
tags.classes = ['block', tags.classes].join(' ').trim();
return `<div` +
`${tags.classes ? ` class="${tags.classes}"` : ''}` +
`${tags.id ? ` id="${tags.id}"` : ''}` +
`${tags.styles ? ` style="${tags.styles}"` : ''}` +
`${tags.attributes ? ` ${Object.entries(tags.attributes).map(([key, value])=>`${key}="${value}"`).join(' ')}` : ''}` +
`>${this.parser.parse(token.tokens)}</div>`; // parse to turn child tokens into HTML
}
};
@@ -192,30 +214,46 @@ const mustacheInjectInline = {
level : 'inline',
start(src) { return src.match(/ *{[^{\n]/)?.index; }, // Hint to Marked.js to stop and check for a match
tokenizer(src, tokens) {
const inlineRegex = /^ *{(?=((?:[:=](?:"['\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"=':{}\s]*)*))\1}/g;
const inlineRegex = /^ *{(?=((?:[:=](?:"['\w,\-()#%=?. ]*"|[\w\-()#%.]*)|[^"=':{}\s]*)*))\1}/g;
const match = inlineRegex.exec(src);
if(match) {
const lastToken = tokens[tokens.length - 1];
if(!lastToken || lastToken.type == 'mustacheInjectInline')
return false;
const tags = `${processStyleTags(match[1])}`;
const tags = processStyleTags(match[1]);
lastToken.originalType = lastToken.type;
lastToken.type = 'mustacheInjectInline';
lastToken.tags = tags;
lastToken.injectedTags = tags;
return {
type : 'text', // Should match "name" above
type : 'mustacheInjectInline', // Should match "name" above
raw : match[0], // Text to consume from the source
text : ''
};
}
},
renderer(token) {
if(!token.originalType){
return;
}
token.type = token.originalType;
const text = this.parser.parseInline([token]);
const openingTag = /(<[^\s<>]+)([^\n<>]*>.*)/s.exec(text);
const originalTags = extractHTMLStyleTags(text);
const injectedTags = token.injectedTags;
const tags = {
id : injectedTags.id || originalTags.id || null,
classes : [originalTags.classes, injectedTags.classes].join(' ').trim() || null,
styles : [originalTags.styles, injectedTags.styles].join(' ').trim() || null,
attributes : Object.assign(originalTags.attributes ?? {}, injectedTags.attributes ?? {})
};
const openingTag = /(<[^\s<>]+)[^\n<>]*(>.*)/s.exec(text);
if(openingTag) {
return `${openingTag[1]} class="${token.tags}${openingTag[2]}`;
return `${openingTag[1]}` +
`${tags.classes ? ` class="${tags.classes}"` : ''}` +
`${tags.id ? ` id="${tags.id}"` : ''}` +
`${tags.styles ? ` style="${tags.styles}"` : ''}` +
`${!_.isEmpty(tags.attributes) ? ` ${Object.entries(tags.attributes).map(([key, value])=>`${key}="${value}"`).join(' ')}` : ''}` +
`${openingTag[2]}`; // parse to turn child tokens into HTML
}
return text;
}
@@ -227,7 +265,7 @@ const mustacheInjectBlock = {
level : 'block',
start(src) { return src.match(/\n *{[^{\n]/m)?.index; }, // Hint to Marked.js to stop and check for a match
tokenizer(src, tokens) {
const inlineRegex = /^ *{(?=((?:[:=](?:"['\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"=':{}\s]*)*))\1}/ym;
const inlineRegex = /^ *{(?=((?:[:=](?:"['\w,\-()#%=?. ]*"|[\w\-()#%.]*)|[^"=':{}\s]*)*))\1}/ym;
const match = inlineRegex.exec(src);
if(match) {
const lastToken = tokens[tokens.length - 1];
@@ -235,7 +273,7 @@ const mustacheInjectBlock = {
return false;
lastToken.originalType = 'mustacheInjectBlock';
lastToken.tags = `${processStyleTags(match[1])}`;
lastToken.injectedTags = processStyleTags(match[1]);
return {
type : 'mustacheInjectBlock', // Should match "name" above
raw : match[0], // Text to consume from the source
@@ -249,9 +287,22 @@ const mustacheInjectBlock = {
}
token.type = token.originalType;
const text = this.parser.parse([token]);
const openingTag = /(<[^\s<>]+)([^\n<>]*>.*)/s.exec(text);
const originalTags = extractHTMLStyleTags(text);
const injectedTags = token.injectedTags;
const tags = {
id : injectedTags.id || originalTags.id || null,
classes : [originalTags.classes, injectedTags.classes].join(' ').trim() || null,
styles : [originalTags.styles, injectedTags.styles].join(' ').trim() || null,
attributes : Object.assign(originalTags.attributes ?? {}, injectedTags.attributes ?? {})
};
const openingTag = /(<[^\s<>]+)[^\n<>]*(>.*)/s.exec(text);
if(openingTag) {
return `${openingTag[1]} class="${token.tags}${openingTag[2]}`;
return `${openingTag[1]}` +
`${tags.classes ? ` class="${tags.classes}"` : ''}` +
`${tags.id ? ` id="${tags.id}"` : ''}` +
`${tags.styles ? ` style="${tags.styles}"` : ''}` +
`${!_.isEmpty(tags.attributes) ? ` ${Object.entries(tags.attributes).map(([key, value])=>`${key}="${value}"`).join(' ')}` : ''}` +
`${openingTag[2]}`; // parse to turn child tokens into HTML
}
return text;
}
@@ -304,10 +355,19 @@ const definitionListsSingleLine = {
let endIndex = 0;
const definitions = [];
while (match = regex.exec(src)) {
definitions.push({
dt : this.lexer.inlineTokens(match[1].trim()),
dd : this.lexer.inlineTokens(match[2].trim())
});
const originalLine = match[0]; // This line and below to handle conflict with emojis
let firstLine = originalLine; // Remove in V4 when definitionListsInline updated to
this.lexer.inlineTokens(firstLine.trim()) // require spaces around `::`
.filter((t)=>t.type == 'emoji')
.map((emoji)=>firstLine = firstLine.replace(emoji.raw, 'x'.repeat(emoji.raw.length)));
const newMatch = /^([^\n]*?)::([^\n]*)(?:\n|$)/ym.exec(firstLine);
if(newMatch) {
definitions.push({
dt : this.lexer.inlineTokens(originalLine.slice(0, newMatch[1].length).trim()),
dd : this.lexer.inlineTokens(originalLine.slice(newMatch[1].length + 2).trim())
});
} // End of emoji hack.
endIndex = regex.lastIndex;
}
if(definitions.length) {
@@ -616,11 +676,30 @@ function MarkedVariables() {
};
//^=====--------------------< Variable Handling >-------------------=====^//
// Emoji options
// To add more icon fonts, need to do these things
// 1) Add the font file as .woff2 to themes/fonts/iconFonts folder
// 2) Create a .less file mapping CSS class names to the font character
// 3) Create a .js file mapping Autosuggest names to CSS class names
// 4) Import the .less file into shared/naturalcrit/codeEditor/codeEditor.less
// 5) Import the .less file into themes/V3/blank.style.less
// 6) Import the .js file to shared/naturalcrit/codeEditor/autocompleteEmoji.js and add to `emojis` object
// 7) Import the .js file here to markdown.js, and add to `emojis` object below
const MarkedEmojiOptions = {
emojis : {
...diceFont,
...elderberryInn,
...fontAwesome,
...gameIcons,
},
renderer : (token)=>`<i class="${token.emoji}"></i>`
};
Marked.use(MarkedVariables());
Marked.use({ extensions: [definitionListsMultiLine, definitionListsSingleLine, superSubScripts, mustacheSpans, mustacheDivs, mustacheInjectInline] });
Marked.use(mustacheInjectBlock);
Marked.use({ renderer: renderer, tokenizer: tokenizer, mangle: false });
Marked.use(MarkedExtendedTables(), MarkedGFMHeadingId(), MarkedSmartypantsLite());
Marked.use(MarkedExtendedTables(), MarkedGFMHeadingId(), MarkedSmartypantsLite(), MarkedEmojis(MarkedEmojiOptions));
const nonWordAndColonTest = /[^\w:]/g;
const cleanUrl = function (sanitize, base, href) {
@@ -687,15 +766,49 @@ const processStyleTags = (string)=>{
//TODO: can we simplify to just split on commas?
const tags = string.match(/(?:[^, ":=]+|[:=](?:"[^"]*"|))+/g);
const id = _.remove(tags, (tag)=>tag.startsWith('#')).map((tag)=>tag.slice(1))[0];
const classes = _.remove(tags, (tag)=>(!tag.includes(':')) && (!tag.includes('=')));
const attributes = _.remove(tags, (tag)=>(tag.includes('='))).map((tag)=>tag.replace(/="?([^"]*)"?/g, '="$1"'));
const styles = tags?.length ? tags.map((tag)=>tag.replace(/:"?([^"]*)"?/g, ':$1;').trim()) : [];
const id = _.remove(tags, (tag)=>tag.startsWith('#')).map((tag)=>tag.slice(1))[0] || null;
const classes = _.remove(tags, (tag)=>(!tag.includes(':')) && (!tag.includes('='))).join(' ') || null;
const attributes = _.remove(tags, (tag)=>(tag.includes('='))).map((tag)=>tag.replace(/="?([^"]*)"?/g, '="$1"'))
?.filter((attr)=>!attr.startsWith('class="') && !attr.startsWith('style="') && !attr.startsWith('id="'))
.reduce((obj, attr)=>{
const index = attr.indexOf('=');
let [key, value] = [attr.substring(0, index), attr.substring(index + 1)];
value = value.replace(/"/g, '');
obj[key] = value;
return obj;
}, {}) || null;
const styles = tags?.length ? tags.map((tag)=>tag.replace(/:"?([^"]*)"?/g, ':$1;').trim()).join(' ') : null;
return `${classes?.length ? ` ${classes.join(' ')}` : ''}"` +
`${id ? ` id="${id}"` : ''}` +
`${styles?.length ? ` style="${styles.join(' ')}"` : ''}` +
`${attributes?.length ? ` ${attributes.join(' ')}` : ''}`;
return {
id : id,
classes : classes,
styles : styles,
attributes : _.isEmpty(attributes) ? null : attributes
};
};
//Given a string representing an HTML element, extract all of its properties (id, class, style, and other attributes)
const extractHTMLStyleTags = (htmlString)=>{
const firstElementOnly = htmlString.split('>')[0];
const id = firstElementOnly.match(/id="([^"]*)"/)?.[1] || null;
const classes = firstElementOnly.match(/class="([^"]*)"/)?.[1] || null;
const styles = firstElementOnly.match(/style="([^"]*)"/)?.[1] || null;
const attributes = firstElementOnly.match(/[a-zA-Z]+="[^"]*"/g)
?.filter((attr)=>!attr.startsWith('class="') && !attr.startsWith('style="') && !attr.startsWith('id="'))
.reduce((obj, attr)=>{
const index = attr.indexOf('=');
let [key, value] = [attr.substring(0, index), attr.substring(index + 1)];
value = value.replace(/"/g, '');
obj[key] = value;
return obj;
}, {}) || null;
return {
id : id,
classes : classes,
styles : styles,
attributes : _.isEmpty(attributes) ? null : attributes
};
};
const globalVarsList = {};

View File

@@ -47,8 +47,8 @@ const Nav = {
color : null
};
},
handleClick : function(){
this.props.onClick();
handleClick : function(e){
this.props.onClick(e);
},
render : function(){
const classes = cx('navItem', this.props.color, this.props.className);

View File

@@ -1,7 +1,6 @@
require('./splitPane.less');
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
const SplitPane = createClass({
@@ -24,6 +23,9 @@ const SplitPane = createClass({
};
},
pane1 : React.createRef(null),
pane2 : React.createRef(null),
componentDidMount : function() {
const dividerPos = window.localStorage.getItem(this.props.storageKey);
if(dividerPos){
@@ -137,7 +139,6 @@ const SplitPane = createClass({
render : function(){
return <div className='splitPane' onPointerMove={this.handleMove} onPointerUp={this.handleUp}>
<Pane
ref='pane1'
width={this.state.currentDividerPos}
>
{React.cloneElement(this.props.children[0], {
@@ -147,7 +148,7 @@ const SplitPane = createClass({
})}
</Pane>
{this.renderDivider()}
<Pane ref='pane2' isDragging={this.state.isDragging}>{this.props.children[1]}</Pane>
<Pane isDragging={this.state.isDragging}>{this.props.children[1]}</Pane>
</div>;
}
});

View File

@@ -0,0 +1,58 @@
const Markdown = require('naturalcrit/markdown.js');
const dedent = require('dedent-tabs').default;
// Marked.js adds line returns after closing tags on some default tokens.
// This removes those line returns for comparison sake.
String.prototype.trimReturns = function(){
return this.replace(/\r?\n|\r/g, '');
};
const emoji = 'df_d12_2';
describe(`When emojis/icons are active`, ()=>{
it('when a word is between two colons (:word:), and a matching emoji exists, it is rendered as an emoji', function() {
const source = `:${emoji}:`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<p><i class="df d12-2"></i></p>`);
});
it('when a word is between two colons (:word:), and no matching emoji exists, it is not parsed', function() {
const source = `:invalid:`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<p>:invalid:</p>`);
});
it('two valid emojis with no whitespace are prioritized over definition lists', function() {
const source = `:${emoji}::${emoji}:`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<p><i class="df d12-2"></i><i class="df d12-2"></i></p>`);
});
it('definition lists that are not also part of an emoji can coexist with normal emojis', function() {
const source = `definition :: term ${emoji}::${emoji}:`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<dl><dt>definition</dt><dd>term df_d12_2:<i class="df d12-2"></i></dd></dl>`);
});
it('A valid emoji is compatible with curly injectors', function() {
const source = `:${emoji}:{color:blue,myClass}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<p><i class="df d12-2 myClass" style="color:blue;"></i></p>`);
});
it('Emojis are not parsed inside of curly span CSS blocks', function() {
const source = `{{color:${emoji} text}}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<span class="inline-block" style="color:df_d12_2;">text</span>`);
});
it('Emojis are not parsed inside of curly div CSS blocks', function() {
const source = dedent`{{color:${emoji}
text
}}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block" style="color:df_d12_2;"><p>text</p></div>`);
});
// another test of the editor to confirm an autocomplete menu opens
});

View File

@@ -130,8 +130,8 @@ describe('Inline: When using the Inline syntax {{ }}', ()=>{
describe(`Block: When using the Block syntax {{tags\\ntext\\n}}`, ()=>{
it('Renders a div with text only', function() {
const source = dedent`{{
text
}}`;
text
}}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block"><p>text</p></div>`);
});
@@ -139,14 +139,14 @@ describe(`Block: When using the Block syntax {{tags\\ntext\\n}}`, ()=>{
it('Renders an empty div', function() {
const source = dedent`{{
}}`;
}}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block"></div>`);
});
it('Renders a single paragraph with opening and closing brackets', function() {
const source = dedent`{{
}}`;
}}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<p>{{}}</p>`);
});
@@ -154,79 +154,79 @@ describe(`Block: When using the Block syntax {{tags\\ntext\\n}}`, ()=>{
it('Renders a div with a single class', function() {
const source = dedent`{{cat
}}`;
}}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block cat"></div>`);
});
it('Renders a div with a single class and text', function() {
const source = dedent`{{cat
Sample text.
}}`;
Sample text.
}}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block cat"><p>Sample text.</p></div>`);
});
it('Renders a div with two classes and text', function() {
const source = dedent`{{cat,dog
Sample text.
}}`;
Sample text.
}}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block cat dog"><p>Sample text.</p></div>`);
});
it('Renders a div with a style and text', function() {
const source = dedent`{{color:red
Sample text.
}}`;
Sample text.
}}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block" style="color:red;"><p>Sample text.</p></div>`);
});
it('Renders a div with a style that has a string variable, and text', function() {
const source = dedent`{{--stringVariable:"'string'"
Sample text.
}}`;
Sample text.
}}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block" style="--stringVariable:'string';"><p>Sample text.</p></div>`);
});
it('Renders a div with a style that has a string variable, and text', function() {
const source = dedent`{{--stringVariable:"'string'"
Sample text.
}}`;
Sample text.
}}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block" style="--stringVariable:'string';"><p>Sample text.</p></div>`);
});
it('Renders a div with a class, style and text', function() {
const source = dedent`{{cat,color:red
Sample text.
}}`;
Sample text.
}}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block cat" style="color:red;"><p>Sample text.</p></div>`);
});
it('Renders a div with an ID, class, style and text (different order)', function() {
const source = dedent`{{color:red,cat,#dog
Sample text.
}}`;
Sample text.
}}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block cat" id="dog" style="color:red;"><p>Sample text.</p></div>`);
});
it('Renders a div with a single ID', function() {
const source = dedent`{{#cat,#dog
Sample text.
}}`;
Sample text.
}}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block" id="cat"><p>Sample text.</p></div>`);
});
it('Renders a div with an ID, class, style and text, and a variable assignment', function() {
const source = dedent`{{color:red,cat,#dog,a="b and c",d="e"
Sample text.
}}`;
Sample text.
}}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class=\"block cat\" id=\"dog\" style=\"color:red;\" a=\"b and c\" d=\"e\"><p>Sample text.</p></div>`);
});
@@ -243,124 +243,218 @@ describe(`Block: When using the Block syntax {{tags\\ntext\\n}}`, ()=>{
describe('Injection: When an injection tag follows an element', ()=>{
// FIXME: Most of these fail because injections currently replace attributes, rather than append to. Or just minor extra whitespace issues.
describe('and that element is an inline-block', ()=>{
it.failing('Renders a span "text" with no injection', function() {
it('Renders a span "text" with no injection', function() {
const source = '{{ text}}{}';
const rendered = Markdown.render(source);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block">text</span>');
});
it.failing('Renders a span "text" with injected Class name', function() {
it('Renders a span "text" with injected Class name', function() {
const source = '{{ text}}{ClassName}';
const rendered = Markdown.render(source);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block ClassName">text</span>');
});
it.failing('Renders a span "text" with injected attribute', function() {
it('Renders a span "text" with injected attribute', function() {
const source = '{{ text}}{a="b and c"}';
const rendered = Markdown.render(source);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span a="b and c" class="inline-block ">text</span>');
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block" a="b and c">text</span>');
});
it.failing('Renders a span "text" with injected style', function() {
it('Renders a span "text" with injected style', function() {
const source = '{{ text}}{color:red}';
const rendered = Markdown.render(source);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block" style="color:red;">text</span>');
});
it.failing('Renders a span "text" with injected style using a string variable', function() {
it('Renders a span "text" with injected style using a string variable', function() {
const source = `{{ text}}{--stringVariable:"'string'"}`;
const rendered = Markdown.render(source);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<span class="inline-block" style="--stringVariable:'string';">text</span>`);
});
it.failing('Renders a span "text" with two injected styles', function() {
it('Renders a span "text" with two injected styles', function() {
const source = '{{ text}}{color:red,background:blue}';
const rendered = Markdown.render(source);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block" style="color:red; background:blue;">text</span>');
});
it.failing('Renders an emphasis element with injected Class name', function() {
it('Renders a span "text" with its own ID, overwritten with an injected ID', function() {
const source = '{{#oldId text}}{#newId}';
const rendered = Markdown.render(source);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block" id="newId">text</span>');
});
it('Renders a span "text" with its own attributes, overwritten with an injected attribute, plus a new one', function() {
const source = '{{attrA="old",attrB="old" text}}{attrA="new",attrC="new"}';
const rendered = Markdown.render(source);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block" attrA="new" attrB="old" attrC="new">text</span>');
});
it('Renders a span "text" with its own attributes, overwritten with an injected attribute, ignoring "class", "style", and "id"', function() {
const source = '{{attrA="old",attrB="old" text}}{attrA="new",attrC="new",class="new",style="new",id="new"}';
const rendered = Markdown.render(source);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block" attrA="new" attrB="old" attrC="new">text</span>');
});
it('Renders a span "text" with its own styles, appended with injected styles', function() {
const source = '{{color:blue,height:10px text}}{width:10px,color:red}';
const rendered = Markdown.render(source);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block" style="color:blue; height:10px; width:10px; color:red;">text</span>');
});
it('Renders a span "text" with its own classes, appended with injected classes', function() {
const source = '{{classA,classB text}}{classA,classC}';
const rendered = Markdown.render(source);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block classA classB classA classC">text</span>');
});
it('Renders an emphasis element with injected Class name', function() {
const source = '*emphasis*{big}';
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<p><em class="big">emphasis</em></p>');
});
it.failing('Renders a code element with injected style', function() {
it('Renders a code element with injected style', function() {
const source = '`code`{background:gray}';
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<p><code style="background:gray;">code</code></p>');
});
it.failing('Renders an image element with injected style', function() {
it('Renders an image element with injected style', function() {
const source = '![alt text](http://i.imgur.com/hMna6G0.png){position:absolute}';
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<p><img src="http://i.imgur.com/hMna6G0.png" alt="homebrew mug" style="position:absolute;"></p>');
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<p><img style="position:absolute;" src="http://i.imgur.com/hMna6G0.png" alt="alt text"></p>');
});
it.failing('Renders an element modified by only the first of two consecutive injections', function() {
it('Renders an element modified by only the first of two consecutive injections', function() {
const source = '{{ text}}{color:red}{background:blue}';
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<p><span class="inline-block" style="color:red;">text</span>{background:blue}</p>');
});
it('Renders an parent and child element, each modified by an injector', function() {
const source = dedent`**bolded text**{color:red}
{color:blue}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<p style="color:blue;"><strong style="color:red;">bolded text</strong></p>');
});
it('Renders an image with added attributes', function() {
const source = `![homebrew mug](https://i.imgur.com/hMna6G0.png) {position:absolute,bottom:20px,left:130px,width:220px,a="b and c",d=e}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<p><img class="" style="position:absolute; bottom:20px; left:130px; width:220px;" a="b and c" d="e" src="https://i.imgur.com/hMna6G0.png" alt="homebrew mug"></p>`);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<p><img style="position:absolute; bottom:20px; left:130px; width:220px;" src="https://i.imgur.com/hMna6G0.png" alt="homebrew mug" a="b and c" d="e"></p>`);
});
it('Renders an image with "=" in the url, and added attributes', function() {
const source = `![homebrew mug](https://i.imgur.com/hMna6G0.png?auth=12345&height=1024) {position:absolute,bottom:20px,left:130px,width:220px,a="b and c",d=e}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<p><img style="position:absolute; bottom:20px; left:130px; width:220px;" src="https://i.imgur.com/hMna6G0.png?auth=12345&height=1024" alt="homebrew mug" a="b and c" d="e"></p>`);
});
it('Renders an image and added attributes with "=" in the value, ', function() {
const source = `![homebrew mug](https://i.imgur.com/hMna6G0.png) {position:absolute,bottom:20px,left:130px,width:220px,a="b and c",d=e,otherUrl="url?auth=12345"}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<p><img style="position:absolute; bottom:20px; left:130px; width:220px;" src="https://i.imgur.com/hMna6G0.png" alt="homebrew mug" a="b and c" d="e" otherUrl="url?auth=12345"></p>`);
});
});
describe('and that element is a block', ()=>{
it.failing('renders a div "text" with no injection', function() {
it('renders a div "text" with no injection', function() {
const source = '{{\ntext\n}}\n{}';
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<div class="block"><p>text</p></div>');
});
it.failing('renders a div "text" with injected Class name', function() {
it('renders a div "text" with injected Class name', function() {
const source = '{{\ntext\n}}\n{ClassName}';
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<div class="block ClassName"><p>text</p></div>');
});
it.failing('renders a div "text" with injected style', function() {
it('renders a div "text" with injected style', function() {
const source = '{{\ntext\n}}\n{color:red}';
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<div class="block" style="color:red;"><p>text</p></div>');
});
it.failing('renders a div "text" with two injected styles', function() {
it('renders a div "text" with two injected styles', function() {
const source = dedent`{{
text
}}
{color:red,background:blue}`;
text
}}
{color:red,background:blue}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block" style="color:red; background:blue"><p>text</p></div>`);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block" style="color:red; background:blue;"><p>text</p></div>`);
});
it.failing('renders a div "text" with injected variable string', function() {
it('renders a div "text" with injected variable string', function() {
const source = dedent`{{
text
}}
{--stringVariable:"'string'"}`;
text
}}
{--stringVariable:"'string'"}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block" style="--stringVariable:'string'"><p>text</p></div>`);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<div class="block" style="--stringVariable:'string';"><p>text</p></div>`);
});
it.failing('renders an h2 header "text" with injected class name', function() {
it('Renders a span "text" with its own ID, overwritten with an injected ID', function() {
const source = dedent`{{#oldId
text
}}
{#newId}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<div class="block" id="newId"><p>text</p></div>');
});
it('Renders a span "text" with its own attributes, overwritten with an injected attribute, plus a new one', function() {
const source = dedent`{{attrA="old",attrB="old"
text
}}
{attrA="new",attrC="new"}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<div class="block" attrA="new" attrB="old" attrC="new"><p>text</p></div>');
});
it('Renders a span "text" with its own attributes, overwritten with an injected attribute, ignoring "class", "style", and "id"', function() {
const source = dedent`{{attrA="old",attrB="old"
text
}}
{attrA="new",attrC="new",class="new",style="new",id="new"}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<div class="block" attrA="new" attrB="old" attrC="new"><p>text</p></div>');
});
it('Renders a span "text" with its own styles, appended with injected styles', function() {
const source = dedent`{{color:blue,height:10px
text
}}
{width:10px,color:red}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<div class="block" style="color:blue; height:10px; width:10px; color:red;"><p>text</p></div>');
});
it('Renders a span "text" with its own classes, appended with injected classes', function() {
const source = dedent`{{classA,classB
text
}}
{classA,classC}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<div class="block classA classB classA classC"><p>text</p></div>');
});
it('renders an h2 header "text" with injected class name', function() {
const source = dedent`## text
{ClassName}`;
{ClassName}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<h2 class="ClassName">text</h2>');
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<h2 class="ClassName" id="text">text</h2>');
});
it.failing('renders a table with injected class name', function() {
it('renders a table with injected class name', function() {
const source = dedent`| Experience Points | Level |
|:------------------|:-----:|
| 0 | 1 |
| 300 | 2 |
|:------------------|:-----:|
| 0 | 1 |
| 300 | 2 |
{ClassName}`;
{ClassName}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<table class="ClassName"><thead><tr><th align=left>Experience Points</th><th align=center>Level</th></tr></thead><tbody><tr><td align=left>0</td><td align=center>1</td></tr><tr><td align=left>300</td><td align=center>2</td></tr></tbody></table>`);
});
@@ -376,23 +470,23 @@ describe('Injection: When an injection tag follows an element', ()=>{
// expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`...`); // FIXME: expect this to be injected into <ul>? Currently injects into last <li>
// });
it.failing('renders an h2 header "text" with injected class name, and "secondInjection" as regular text on the next line.', function() {
it('renders an h2 header "text" with injected class name, and "secondInjection" as regular text on the next line.', function() {
const source = dedent`## text
{ClassName}
{secondInjection}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<h2 class="ClassName">text</h2><p>{secondInjection}</p>');
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<h2 class="ClassName" id="text">text</h2><p>{secondInjection}</p>');
});
it.failing('renders a div nested into another div, the inner with class=innerDiv and the other class=outerDiv', function() {
it('renders a div nested into another div, the inner with class=innerDiv and the other class=outerDiv', function() {
const source = dedent`{{
outer text
{{
inner text
}}
{innerDiv}
}}
{outerDiv}`;
outer text
{{
inner text
}}
{innerDiv}
}}
{outerDiv}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<div class="block outerDiv"><p>outer text</p><div class="block innerDiv"><p>inner text</p></div></div>');
});

View File

@@ -329,7 +329,7 @@ describe('Normal Links and Images', ()=>{
const source = `![alt text](url){width:100px}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(dedent`
<p><img class="" style="width:100px;" src="url" alt="alt text"></p>`.trimReturns());
<p><img style="width:100px;" src="url" alt="alt text"></p>`.trimReturns());
});
it('Renders normal links', function() {

View File

@@ -21,9 +21,43 @@ module.exports = [
view : 'text',
snippets : [
{
name : 'Table of Contents',
icon : 'fas fa-book',
gen : TableOfContentsGen
name : 'Table of Contents',
icon : 'fas fa-book',
gen : TableOfContentsGen,
experimental : true,
subsnippets : [
{
name : 'Table of Contents',
icon : 'fas fa-book',
gen : TableOfContentsGen,
experimental : true
},
{
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 : 'Index',

View File

@@ -171,7 +171,7 @@ module.exports = {
**Condition Immunities** :: ${genList(['groggy', 'swagged', 'weak-kneed', 'buzzed', 'groovy', 'melancholy', 'drunk'], 3)}
**Senses** :: darkvision 60 ft., passive Perception ${_.random(3, 20)}
**Languages** :: ${genList(['Common', 'Pottymouth', 'Gibberish', 'Latin', 'Jive'], 2)}
**Challenge** :: ${_.random(0, 15)} (${_.random(10, 10000)} XP)
**Challenge** :: ${_.random(0, 15)} (${_.random(10, 10000)} XP) {{bonus **Proficiency Bonus** +${_.random(2, 6)}}}
___
${_.times(_.random(genLines, genLines + 2), function(){return genAbilities();}).join('\n:\n')}
:

View File

@@ -1,47 +1,47 @@
const _ = require("lodash");
const _ = require('lodash');
const quotes = [
"The sword glinted in the dim light, its edges keen and deadly. As the adventurer reached for it, he couldn't help but feel a surge of excitement mixed with fear. This was no ordinary blade.",
"The dragon's roar shook the ground beneath their feet, and the brave knight stood tall, his sword at the ready. He knew that this would be the battle of his life, but he was determined to emerge victorious.",
"The wizard's laboratory was a sight to behold, filled with bubbling cauldrons, ancient tomes, and strange artifacts from distant lands. As the apprentice gazed around in wonder, she knew that she was about to embark on a journey unlike any other.",
"The tavern was packed with rowdy patrons, their voices raised in song and laughter. The bard took center stage, strumming his lute and launching into a tale of adventure and heroism that had the crowd hanging on his every word.",
"The thief crept through the shadows, his eyes scanning the room for any sign of danger. He knew that one false move could mean the difference between success and failure, and he was determined to come out on top.",
"The elf queen stood atop her castle walls, surveying the kingdom below with a mix of pride and sadness. She knew that the coming war would be brutal, but she was determined to protect her people at all costs.",
"The necromancer's tower loomed in the distance, its dark spires piercing the sky. As the adventurers approached, they could feel the chill of death emanating from within",
"The ranger moved through the forest like a shadow, his senses attuned to every sound and movement around him. He knew that danger lurked behind every tree, but he was ready for whatever came his way.",
"The paladin knelt before the altar, his hands clasped in prayer. He knew that his faith would be tested in the days ahead, but he was ready to face whatever trials lay in store for him.",
"The druid communed with the spirits of nature, his mind merging with the trees, the animals, and the very earth itself. He knew that his power came with a great responsibility, and he was determined to use it for the greater good.",
'The sword glinted in the dim light, its edges keen and deadly. As the adventurer reached for it, he couldn\'t help but feel a surge of excitement mixed with fear. This was no ordinary blade.',
'The dragon\'s roar shook the ground beneath their feet, and the brave knight stood tall, his sword at the ready. He knew that this would be the battle of his life, but he was determined to emerge victorious.',
'The wizard\'s laboratory was a sight to behold, filled with bubbling cauldrons, ancient tomes, and strange artifacts from distant lands. As the apprentice gazed around in wonder, she knew that she was about to embark on a journey unlike any other.',
'The tavern was packed with rowdy patrons, their voices raised in song and laughter. The bard took center stage, strumming his lute and launching into a tale of adventure and heroism that had the crowd hanging on his every word.',
'The thief crept through the shadows, his eyes scanning the room for any sign of danger. He knew that one false move could mean the difference between success and failure, and he was determined to come out on top.',
'The elf queen stood atop her castle walls, surveying the kingdom below with a mix of pride and sadness. She knew that the coming war would be brutal, but she was determined to protect her people at all costs.',
'The necromancer\'s tower loomed in the distance, its dark spires piercing the sky. As the adventurers approached, they could feel the chill of death emanating from within',
'The ranger moved through the forest like a shadow, his senses attuned to every sound and movement around him. He knew that danger lurked behind every tree, but he was ready for whatever came his way.',
'The paladin knelt before the altar, his hands clasped in prayer. He knew that his faith would be tested in the days ahead, but he was ready to face whatever trials lay in store for him.',
'The druid communed with the spirits of nature, his mind merging with the trees, the animals, and the very earth itself. He knew that his power came with a great responsibility, and he was determined to use it for the greater good.',
];
const authors = [
"Unknown",
"James Wyatt",
"Eolande Blackwood",
"Ragnar Ironheart",
"Lyra Nightshade",
"Valtorius Darkstar",
"Isadora Fireheart",
"Theron Shadowbane",
"Lirien Starweaver",
"Drogathar Bonecrusher",
"Kaelen Frostblade",
'Unknown',
'James Wyatt',
'Eolande Blackwood',
'Ragnar Ironheart',
'Lyra Nightshade',
'Valtorius Darkstar',
'Isadora Fireheart',
'Theron Shadowbane',
'Lirien Starweaver',
'Drogathar Bonecrusher',
'Kaelen Frostblade',
];
const books = [
"The Blade of Destiny",
"Dragonfire and Steel",
"The Bard's Tale",
"Darkness Rising",
"The Sacred Quest",
"Shadows in the Forest",
"The Starweaver Chronicles",
"Beneath the Bones",
"Moonlit Magic",
"Frost and Fury",
'The Blade of Destiny',
'Dragonfire and Steel',
'The Bard\'s Tale',
'Darkness Rising',
'The Sacred Quest',
'Shadows in the Forest',
'The Starweaver Chronicles',
'Beneath the Bones',
'Moonlit Magic',
'Frost and Fury',
];
module.exports = () => {
return `
module.exports = ()=>{
return `
{{quote
${_.sample(quotes)}

View File

@@ -2,77 +2,68 @@ const _ = require('lodash');
const dedent = require('dedent-tabs').default;
const getTOC = (pages)=>{
const add1 = (title, page)=>{
res.push({
title : title,
page : page + 1,
children : []
});
};
const add2 = (title, page)=>{
if(!_.last(res)) add1(null, page);
_.last(res).children.push({
title : title,
page : page + 1,
children : []
});
};
const add3 = (title, page)=>{
if(!_.last(res)) add1(null, page);
if(!_.last(_.last(res).children)) add2(null, page);
_.last(_.last(res).children).children.push({
title : title,
page : page + 1,
children : []
});
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 : []
});
}
recursiveAdd(title, page, targetDepth, _.last(child).children, curDepth+1,);
}
};
const res = [];
_.each(pages, (page, pageNum)=>{
if(!page.includes("{{frontCover}}") && !page.includes("{{insideCover}}") && !page.includes("{{partCover}}") && !page.includes("{{backCover}}")) {
const lines = page.split('\n');
_.each(lines, (line)=>{
if(_.startsWith(line, '# ')){
const title = line.replace('# ', '');
add1(title, pageNum);
}
if(_.startsWith(line, '## ')){
const title = line.replace('## ', '');
add2(title, pageNum);
}
if(_.startsWith(line, '### ')){
const title = line.replace('### ', '');
add3(title, pageNum);
}
});
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'];
_.each(headings, (heading)=>{
const onPage = parseInt(heading.closest('.page').id?.replace(/^p/, ''));
const ToCExclude = getComputedStyle(heading).getPropertyValue('--TOC');
if(ToCExclude != 'exclude') {
recursiveAdd(heading.innerText.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;
};
module.exports = function(props){
const pages = props.brew.text.split('\\page');
const TOC = getTOC(pages);
const markdown = _.reduce(TOC, (r, g1, idx1)=>{
if(g1.title !== null) {
r.push(`- ### [{{ ${g1.title}}}{{ ${g1.page}}}](#p${g1.page})`);
}
if(g1.children.length){
_.each(g1.children, (g2, idx2)=>{
if(g2.title !== null) {
r.push(` - #### [{{ ${g2.title}}}{{ ${g2.page}}}](#p${g2.page})`);
}
if(g2.children.length){
_.each(g2.children, (g3, idx3)=>{
if(g2.title !== null) {
r.push(` - [{{ ${g3.title}}}{{ ${g3.page}}}](#p${g3.page})`);
} else { // Don't over-indent if no level-2 parent entry
r.push(` - [{{ ${g3.title}}}{{ ${g3.page}}}](#p${g3.page})`);
}
});
}
});
}
r.push(ToCIterate(g1).join('\n'));
return r;
}, []).join('\n');

View File

@@ -1,6 +1,4 @@
@import (less) './themes/assets/assets.less';
@import (less) './themes/fonts/icon fonts/font-icons.less';
@import (less) './themes/fonts/icon fonts/diceFont.less';
:root {
//Colors
@@ -356,6 +354,11 @@
}
}
.bonus {
float: right;
padding-right: 0.5em;
}
// Monster Ability table
hr + table:first-of-type {
margin : 0;
@@ -543,10 +546,8 @@
color : white;
text-shadow : unset;
text-transform : uppercase;
filter : drop-shadow(0 0 1.5px black) drop-shadow(0 0 0 black)
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black)
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black)
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black);
-webkit-text-stroke: 0.2cm black;
paint-order:stroke;
}
h2 {
font-family : 'NodestoCapsCondensed';
@@ -554,10 +555,8 @@
font-weight : normal;
color : white;
letter-spacing : 0.1cm;
filter : drop-shadow(0 0 1px black) drop-shadow(0 0 0 black)
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black)
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black)
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black);
-webkit-text-stroke: 0.14cm black;
paint-order:stroke;
}
hr {
position : relative;
@@ -603,10 +602,8 @@
font-size : 0.496cm;
color : white;
text-align : center;
filter : drop-shadow(0 0 0.7px black) drop-shadow(0 0 0 black)
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black)
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black)
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black);
-webkit-text-stroke: 0.1cm black;
paint-order:stroke;
}
.logo {
position : absolute;
@@ -789,6 +786,39 @@
// *****************************
// * TABLE OF CONTENTS
// *****************************/
// Default Exclusions
// Anything not exlcuded is included, default Headers are H1, H2, and H3.
h4,
h5,
h6,
.page:has(.frontCover),
.page:has(.backCover),
.page:has(.insideCover),
.monster,
.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; }
.tocIncludeH1 h1 {--TOC: include; }
.tocIncludeH2 h2 {--TOC: include; }
.tocIncludeH3 h3 {--TOC: include; }
.tocIncludeH4 h4 {--TOC: include; }
.tocIncludeH5 h5 {--TOC: include; }
.tocIncludeH6 h6 {--TOC: include; }
.page:has(.partCover) {
--TOC: exclude;
& h1 {
--TOC: include;
}
}
.page {
&:has(.toc)::after { display : none; }
.toc {

View File

@@ -307,8 +307,8 @@ module.exports = [
/**************** FONTS *************/
{
groupName : 'Fonts',
icon : 'fas fa-keyboard',
view : 'text',
icon : 'fas fa-keyboard',
view : 'text',
snippets : [
{
name : 'Open Sans',
@@ -341,59 +341,59 @@ module.exports = [
gen : dedent`{{font-family:MrEavesRemake Dummy Text}}`
},
{
name: 'Solbera Imitation',
icon: 'font SolberaImitationRemake',
gen: dedent`{{font-family:SolberaImitationRemake Dummy Text}}`
name : 'Solbera Imitation',
icon : 'font SolberaImitationRemake',
gen : dedent`{{font-family:SolberaImitationRemake Dummy Text}}`
},
{
name: 'Scaly Sans Small Caps',
icon: 'font ScalySansSmallCapsRemake',
gen: dedent`{{font-family:ScalySansSmallCapsRemake Dummy Text}}`
name : 'Scaly Sans Small Caps',
icon : 'font ScalySansSmallCapsRemake',
gen : dedent`{{font-family:ScalySansSmallCapsRemake Dummy Text}}`
},
{
name: 'Walter Turncoat',
icon: 'font WalterTurncoat',
gen: dedent`{{font-family:WalterTurncoat Dummy Text}}`
name : 'Walter Turncoat',
icon : 'font WalterTurncoat',
gen : dedent`{{font-family:WalterTurncoat Dummy Text}}`
},
{
name: 'Lato',
icon: 'font Lato',
gen: dedent`{{font-family:Lato Dummy Text}}`
name : 'Lato',
icon : 'font Lato',
gen : dedent`{{font-family:Lato Dummy Text}}`
},
{
name: 'Courier',
icon: 'font Courier',
gen: dedent`{{font-family:Courier Dummy Text}}`
name : 'Courier',
icon : 'font Courier',
gen : dedent`{{font-family:Courier Dummy Text}}`
},
{
name: 'Nodesto Caps Condensed',
icon: 'font NodestoCapsCondensed',
gen: dedent`{{font-family:NodestoCapsCondensed Dummy Text}}`
name : 'Nodesto Caps Condensed',
icon : 'font NodestoCapsCondensed',
gen : dedent`{{font-family:NodestoCapsCondensed Dummy Text}}`
},
{
name: 'Overpass',
icon: 'font Overpass',
gen: dedent`{{font-family:Overpass Dummy Text}}`
name : 'Overpass',
icon : 'font Overpass',
gen : dedent`{{font-family:Overpass Dummy Text}}`
},
{
name: 'Davek',
icon: 'font Davek',
gen: dedent`{{font-family:Davek Dummy Text}}`
name : 'Davek',
icon : 'font Davek',
gen : dedent`{{font-family:Davek Dummy Text}}`
},
{
name: 'Iokharic',
icon: 'font Iokharic',
gen: dedent`{{font-family:Iokharic Dummy Text}}`
name : 'Iokharic',
icon : 'font Iokharic',
gen : dedent`{{font-family:Iokharic Dummy Text}}`
},
{
name: 'Rellanic',
icon: 'font Rellanic',
gen: dedent`{{font-family:Rellanic Dummy Text}}`
name : 'Rellanic',
icon : 'font Rellanic',
gen : dedent`{{font-family:Rellanic Dummy Text}}`
},
{
name: 'Times New Roman',
icon: 'font TimesNewRoman',
gen: dedent`{{font-family:"Times New Roman" Dummy Text}}`
name : 'Times New Roman',
icon : 'font TimesNewRoman',
gen : dedent`{{font-family:"Times New Roman" Dummy Text}}`
}
]
},

View File

@@ -1,6 +1,9 @@
@import (less) './themes/fonts/5e/fonts.less';
@import (less) './themes/assets/assets.less';
@import (less) './themes/fonts/icon fonts/diceFont.less';
@import (less) './themes/fonts/iconFonts/elderberryInn.less';
@import (less) './themes/fonts/iconFonts/diceFont.less';
@import (less) './themes/fonts/iconFonts/gameIcons.less';
@import (less) './themes/fonts/iconFonts/fontAwesome.less';
:root {
//Colors

View File

@@ -58,7 +58,7 @@
background-color: rgba(35,153,153,0.5);
}
.pageLine {
background-color: rgba(255,255,255,0.75);
background-color: rgba(255,255,255,0.5);
& ~ pre.CodeMirror-line {
color: black;
}
@@ -85,4 +85,4 @@
// Future styling for themes with light backgrounds
--dummyVar: 'currently unused';
}
}
}

View File

@@ -74,8 +74,9 @@
@font-face {
font-family: SolberaImitationRemake; //Tweaked 5e version
src: url('../../../fonts/5e/Solbera Imitation Tweak.woff2');
font-weight: normal;
font-weight: 100 1000;
font-style: normal;
font-style: italic;
}
/* Cover Page */

View File

@@ -1,224 +0,0 @@
/* Icon Font: Elderberry Inn */
@font-face {
font-family : 'Elderberry-Inn';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/icon fonts/Elderberry-Inn-Icons.woff2');
}
.page {
span.ei {
display : inline-block;
margin-right : 3px;
font-family : 'Elderberry-Inn';
line-height : 1;
vertical-align : baseline;
-moz-osx-font-smoothing : grayscale;
-webkit-font-smoothing : antialiased;
text-rendering : auto;
&.book::before { content : '\E900'; }
&.screen::before { content : '\E901'; }
/* Spell levels */
&.spell-0::before { content : '\E902'; }
&.spell-1::before { content : '\E903'; }
&.spell-2::before { content : '\E904'; }
&.spell-3::before { content : '\E905'; }
&.spell-4::before { content : '\E906'; }
&.spell-5::before { content : '\E907'; }
&.spell-6::before { content : '\E908'; }
&.spell-7::before { content : '\E909'; }
&.spell-8::before { content : '\E90A'; }
&.spell-9::before { content : '\E90B'; }
/* Damage types */
&.acid::before { content : '\E90C'; }
&.bludgeoning::before { content : '\E90D'; }
&.cold::before { content : '\E90E'; }
&.fire::before { content : '\E90F'; }
&.force::before { content : '\E910'; }
&.lightning::before { content : '\E911'; }
&.necrotic::before { content : '\E912'; }
&.piercing::before { content : '\E914'; }
&.poison::before { content : '\E913'; }
&.psychic::before { content : '\E915'; }
&.radiant::before { content : '\E916'; }
&.slashing::before { content : '\E917'; }
&.thunder::before { content : '\E918'; }
/* DnD Conditions */
&.blinded::before { content : '\E919'; }
&.charmed::before { content : '\E91A'; }
&.deafened::before { content : '\E91B'; }
&.exhaust-1::before { content : '\E91C'; }
&.exhaust-2::before { content : '\E91D'; }
&.exhaust-3::before { content : '\E91E'; }
&.exhaust-4::before { content : '\E91F'; }
&.exhaust-5::before { content : '\E920'; }
&.exhaust-6::before { content : '\E921'; }
&.frightened::before { content : '\E922'; }
&.grappled::before { content : '\E923'; }
&.incapacitated::before { content : '\E924'; }
&.invisible::before { content : '\E926'; }
&.paralyzed::before { content : '\E927'; }
&.petrified::before { content : '\E928'; }
&.poisoned::before { content : '\E929'; }
&.prone::before { content : '\E92A'; }
&.restrained::before { content : '\E92B'; }
&.stunned::before { content : '\E92C'; }
&.unconscious::before { content : '\E925'; }
/* Character Classes and Features */
&.barbarian-rage::before { content : '\E92D'; }
&.barbarian-reckless-attack::before { content : '\E92E'; }
&.bardic-inspiration::before { content : '\E92F'; }
&.cleric-channel-divinity::before { content : '\E930'; }
&.druid-wild-shape::before { content : '\E931'; }
&.fighter-action-surge::before { content : '\E932'; }
&.fighter-second-wind::before { content : '\E933'; }
&.monk-flurry-blows::before { content : '\E934'; }
&.monk-patient-defense::before { content : '\E935'; }
&.monk-step-of-the-wind::before { content : '\E936'; }
&.monk-step-of-the-wind-2::before { content : '\E937'; }
&.monk-step-of-the-wind-3::before { content : '\E938'; }
&.monk-stunning-strike::before { content : '\E939'; }
&.monk-stunning-strike-2::before { content : '\E939'; }
&.paladin-divine-smite::before { content : '\E93B'; }
&.paladin-lay-on-hands::before { content : '\E93C'; }
&.barbarian-abilities::before { content : '\E93D'; }
&.barbarian::before { content : '\E93E'; }
&.bard-abilities::before { content : '\E93F'; }
&.bard::before { content : '\E940'; }
&.cleric-abilities::before { content : '\E941'; }
&.cleric::before { content : '\E942'; }
&.druid-abilities::before { content : '\E943'; }
&.druid::before { content : '\E944'; }
&.fighter-abilities::before { content : '\E945'; }
&.fighter::before { content : '\E946'; }
&.monk-abilities::before { content : '\E947'; }
&.monk::before { content : '\E948'; }
&.paladin-abilities::before { content : '\E949'; }
&.paladin::before { content : '\E94A'; }
&.ranger-abilities::before { content : '\E94B'; }
&.ranger::before { content : '\E94C'; }
&.rogue-abilities::before { content : '\E94D'; }
&.rogue::before { content : '\E94E'; }
&.sorcerer-abilities::before { content : '\E94F'; }
&.sorcerer::before { content : '\E950'; }
&.warlock-abilities::before { content : '\E951'; }
&.warlock::before { content : '\E952'; }
&.wizard-abilities::before { content : '\E953'; }
&.wizard::before { content : '\E954'; }
/* Types of actions */
&.movement::before { content : '\E955'; }
&.action::before { content : '\E956'; }
&.bonus-action::before { content : '\E957'; }
&.reaction::before { content : '\E958'; }
/* SRD Spells */
&.acid-arrow::before { content : '\E959'; }
&.action-1::before { content : '\E95A'; }
&.alter-self::before { content : '\E95B'; }
&.alter-self-2::before { content : '\E95C'; }
&.animal-friendship::before { content : '\E95E'; }
&.animate-dead::before { content : '\E95F'; }
&.animate-objects::before { content : '\E960'; }
&.animate-objects-2::before { content : '\E961'; }
&.bane::before { content : '\E962'; }
&.bless::before { content : '\E963'; }
&.blur::before { content : '\E964'; }
&.bonus::before { content : '\E965'; }
&.branding-smite::before { content : '\E966'; }
&.burning-hands::before { content : '\E967'; }
&.charm-person::before { content : '\E968'; }
&.chill-touch::before { content : '\E969'; }
&.cloudkill::before { content : '\E96A'; }
&.comprehend-languages::before { content : '\E96B'; }
&.cone-of-cold::before { content : '\E96C'; }
&.conjure-elemental::before { content : '\E96D'; }
&.conjure-minor-elemental::before { content : '\E96E'; }
&.control-water::before { content : '\E96F'; }
&.counterspell::before { content : '\E970'; }
&.cure-wounds::before { content : '\E971'; }
&.dancing-lights::before { content : '\E972'; }
&.darkness::before { content : '\E973'; }
&.detect-magic::before { content : '\E974'; }
&.disguise-self::before { content : '\E975'; }
&.disintegrate::before { content : '\E976'; }
&.dispel-evil-and-good::before { content : '\E977'; }
&.dispel-magic::before { content : '\E978'; }
&.dominate-monster::before { content : '\E979'; }
&.dominate-person::before { content : '\E97A'; }
&.eldritch-blast::before { content : '\E97B'; }
&.enlarge-reduce::before { content : '\E97C'; }
&.entangle::before { content : '\E97D'; }
&.faerie-fire::before { content : '\E97E'; }
&.faerie-fire2::before { content : '\E97F'; }
&.feather-fall::before { content : '\E980'; }
&.find-familiar::before { content : '\E981'; }
&.finger-of-death::before { content : '\E982'; }
&.fireball::before { content : '\E983'; }
&.floating-disk::before { content : '\E984'; }
&.fly::before { content : '\E985'; }
&.fog-cloud::before { content : '\E986'; }
&.gaseous-form::before { content : '\E987'; }
&.gaseous-form2::before { content : '\E988'; }
&.gentle-repose::before { content : '\E989'; }
&.gentle-repose2::before { content : '\E98A'; }
&.globe-of-invulnerability::before { content : '\E98B'; }
&.guiding-bolt::before { content : '\E98C'; }
&.healing-word::before { content : '\E98D'; }
&.heat-metal::before { content : '\E98E'; }
&.hellish-rebuke::before { content : '\E98F'; }
&.heroes-feast::before { content : '\E990'; }
&.heroism::before { content : '\E991'; }
&.hideous-laughter::before { content : '\E992'; }
&.identify::before { content : '\E993'; }
&.illusory-script::before { content : '\E994'; }
&.inflict-wounds::before { content : '\E995'; }
&.light::before { content : '\E996'; }
&.longstrider::before { content : '\E997'; }
&.mage-armor::before { content : '\E998'; }
&.mage-hand::before { content : '\E999'; }
&.magic-missile::before { content : '\E99A'; }
&.mass-cure-wounds::before { content : '\E99B'; }
&.mass-healing-word::before { content : '\E99C'; }
&.Mending::before { content : '\E99D'; }
&.message::before { content : '\E99E'; }
&.Minor-illusion::before { content : '\E99F'; }
&.movement1::before { content : '\E9A0'; }
&.polymorph::before { content : '\E9A1'; }
&.power-word-kill::before { content : '\E9A2'; }
&.power-word-stun::before { content : '\E9A3'; }
&.prayer-of-healing::before { content : '\E9A4'; }
&.prestidigitation::before { content : '\E9A5'; }
&.protection-from-evil-and-good::before { content : '\E9A6'; }
&.raise-read::before { content : '\E9A7'; }
&.raise-read2::before { content : '\E9A8'; }
&.reaction1::before { content : '\E9A9'; }
&.resurrection::before { content : '\E9AA'; }
&.resurrection2::before { content : '\E9AB'; }
&.revivify::before { content : '\E9AC'; }
&.revivify2::before { content : '\E9AD'; }
&.sacred-flame::before { content : '\E9AE'; }
&.sanctuary::before { content : '\E9AF'; }
&.scorching-ray::before { content : '\E9B0'; }
&.sending::before { content : '\E9B1'; }
&.shatter::before { content : '\E9B2'; }
&.shield::before { content : '\E9B3'; }
&.silent-image::before { content : '\E9B4'; }
&.sleep::before { content : '\E9B5'; }
&.speak-with-animals::before { content : '\E9B6'; }
&.telekinesis::before { content : '\E9B7'; }
&.true-strike::before { content : '\E9B8'; }
&.vicious-mockery::before { content : '\E9B9'; }
&.wall-of-fire::before { content : '\E9BA'; }
&.wall-of-force::before { content : '\E9BB'; }
&.wall-of-ice::before { content : '\E9BC'; }
&.wall-of-stone::before { content : '\E9BD'; }
&.wall-of-thorns::before { content : '\E9BE'; }
&.wish::before { content : '\E9BF'; }
}
}

View File

@@ -0,0 +1,96 @@
const diceFont = {
'df_f' : 'df F',
'df_f_minus' : 'df F-minus',
'df_f_plus' : 'df F-plus',
'df_f_zero' : 'df F-zero',
'df_d10' : 'df d10',
'df_d10_1' : 'df d10-1',
'df_d10_10' : 'df d10-10',
'df_d10_2' : 'df d10-2',
'df_d10_3' : 'df d10-3',
'df_d10_4' : 'df d10-4',
'df_d10_5' : 'df d10-5',
'df_d10_6' : 'df d10-6',
'df_d10_7' : 'df d10-7',
'df_d10_8' : 'df d10-8',
'df_d10_9' : 'df d10-9',
'df_d12' : 'df d12',
'df_d12_1' : 'df d12-1',
'df_d12_10' : 'df d12-10',
'df_d12_11' : 'df d12-11',
'df_d12_12' : 'df d12-12',
'df_d12_2' : 'df d12-2',
'df_d12_3' : 'df d12-3',
'df_d12_4' : 'df d12-4',
'df_d12_5' : 'df d12-5',
'df_d12_6' : 'df d12-6',
'df_d12_7' : 'df d12-7',
'df_d12_8' : 'df d12-8',
'df_d12_9' : 'df d12-9',
'df_d2' : 'df d2',
'df_d2_1' : 'df d2-1',
'df_d2_2' : 'df d2-2',
'df_d20' : 'df d20',
'df_d20_1' : 'df d20-1',
'df_d20_10' : 'df d20-10',
'df_d20_11' : 'df d20-11',
'df_d20_12' : 'df d20-12',
'df_d20_13' : 'df d20-13',
'df_d20_14' : 'df d20-14',
'df_d20_15' : 'df d20-15',
'df_d20_16' : 'df d20-16',
'df_d20_17' : 'df d20-17',
'df_d20_18' : 'df d20-18',
'df_d20_19' : 'df d20-19',
'df_d20_2' : 'df d20-2',
'df_d20_20' : 'df d20-20',
'df_d20_3' : 'df d20-3',
'df_d20_4' : 'df d20-4',
'df_d20_5' : 'df d20-5',
'df_d20_6' : 'df d20-6',
'df_d20_7' : 'df d20-7',
'df_d20_8' : 'df d20-8',
'df_d20_9' : 'df d20-9',
'df_d4' : 'df d4',
'df_d4_1' : 'df d4-1',
'df_d4_2' : 'df d4-2',
'df_d4_3' : 'df d4-3',
'df_d4_4' : 'df d4-4',
'df_d6' : 'df d6',
'df_d6_1' : 'df d6-1',
'df_d6_2' : 'df d6-2',
'df_d6_3' : 'df d6-3',
'df_d6_4' : 'df d6-4',
'df_d6_5' : 'df d6-5',
'df_d6_6' : 'df d6-6',
'df_d8' : 'df d8',
'df_d8_1' : 'df d8-1',
'df_d8_2' : 'df d8-2',
'df_d8_3' : 'df d8-3',
'df_d8_4' : 'df d8-4',
'df_d8_5' : 'df d8-5',
'df_d8_6' : 'df d8-6',
'df_d8_7' : 'df d8-7',
'df_d8_8' : 'df d8-8',
'df_dot_d6' : 'df dot-d6',
'df_dot_d6_1' : 'df dot-d6-1',
'df_dot_d6_2' : 'df dot-d6-2',
'df_dot_d6_3' : 'df dot-d6-3',
'df_dot_d6_4' : 'df dot-d6-4',
'df_dot_d6_5' : 'df dot-d6-5',
'df_dot_d6_6' : 'df dot-d6-6',
'df_small_dot_d6_1' : 'df small-dot-d6-1',
'df_small_dot_d6_2' : 'df small-dot-d6-2',
'df_small_dot_d6_3' : 'df small-dot-d6-3',
'df_small_dot_d6_4' : 'df small-dot-d6-4',
'df_small_dot_d6_5' : 'df small-dot-d6-5',
'df_small_dot_d6_6' : 'df small-dot-d6-6',
'df_solid_small_dot_d6_1' : 'df solid-small-dot-d6-1',
'df_solid_small_dot_d6_2' : 'df solid-small-dot-d6-2',
'df_solid_small_dot_d6_3' : 'df solid-small-dot-d6-3',
'df_solid_small_dot_d6_4' : 'df solid-small-dot-d6-4',
'df_solid_small_dot_d6_5' : 'df solid-small-dot-d6-5',
'df_solid_small_dot_d6_6' : 'df solid-small-dot-d6-6'
};
module.exports = diceFont;

View File

@@ -3,11 +3,11 @@
font-family : 'DiceFont';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/icon fonts/diceFont.woff2');
src : url('../../../fonts/iconFonts/diceFont.woff2');
}
.df {
display : inline-block;
display : inline;
font-family : 'DiceFont';
font-style : normal;
font-weight : normal;
@@ -16,8 +16,11 @@
text-decoration : inherit;
text-transform : none;
text-rendering : optimizeLegibility;
-moz-osx-font-smoothing : grayscale;
/* Better Font Rendering =========== */
-webkit-font-smoothing : antialiased;
-moz-osx-font-smoothing : grayscale;
&.F::before { content : '\f190'; }
&.F-minus::before { content : '\f191'; }
&.F-plus::before { content : '\f192'; }

View File

@@ -0,0 +1,209 @@
const elderberryInn = {
'ei_book' : 'ei book',
'ei_screen' : 'ei screen',
/* Spell levels */
'ei_spell_0' : 'ei spell-0',
'ei_spell_1' : 'ei spell-1',
'ei_spell_2' : 'ei spell-2',
'ei_spell_3' : 'ei spell-3',
'ei_spell_4' : 'ei spell-4',
'ei_spell_5' : 'ei spell-5',
'ei_spell_6' : 'ei spell-6',
'ei_spell_7' : 'ei spell-7',
'ei_spell_8' : 'ei spell-8',
'ei_spell_9' : 'ei spell-9',
/* Damage types */
'ei_acid' : 'ei acid',
'ei_bludgeoning' : 'ei bludgeoning',
'ei_cold' : 'ei cold',
'ei_fire' : 'ei fire',
'ei_force' : 'ei force',
'ei_lightning' : 'ei lightning',
'ei_necrotic' : 'ei necrotic',
'ei_piercing' : 'ei piercing',
'ei_poison' : 'ei poison',
'ei_psychic' : 'ei psychic',
'ei_radiant' : 'ei radiant',
'ei_slashing' : 'ei slashing',
'ei_thunder' : 'ei thunder',
/* DnD Conditions */
'ei_blinded' : 'ei blinded',
'ei_charmed' : 'ei charmed',
'ei_deafened' : 'ei deafened',
'ei_exhaust1' : 'ei exhaust-1',
'ei_blinded' : 'ei blinded',
'ei_exhaust2' : 'ei exhaust-2',
'ei_exhaust3' : 'ei exhaust-3',
'ei_exhaust4' : 'ei exhaust-4',
'ei_exhaust5' : 'ei exhaust-5',
'ei_exhaust6' : 'ei exhaust-6',
'ei_frightened' : 'ei frightened',
'ei_grappled' : 'ei grappled',
'ei_incapacitated' : 'ei incapacitated',
'ei_invisible' : 'ei invisible',
'ei_paralyzed' : 'ei paralyzed',
'ei_petrified' : 'ei petrified',
'ei_poisoned' : 'ei poisoned',
'ei_prone' : 'ei prone',
'ei_restrained' : 'ei restrained',
'ei_stunned' : 'ei stunned',
'ei_unconscious' : 'ei unconscious',
/* Character Classes and Features */
'ei_barbarian_rage' : 'ei barbarian-rage',
'ei_barbarian_reckless_attack' : 'ei barbarian-reckless-attack',
'ei_bardic_inspiration' : 'ei bardic-inspiration',
'ei_cleric_channel_divinity' : 'ei cleric-channel-divinity',
'ei_druid_wild_shape' : 'ei druid-wild-shape',
'ei_fighter_action_surge' : 'ei fighter-action-surge',
'ei_fighter_second_wind' : 'ei fighter-second-wind',
'ei_monk_flurry_blows' : 'ei monk-flurry-blows',
'ei_monk_patient_defense' : 'ei monk-patient-defense',
'ei_monk_step_of_the_wind' : 'ei monk-step-of-the-wind',
'ei_monk_step_of_the_wind2' : 'ei monk-step-of-the-wind-2',
'ei_monk_step_of_the_wind3' : 'ei monk-step-of-the-wind-3',
'ei_monk_stunning_strike' : 'ei monk-stunning-strike',
'ei_monk_stunning_strike2' : 'ei monk-stunning-strike-2',
'ei_paladin_divine_smite' : 'ei paladin-divine-smite',
'ei_paladin_lay_on_hands' : 'ei paladin-lay-on-hands',
'ei_barbarian_abilities' : 'ei barbarian-abilities',
'ei_barbarian' : 'ei barbarian',
'ei_bard_abilities' : 'ei bard-abilities',
'ei_bard' : 'ei bard',
'ei_cleric_abilities' : 'ei cleric-abilities',
'ei_cleric' : 'ei cleric',
'ei_druid_abilities' : 'ei druid-abilities',
'ei_druid' : 'ei druid',
'ei_fighter_abilities' : 'ei fighter-abilities',
'ei_fighter' : 'ei fighter',
'ei_monk_abilities' : 'ei monk-abilities',
'ei_monk' : 'ei monk',
'ei_paladin_abilities' : 'ei paladin-abilities',
'ei_paladin' : 'ei paladin',
'ei_ranger_abilities' : 'ei ranger-abilities',
'ei_ranger' : 'ei ranger',
'ei_rogue_abilities' : 'ei rogue-abilities',
'ei_rogue' : 'ei rogue',
'ei_sorcerer_abilities' : 'ei sorcerer-abilities',
'ei_sorcerer' : 'ei sorcerer',
'ei_warlock_abilities' : 'ei warlock-abilities',
'ei_warlock' : 'ei warlock',
'ei_wizard_abilities' : 'ei wizard-abilities',
'ei_wizard' : 'ei wizard',
/* Types of actions */
'ei_movement' : 'ei movement',
'ei_action' : 'ei action',
'ei_bonus_action' : 'ei bonus-action',
'ei_reaction' : 'ei reaction',
/* SRD Spells */
'ei_acid_arrow' : 'ei acid-arrow',
'ei_action1' : 'ei action-1',
'ei_alter_self' : 'ei alter-self',
'ei_alter_self2' : 'ei alter-self-2',
'ei_magic_beans' : 'ei magic-beans',
'ei_animal_friendship' : 'ei animal-friendship',
'ei_animate_dead' : 'ei animate-dead',
'ei_animate_objects' : 'ei animate-objects',
'ei_animate_objects2' : 'ei animate-objects-2',
'ei_bane' : 'ei bane',
'ei_bless' : 'ei bless',
'ei_blur' : 'ei blur',
'ei_bonus' : 'ei bonus',
'ei_branding_smite' : 'ei branding-smite',
'ei_burning_hands' : 'ei burning-hands',
'ei_charm_person' : 'ei charm-person',
'ei_chill_touch' : 'ei chill-touch',
'ei_cloudkill' : 'ei cloudkill',
'ei_comprehend_languages' : 'ei comprehend-languages',
'ei_cone_of_cold' : 'ei cone-of-cold',
'ei_conjure_elemental' : 'ei conjure-elemental',
'ei_conjure_minor_elemental' : 'ei conjure-minor-elemental',
'ei_control_water' : 'ei control-water',
'ei_counterspell' : 'ei counterspell',
'ei_cure_wounds' : 'ei cure-wounds',
'ei_dancing_lights' : 'ei dancing-lights',
'ei_darkness' : 'ei darkness',
'ei_detect_magic' : 'ei detect-magic',
'ei_disguise_self' : 'ei disguise-self',
'ei_disintegrate' : 'ei disintegrate',
'ei_dispel_evil_and_good' : 'ei dispel-evil-and-good',
'ei_dispel_magic' : 'ei dispel-magic',
'ei_dominate_monster' : 'ei dominate-monster',
'ei_dominate_person' : 'ei dominate-person',
'ei_eldritch_blast' : 'ei eldritch-blast',
'ei_enlarge_reduce' : 'ei enlarge-reduce',
'ei_entangle' : 'ei entangle',
'ei_faerie_fire' : 'ei faerie-fire',
'ei_faerie_fire2' : 'ei faerie-fire2',
'ei_feather_fall' : 'ei feather-fall',
'ei_find_familiar' : 'ei find-familiar',
'ei_finger_of_death' : 'ei finger-of-death',
'ei_fireball' : 'ei fireball',
'ei_floating_disk' : 'ei floating-disk',
'ei_fly' : 'ei fly',
'ei_fog_cloud' : 'ei fog-cloud',
'ei_gaseous_form' : 'ei gaseous-form',
'ei_gaseous_form2' : 'ei gaseous-form2',
'ei_gentle_repose' : 'ei gentle-repose',
'ei_gentle_repose2' : 'ei gentle-repose2',
'ei_globe_of_invulnerability' : 'ei globe-of-invulnerability',
'ei_guiding_bolt' : 'ei guiding-bolt',
'ei_healing_word' : 'ei healing-word',
'ei_heat_metal' : 'ei heat-metal',
'ei_hellish_rebuke' : 'ei hellish-rebuke',
'ei_heroes_feast' : 'ei heroes-feast',
'ei_heroism' : 'ei heroism',
'ei_hideous_laughter' : 'ei hideous-laughter',
'ei_identify' : 'ei identify',
'ei_illusory_script' : 'ei illusory-script',
'ei_inflict_wounds' : 'ei inflict-wounds',
'ei_light' : 'ei light',
'ei_longstrider' : 'ei longstrider',
'ei_mage_armor' : 'ei mage-armor',
'ei_mage_hand' : 'ei mage-hand',
'ei_magic_missile' : 'ei magic-missile',
'ei_mass_cure_wounds' : 'ei mass-cure-wounds',
'ei_mass_healing_word' : 'ei mass-healing-word',
'ei_mending' : 'ei _mending',
'ei_message' : 'ei message',
'ei_minor_illusion' : 'ei _minor-illusion',
'ei_movement1' : 'ei movement1',
'ei_polymorph' : 'ei polymorph',
'ei_power_word_kill' : 'ei power-word-kill',
'ei_power_word_stun' : 'ei power-word-stun',
'ei_prayer_of_healing' : 'ei prayer-of-healing',
'ei_prestidigitation' : 'ei prestidigitation',
'ei_protection_from_evil_and_good' : 'ei protection-from-evil-and-good',
'ei_raise_dead' : 'ei raise-dead',
'ei_raise_dead2' : 'ei raise-dead2',
'ei_reaction1' : 'ei reaction1',
'ei_resurrection' : 'ei resurrection',
'ei_resurrection2' : 'ei resurrection2',
'ei_revivify' : 'ei revivify',
'ei_revivify2' : 'ei revivify2',
'ei_sacred_flame' : 'ei sacred-flame',
'ei_sanctuary' : 'ei sanctuary',
'ei_scorching_ray' : 'ei scorching-ray',
'ei_sending' : 'ei sending',
'ei_shatter' : 'ei shatter',
'ei_shield' : 'ei shield',
'ei_silent_image' : 'ei silent-image',
'ei_sleep' : 'ei sleep',
'ei_speak_with_animals' : 'ei speak-with-animals',
'ei_telekinesis' : 'ei telekinesis',
'ei_true_strike' : 'ei true-strike',
'ei_vicious_mockery' : 'ei vicious-mockery',
'ei_wall_of_fire' : 'ei wall-of-fire',
'ei_wall_of_force' : 'ei wall-of-force',
'ei_wall_of_ice' : 'ei wall-of-ice',
'ei_wall_of_stone' : 'ei wall-of-stone',
'ei_wall_of_thorns' : 'ei wall-of-thorns',
'ei_wish' : 'ei wish'
};
module.exports = elderberryInn;

View File

@@ -0,0 +1,225 @@
/* Icon Font: Elderberry Inn */
@font-face {
font-family : 'Elderberry-Inn';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/iconFonts/elderberryInn.woff2');
}
.ei {
display : inline;
font-family : 'Elderberry-Inn';
line-height : 1;
vertical-align : baseline;
text-rendering : auto;
/* Better Font Rendering =========== */
-webkit-font-smoothing : antialiased;
-moz-osx-font-smoothing : grayscale;
&.book::before { content : '\E900'; }
&.screen::before { content : '\E901'; }
/* Spell levels */
&.spell-0::before { content : '\E902'; }
&.spell-1::before { content : '\E903'; }
&.spell-2::before { content : '\E904'; }
&.spell-3::before { content : '\E905'; }
&.spell-4::before { content : '\E906'; }
&.spell-5::before { content : '\E907'; }
&.spell-6::before { content : '\E908'; }
&.spell-7::before { content : '\E909'; }
&.spell-8::before { content : '\E90A'; }
&.spell-9::before { content : '\E90B'; }
/* Damage types */
&.acid::before { content : '\E90C'; }
&.bludgeoning::before { content : '\E90D'; }
&.cold::before { content : '\E90E'; }
&.fire::before { content : '\E90F'; }
&.force::before { content : '\E910'; }
&.lightning::before { content : '\E911'; }
&.necrotic::before { content : '\E912'; }
&.piercing::before { content : '\E913'; }
&.poison::before { content : '\E914'; }
&.psychic::before { content : '\E915'; }
&.radiant::before { content : '\E916'; }
&.slashing::before { content : '\E917'; }
&.thunder::before { content : '\E918'; }
/* DnD Conditions */
&.blinded::before { content : '\E919'; }
&.charmed::before { content : '\E91A'; }
&.deafened::before { content : '\E91B'; }
&.exhaust-1::before { content : '\E91C'; }
&.exhaust-2::before { content : '\E91D'; }
&.exhaust-3::before { content : '\E91E'; }
&.exhaust-4::before { content : '\E91F'; }
&.exhaust-5::before { content : '\E920'; }
&.exhaust-6::before { content : '\E921'; }
&.frightened::before { content : '\E922'; }
&.grappled::before { content : '\E923'; }
&.incapacitated::before { content : '\E924'; }
&.unconscious::before { content : '\E925'; }
&.invisible::before { content : '\E926'; }
&.paralyzed::before { content : '\E927'; }
&.petrified::before { content : '\E928'; }
&.poisoned::before { content : '\E929'; }
&.prone::before { content : '\E92A'; }
&.restrained::before { content : '\E92B'; }
&.stunned::before { content : '\E92C'; }
/* Character Classes and Features */
&.barbarian-rage::before { content : '\E92D'; }
&.barbarian-reckless-attack::before { content : '\E92E'; }
&.bardic-inspiration::before { content : '\E92F'; }
&.cleric-channel-divinity::before { content : '\E930'; }
&.druid-wild-shape::before { content : '\E931'; }
&.fighter-action-surge::before { content : '\E932'; }
&.fighter-second-wind::before { content : '\E933'; }
&.monk-flurry-blows::before { content : '\E934'; }
&.monk-patient-defense::before { content : '\E935'; }
&.monk-step-of-the-wind::before { content : '\E936'; }
&.monk-step-of-the-wind-2::before { content : '\E937'; }
&.monk-step-of-the-wind-3::before { content : '\E938'; }
&.monk-stunning-strike::before { content : '\E939'; }
&.monk-stunning-strike-2::before { content : '\E93A'; }
&.paladin-divine-smite::before { content : '\E93B'; }
&.paladin-lay-on-hands::before { content : '\E93C'; }
&.barbarian-abilities::before { content : '\E93D'; }
&.barbarian::before { content : '\E93E'; }
&.bard-abilities::before { content : '\E93F'; }
&.bard::before { content : '\E940'; }
&.cleric-abilities::before { content : '\E941'; }
&.cleric::before { content : '\E942'; }
&.druid-abilities::before { content : '\E943'; }
&.druid::before { content : '\E944'; }
&.fighter-abilities::before { content : '\E945'; }
&.fighter::before { content : '\E946'; }
&.monk-abilities::before { content : '\E947'; }
&.monk::before { content : '\E948'; }
&.paladin-abilities::before { content : '\E949'; }
&.paladin::before { content : '\E94A'; }
&.ranger-abilities::before { content : '\E94B'; }
&.ranger::before { content : '\E94C'; }
&.rogue-abilities::before { content : '\E94D'; }
&.rogue::before { content : '\E94E'; }
&.sorcerer-abilities::before { content : '\E94F'; }
&.sorcerer::before { content : '\E950'; }
&.warlock-abilities::before { content : '\E951'; }
&.warlock::before { content : '\E952'; }
&.wizard-abilities::before { content : '\E953'; }
&.wizard::before { content : '\E954'; }
/* Types of actions */
&.movement::before { content : '\E955'; }
&.action::before { content : '\E956'; }
&.bonus-action::before { content : '\E957'; }
&.reaction::before { content : '\E958'; }
/* SRD Spells */
&.acid-arrow::before { content : '\E959'; }
&.action-1::before { content : '\E95A'; }
&.alter-self::before { content : '\E95B'; }
&.alter-self-2::before { content : '\E95C'; }
&.magic-beans::before { content : '\E95D'; }
&.animal-friendship::before { content : '\E95E'; }
&.animate-dead::before { content : '\E95F'; }
&.animate-objects::before { content : '\E960'; }
&.animate-objects-2::before { content : '\E961'; }
&.bane::before { content : '\E962'; }
&.bless::before { content : '\E963'; }
&.blur::before { content : '\E964'; }
&.bonus::before { content : '\E965'; }
&.branding-smite::before { content : '\E966'; }
&.burning-hands::before { content : '\E967'; }
&.charm-person::before { content : '\E968'; }
&.chill-touch::before { content : '\E969'; }
&.cloudkill::before { content : '\E96A'; }
&.comprehend-languages::before { content : '\E96B'; }
&.cone-of-cold::before { content : '\E96C'; }
&.conjure-elemental::before { content : '\E96D'; }
&.conjure-minor-elemental::before { content : '\E96E'; }
&.control-water::before { content : '\E96F'; }
&.counterspell::before { content : '\E970'; }
&.cure-wounds::before { content : '\E971'; }
&.dancing-lights::before { content : '\E972'; }
&.darkness::before { content : '\E973'; }
&.detect-magic::before { content : '\E974'; }
&.disguise-self::before { content : '\E975'; }
&.disintegrate::before { content : '\E976'; }
&.dispel-evil-and-good::before { content : '\E977'; }
&.dispel-magic::before { content : '\E978'; }
&.dominate-monster::before { content : '\E979'; }
&.dominate-person::before { content : '\E97A'; }
&.eldritch-blast::before { content : '\E97B'; }
&.enlarge-reduce::before { content : '\E97C'; }
&.entangle::before { content : '\E97D'; }
&.faerie-fire::before { content : '\E97E'; }
&.faerie-fire2::before { content : '\E97F'; }
&.feather-fall::before { content : '\E980'; }
&.find-familiar::before { content : '\E981'; }
&.finger-of-death::before { content : '\E982'; }
&.fireball::before { content : '\E983'; }
&.floating-disk::before { content : '\E984'; }
&.fly::before { content : '\E985'; }
&.fog-cloud::before { content : '\E986'; }
&.gaseous-form::before { content : '\E987'; }
&.gaseous-form2::before { content : '\E988'; }
&.gentle-repose::before { content : '\E989'; }
&.gentle-repose2::before { content : '\E98A'; }
&.globe-of-invulnerability::before { content : '\E98B'; }
&.guiding-bolt::before { content : '\E98C'; }
&.healing-word::before { content : '\E98D'; }
&.heat-metal::before { content : '\E98E'; }
&.hellish-rebuke::before { content : '\E98F'; }
&.heroes-feast::before { content : '\E990'; }
&.heroism::before { content : '\E991'; }
&.hideous-laughter::before { content : '\E992'; }
&.identify::before { content : '\E993'; }
&.illusory-script::before { content : '\E994'; }
&.inflict-wounds::before { content : '\E995'; }
&.light::before { content : '\E996'; }
&.longstrider::before { content : '\E997'; }
&.mage-armor::before { content : '\E998'; }
&.mage-hand::before { content : '\E999'; }
&.magic-missile::before { content : '\E99A'; }
&.mass-cure-wounds::before { content : '\E99B'; }
&.mass-healing-word::before { content : '\E99C'; }
&.Mending::before { content : '\E99D'; }
&.message::before { content : '\E99E'; }
&.Minor-illusion::before { content : '\E99F'; }
&.movement1::before { content : '\E9A0'; }
&.polymorph::before { content : '\E9A1'; }
&.power-word-kill::before { content : '\E9A2'; }
&.power-word-stun::before { content : '\E9A3'; }
&.prayer-of-healing::before { content : '\E9A4'; }
&.prestidigitation::before { content : '\E9A5'; }
&.protection-from-evil-and-good::before { content : '\E9A6'; }
&.raise-dead::before { content : '\E9A7'; }
&.raise-dead2::before { content : '\E9A8'; }
&.reaction1::before { content : '\E9A9'; }
&.resurrection::before { content : '\E9AA'; }
&.resurrection2::before { content : '\E9AB'; }
&.revivify::before { content : '\E9AC'; }
&.revivify2::before { content : '\E9AD'; }
&.sacred-flame::before { content : '\E9AE'; }
&.sanctuary::before { content : '\E9AF'; }
&.scorching-ray::before { content : '\E9B0'; }
&.sending::before { content : '\E9B1'; }
&.shatter::before { content : '\E9B2'; }
&.shield::before { content : '\E9B3'; }
&.silent-image::before { content : '\E9B4'; }
&.sleep::before { content : '\E9B5'; }
&.speak-with-animals::before { content : '\E9B6'; }
&.telekinesis::before { content : '\E9B7'; }
&.true-strike::before { content : '\E9B8'; }
&.vicious-mockery::before { content : '\E9B9'; }
&.wall-of-fire::before { content : '\E9BA'; }
&.wall-of-force::before { content : '\E9BB'; }
&.wall-of-ice::before { content : '\E9BC'; }
&.wall-of-stone::before { content : '\E9BD'; }
&.wall-of-thorns::before { content : '\E9BE'; }
&.wish::before { content : '\E9BF'; }
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
/* Icon Font: Font Awesome */
.far,.fas,.fab { display : inline; }

View File

@@ -0,0 +1,13 @@
# Game Icons License
The font used in gameIcons.woff / gameIcons.less / gameIcons.js, and usable in the Homebrewery as "gi" icons, are a subset of the Game-Icons.net library of icons.
## The license
Game-Icons has this to say about their license:
> Game-icons.net is an online repository providing heaps of cool game related graphics.
>
> They are provided provided under the terms of the Creative Commons 3.0 BY license.
>
> It means that you can use them freely as long as you credit the original author in your creation(see below). A mention like "Icons made by {author;}. Available on https://game-icons.net" is fine.

View File

@@ -0,0 +1,509 @@
/* eslint-disable max-lines */
// This is a subset of the library of icons at game-icons.net -- the subset is from RPG-Awesome repo
// The entire font can be downloaded as svg from game-icons.net,
// and then loaded through icomoon.io to create webfont from svg,
// and the css font file can be turned into below list using regex
// regex used: \.([^:-]*)-([^:]*)(.*)
// substitution: "$1$2" : "$1-$2",
const gameIcons = {
'gi_zigzag_leaf' : 'gi zigzag-leaf',
'gi_zebra_shield' : 'gi zebra-shield',
'gi_x_mark' : 'gi x-mark',
'gi_wyvern' : 'gi wyvern',
'gi_wrench' : 'gi wrench',
'gi_wooden_sign' : 'gi wooden-sign',
'gi_wolf_howl' : 'gi wolf-howl',
'gi_wolf_head' : 'gi wolf-head',
'gi_wireless_signal' : 'gi wireless-signal',
'gi_wifi' : 'gi wifi',
'gi_water_drop' : 'gi water-drop',
'gi_virgo' : 'gi virgo',
'gi_vine_whip' : 'gi vine-whip',
'gi_vial' : 'gi vial',
'gi_vest' : 'gi vest',
'gi_venomous_snake' : 'gi venomous-snake',
'gi_vase' : 'gi vase',
'gi_unplugged' : 'gi unplugged',
'gi_underhand' : 'gi underhand',
'gi_uncertainty' : 'gi uncertainty',
'gi_two_hearts' : 'gi two-hearts',
'gi_two_dragons' : 'gi two-dragons',
'gi_turd' : 'gi turd',
'gi_trophy' : 'gi trophy',
'gi_triforce' : 'gi triforce',
'gi_trident' : 'gi trident',
'gi_trefoil_lily' : 'gi trefoil-lily',
'gi_trail' : 'gi trail',
'gi_tower' : 'gi tower',
'gi_torch' : 'gi torch',
'gi_tooth' : 'gi tooth',
'gi_tombstone' : 'gi tombstone',
'gi_toast' : 'gi toast',
'gi_tic_tac_toe' : 'gi tic-tac-toe',
'gi_three_keys' : 'gi three-keys',
'gi_thorny_vine' : 'gi thorny-vine',
'gi_thorn_arrow' : 'gi thorn-arrow',
'gi_tesla' : 'gi tesla',
'gi_tentacle' : 'gi tentacle',
'gi_telescope' : 'gi telescope',
'gi_taurus' : 'gi taurus',
'gi_targeted' : 'gi targeted',
'gi_target_laser' : 'gi target-laser',
'gi_target_arrows' : 'gi target-arrows',
'gi_syringe' : 'gi syringe',
'gi_surveillance_camera' : 'gi surveillance-camera',
'gi_supersonic_arrow' : 'gi supersonic-arrow',
'gi_super_mushroom' : 'gi super-mushroom',
'gi_sunbeams' : 'gi sunbeams',
'gi_sun' : 'gi sun',
'gi_sun_symbol' : 'gi sun-symbol',
'gi_suits' : 'gi suits',
'gi_suckered_tentacle' : 'gi suckered-tentacle',
'gi_stopwatch' : 'gi stopwatch',
'gi_sprout' : 'gi sprout',
'gi_sprout_emblem' : 'gi sprout-emblem',
'gi_spray_can' : 'gi spray-can',
'gi_splash' : 'gi splash',
'gi_spiral_shell' : 'gi spiral-shell',
'gi_spinning_sword' : 'gi spinning-sword',
'gi_spiked_tentacle' : 'gi spiked-tentacle',
'gi_spiked_mace' : 'gi spiked-mace',
'gi_spikeball' : 'gi spikeball',
'gi_spider_face' : 'gi spider-face',
'gi_speech_bubbles' : 'gi speech-bubbles',
'gi_speech_bubble' : 'gi speech-bubble',
'gi_spear_head' : 'gi spear-head',
'gi_spawn_node' : 'gi spawn-node',
'gi_spades' : 'gi spades',
'gi_spades_card' : 'gi spades-card',
'gi_soccer_ball' : 'gi soccer-ball',
'gi_snowflake' : 'gi snowflake',
'gi_snorkel' : 'gi snorkel',
'gi_snake' : 'gi snake',
'gi_snail' : 'gi snail',
'gi_small_fire' : 'gi small-fire',
'gi_slash_ring' : 'gi slash-ring',
'gi_skull' : 'gi skull',
'gi_skull_trophy' : 'gi skull-trophy',
'gi_site' : 'gi site',
'gi_sideswipe' : 'gi sideswipe',
'gi_sickle' : 'gi sickle',
'gi_shuriken' : 'gi shuriken',
'gi_shovel' : 'gi shovel',
'gi_shotgun_shell' : 'gi shotgun-shell',
'gi_shot_through_the_heart' : 'gi shot-through-the-heart',
'gi_shoe_prints' : 'gi shoe-prints',
'gi_ship_emblem' : 'gi ship-emblem',
'gi_shield' : 'gi shield',
'gi_sheriff' : 'gi sheriff',
'gi_sheep' : 'gi sheep',
'gi_shark' : 'gi shark',
'gi_seagull' : 'gi seagull',
'gi_sea_serpent' : 'gi sea-serpent',
'gi_scythe' : 'gi scythe',
'gi_scroll_unfurled' : 'gi scroll-unfurled',
'gi_scorpio' : 'gi scorpio',
'gi_save' : 'gi save',
'gi_satellite' : 'gi satellite',
'gi_sapphire' : 'gi sapphire',
'gi_sagittarius' : 'gi sagittarius',
'gi_rune_stone' : 'gi rune-stone',
'gi_rss' : 'gi rss',
'gi_round_shield' : 'gi round-shield',
'gi_round_bottom_flask' : 'gi round-bottom-flask',
'gi_robot_arm' : 'gi robot-arm',
'gi_roast_chicken' : 'gi roast-chicken',
'gi_ringing_bell' : 'gi ringing-bell',
'gi_rifle' : 'gi rifle',
'gi_revolver' : 'gi revolver',
'gi_reverse' : 'gi reverse',
'gi_repair' : 'gi repair',
'gi_relic_blade' : 'gi relic-blade',
'gi_regeneration' : 'gi regeneration',
'gi_recycle' : 'gi recycle',
'gi_reactor' : 'gi reactor',
'gi_raven' : 'gi raven',
'gi_radioactive' : 'gi radioactive',
'gi_radial_balance' : 'gi radial-balance',
'gi_radar_dish' : 'gi radar-dish',
'gi_rabbit' : 'gi rabbit',
'gi_quill_ink' : 'gi quill-ink',
'gi_queen_crown' : 'gi queen-crown',
'gi_pyramids' : 'gi pyramids',
'gi_potion' : 'gi potion',
'gi_poison_cloud' : 'gi poison-cloud',
'gi_podium' : 'gi podium',
'gi_player' : 'gi player',
'gi_player_thunder_struck' : 'gi player-thunder-struck',
'gi_player_teleport' : 'gi player-teleport',
'gi_player_shot' : 'gi player-shot',
'gi_player_pyromaniac' : 'gi player-pyromaniac',
'gi_player_pain' : 'gi player-pain',
'gi_player_lift' : 'gi player-lift',
'gi_player_king' : 'gi player-king',
'gi_player_dodge' : 'gi player-dodge',
'gi_player_despair' : 'gi player-despair',
'gi_plain_dagger' : 'gi plain-dagger',
'gi_pisces' : 'gi pisces',
'gi_ping_pong' : 'gi ping-pong',
'gi_pine_tree' : 'gi pine-tree',
'gi_pills' : 'gi pills',
'gi_pill' : 'gi pill',
'gi_perspective_dice_three' : 'gi perspective-dice-three',
'gi_perspective_dice_six' : 'gi perspective-dice-six',
'gi_perspective_dice_six_two' : 'gi perspective-dice-six-two',
'gi_perspective_dice_random' : 'gi perspective-dice-random',
'gi_perspective_dice_one' : 'gi perspective-dice-one',
'gi_perspective_dice_four' : 'gi perspective-dice-four',
'gi_perspective_dice_five' : 'gi perspective-dice-five',
'gi_pawprint' : 'gi pawprint',
'gi_pawn' : 'gi pawn',
'gi_palm_tree' : 'gi palm-tree',
'gi_overmind' : 'gi overmind',
'gi_overhead' : 'gi overhead',
'gi_ophiuchus' : 'gi ophiuchus',
'gi_on_target' : 'gi on-target',
'gi_omega' : 'gi omega',
'gi_octopus' : 'gi octopus',
'gi_ocean_emblem' : 'gi ocean-emblem',
'gi_ocarina' : 'gi ocarina',
'gi_nuclear' : 'gi nuclear',
'gi_noose' : 'gi noose',
'gi_nodular' : 'gi nodular',
'gi_nails' : 'gi nails',
'gi_musket' : 'gi musket',
'gi_muscle_up' : 'gi muscle-up',
'gi_muscle_fat' : 'gi muscle-fat',
'gi_mp5' : 'gi mp5',
'gi_moon_sun' : 'gi moon-sun',
'gi_montains' : 'gi montains',
'gi_monster_skull' : 'gi monster-skull',
'gi_mirror' : 'gi mirror',
'gi_mining_diamonds' : 'gi mining-diamonds',
'gi_mine_wagon' : 'gi mine-wagon',
'gi_microphone' : 'gi microphone',
'gi_metal_gate' : 'gi metal-gate',
'gi_medical_pack' : 'gi medical-pack',
'gi_meat' : 'gi meat',
'gi_meat_hook' : 'gi meat-hook',
'gi_match' : 'gi match',
'gi_mass_driver' : 'gi mass-driver',
'gi_magnet' : 'gi magnet',
'gi_maggot' : 'gi maggot',
'gi_love_howl' : 'gi love-howl',
'gi_locked_fortress' : 'gi locked-fortress',
'gi_load' : 'gi load',
'gi_lit_candelabra' : 'gi lit-candelabra',
'gi_lion' : 'gi lion',
'gi_lightning' : 'gi lightning',
'gi_lightning_trio' : 'gi lightning-trio',
'gi_lightning_sword' : 'gi lightning-sword',
'gi_lightning_storm' : 'gi lightning-storm',
'gi_lightning_bolt' : 'gi lightning-bolt',
'gi_lighthouse' : 'gi lighthouse',
'gi_light_bulb' : 'gi light-bulb',
'gi_libra' : 'gi libra',
'gi_lever' : 'gi lever',
'gi_level_two' : 'gi level-two',
'gi_level_two_advanced' : 'gi level-two-advanced',
'gi_level_three' : 'gi level-three',
'gi_level_three_advanced' : 'gi level-three-advanced',
'gi_level_four' : 'gi level-four',
'gi_level_four_advanced' : 'gi level-four-advanced',
'gi_leo' : 'gi leo',
'gi_leaf' : 'gi leaf',
'gi_lava' : 'gi lava',
'gi_laser_site' : 'gi laser-site',
'gi_laser_blast' : 'gi laser-blast',
'gi_large_hammer' : 'gi large-hammer',
'gi_lantern_flame' : 'gi lantern-flame',
'gi_kunai' : 'gi kunai',
'gi_knight_helmet' : 'gi knight-helmet',
'gi_knife' : 'gi knife',
'gi_knife_fork' : 'gi knife-fork',
'gi_kitchen_knives' : 'gi kitchen-knives',
'gi_key' : 'gi key',
'gi_key_basic' : 'gi key-basic',
'gi_kettlebell' : 'gi kettlebell',
'gi_kaleidoscope' : 'gi kaleidoscope',
'gi_jigsaw_piece' : 'gi jigsaw-piece',
'gi_jetpack' : 'gi jetpack',
'gi_interdiction' : 'gi interdiction',
'gi_insect_jaws' : 'gi insect-jaws',
'gi_incense' : 'gi incense',
'gi_implosion' : 'gi implosion',
'gi_ice_cube' : 'gi ice-cube',
'gi_hydra' : 'gi hydra',
'gi_hydra_shot' : 'gi hydra-shot',
'gi_hourglass' : 'gi hourglass',
'gi_hot_surface' : 'gi hot-surface',
'gi_hospital_cross' : 'gi hospital-cross',
'gi_horseshoe' : 'gi horseshoe',
'gi_horns' : 'gi horns',
'gi_horn_call' : 'gi horn-call',
'gi_hood' : 'gi hood',
'gi_honeycomb' : 'gi honeycomb',
'gi_hole_ladder' : 'gi hole-ladder',
'gi_hive_emblem' : 'gi hive-emblem',
'gi_help' : 'gi help',
'gi_helmet' : 'gi helmet',
'gi_heavy_shield' : 'gi heavy-shield',
'gi_heavy_fall' : 'gi heavy-fall',
'gi_heat_haze' : 'gi heat-haze',
'gi_hearts' : 'gi hearts',
'gi_hearts_card' : 'gi hearts-card',
'gi_heartburn' : 'gi heartburn',
'gi_heart_tower' : 'gi heart-tower',
'gi_heart_bottle' : 'gi heart-bottle',
'gi_health' : 'gi health',
'gi_health_increase' : 'gi health-increase',
'gi_health_decrease' : 'gi health-decrease',
'gi_harpoon_trident' : 'gi harpoon-trident',
'gi_hand' : 'gi hand',
'gi_hand_saw' : 'gi hand-saw',
'gi_hand_emblem' : 'gi hand-emblem',
'gi_hammer' : 'gi hammer',
'gi_hammer_drop' : 'gi hammer-drop',
'gi_halberd' : 'gi halberd',
'gi_guillotine' : 'gi guillotine',
'gi_guarded_tower' : 'gi guarded-tower',
'gi_groundbreaker' : 'gi groundbreaker',
'gi_grenade' : 'gi grenade',
'gi_grass' : 'gi grass',
'gi_grass_patch' : 'gi grass-patch',
'gi_grappling_hook' : 'gi grappling-hook',
'gi_gold_bar' : 'gi gold-bar',
'gi_gloop' : 'gi gloop',
'gi_glass_heart' : 'gi glass-heart',
'gi_gemini' : 'gi gemini',
'gi_gem' : 'gi gem',
'gi_gem_pendant' : 'gi gem-pendant',
'gi_gecko' : 'gi gecko',
'gi_gears' : 'gi gears',
'gi_gear_heart' : 'gi gear-heart',
'gi_gear_hammer' : 'gi gear-hammer',
'gi_gavel' : 'gi gavel',
'gi_gamepad_cross' : 'gi gamepad-cross',
'gi_frozen_arrow' : 'gi frozen-arrow',
'gi_frostfire' : 'gi frostfire',
'gi_frost_emblem' : 'gi frost-emblem',
'gi_fox' : 'gi fox',
'gi_forward' : 'gi forward',
'gi_forging' : 'gi forging',
'gi_footprint' : 'gi footprint',
'gi_food_chain' : 'gi food-chain',
'gi_focused_lightning' : 'gi focused-lightning',
'gi_fluffy_swirl' : 'gi fluffy-swirl',
'gi_flowers' : 'gi flowers',
'gi_flower' : 'gi flower',
'gi_flat_hammer' : 'gi flat-hammer',
'gi_flask' : 'gi flask',
'gi_flaming_trident' : 'gi flaming-trident',
'gi_flaming_claw' : 'gi flaming-claw',
'gi_flaming_arrow' : 'gi flaming-arrow',
'gi_flame_symbol' : 'gi flame-symbol',
'gi_fizzing_flask' : 'gi fizzing-flask',
'gi_fish' : 'gi fish',
'gi_fireball_sword' : 'gi fireball-sword',
'gi_fire' : 'gi fire',
'gi_fire_symbol' : 'gi fire-symbol',
'gi_fire_shield' : 'gi fire-shield',
'gi_fire_ring' : 'gi fire-ring',
'gi_fire_breath' : 'gi fire-breath',
'gi_fire_bomb' : 'gi fire-bomb',
'gi_fedora' : 'gi fedora',
'gi_feathered_wing' : 'gi feathered-wing',
'gi_feather_wing' : 'gi feather-wing',
'gi_fast_ship' : 'gi fast-ship',
'gi_falling' : 'gi falling',
'gi_fall_down' : 'gi fall-down',
'gi_fairy' : 'gi fairy',
'gi_fairy_wand' : 'gi fairy-wand',
'gi_eyeball' : 'gi eyeball',
'gi_eye_shield' : 'gi eye-shield',
'gi_eye_monster' : 'gi eye-monster',
'gi_explosive_materials' : 'gi explosive-materials',
'gi_explosion' : 'gi explosion',
'gi_energise' : 'gi energise',
'gi_emerald' : 'gi emerald',
'gi_eggplant' : 'gi eggplant',
'gi_egg' : 'gi egg',
'gi_egg_pod' : 'gi egg-pod',
'gi_duel' : 'gi duel',
'gi_droplets' : 'gi droplets',
'gi_droplet' : 'gi droplet',
'gi_droplet_splash' : 'gi droplet-splash',
'gi_dripping_sword' : 'gi dripping-sword',
'gi_dripping_knife' : 'gi dripping-knife',
'gi_dripping_blade' : 'gi dripping-blade',
'gi_drill' : 'gi drill',
'gi_dragonfly' : 'gi dragonfly',
'gi_dragon' : 'gi dragon',
'gi_dragon_wing' : 'gi dragon-wing',
'gi_dragon_breath' : 'gi dragon-breath',
'gi_doubled' : 'gi doubled',
'gi_double_team' : 'gi double-team',
'gi_diving_dagger' : 'gi diving-dagger',
'gi_divert' : 'gi divert',
'gi_dinosaur' : 'gi dinosaur',
'gi_dice_two' : 'gi dice-two',
'gi_dice_three' : 'gi dice-three',
'gi_dice_six' : 'gi dice-six',
'gi_dice_one' : 'gi dice-one',
'gi_dice_four' : 'gi dice-four',
'gi_dice_five' : 'gi dice-five',
'gi_diamonds' : 'gi diamonds',
'gi_diamonds_card' : 'gi diamonds-card',
'gi_diamond' : 'gi diamond',
'gi_desert_skull' : 'gi desert-skull',
'gi_dervish_swords' : 'gi dervish-swords',
'gi_demolish' : 'gi demolish',
'gi_defibrillate' : 'gi defibrillate',
'gi_decapitation' : 'gi decapitation',
'gi_death_skull' : 'gi death-skull',
'gi_dead_tree' : 'gi dead-tree',
'gi_daisy' : 'gi daisy',
'gi_daggers' : 'gi daggers',
'gi_cycle' : 'gi cycle',
'gi_cut_palm' : 'gi cut-palm',
'gi_cubes' : 'gi cubes',
'gi_crystals' : 'gi crystals',
'gi_crystal_wand' : 'gi crystal-wand',
'gi_crystal_cluster' : 'gi crystal-cluster',
'gi_crystal_ball' : 'gi crystal-ball',
'gi_crush' : 'gi crush',
'gi_crowned_heart' : 'gi crowned-heart',
'gi_crown' : 'gi crown',
'gi_crown_of_thorns' : 'gi crown-of-thorns',
'gi_crossed_swords' : 'gi crossed-swords',
'gi_crossed_sabres' : 'gi crossed-sabres',
'gi_crossed_pistols' : 'gi crossed-pistols',
'gi_crossed_bones' : 'gi crossed-bones',
'gi_crossed_axes' : 'gi crossed-axes',
'gi_crossbow' : 'gi crossbow',
'gi_croc_sword' : 'gi croc-sword',
'gi_cracked_shield' : 'gi cracked-shield',
'gi_cracked_helm' : 'gi cracked-helm',
'gi_crab_claw' : 'gi crab-claw',
'gi_corked_tube' : 'gi corked-tube',
'gi_compass' : 'gi compass',
'gi_cold_heart' : 'gi cold-heart',
'gi_cog' : 'gi cog',
'gi_cog_wheel' : 'gi cog-wheel',
'gi_coffee_mug' : 'gi coffee-mug',
'gi_cluster_bomb' : 'gi cluster-bomb',
'gi_clovers' : 'gi clovers',
'gi_clovers_card' : 'gi clovers-card',
'gi_clover' : 'gi clover',
'gi_clockwork' : 'gi clockwork',
'gi_cloak_and_dagger' : 'gi cloak-and-dagger',
'gi_circular_shield' : 'gi circular-shield',
'gi_circular_saw' : 'gi circular-saw',
'gi_circle_of_circles' : 'gi circle-of-circles',
'gi_chicken_leg' : 'gi chicken-leg',
'gi_chessboard' : 'gi chessboard',
'gi_chemical_arrow' : 'gi chemical-arrow',
'gi_cheese' : 'gi cheese',
'gi_chain' : 'gi chain',
'gi_cat' : 'gi cat',
'gi_castle_flag' : 'gi castle-flag',
'gi_castle_emblem' : 'gi castle-emblem',
'gi_carrot' : 'gi carrot',
'gi_capricorn' : 'gi capricorn',
'gi_capitol' : 'gi capitol',
'gi_cannon_shot' : 'gi cannon-shot',
'gi_candle' : 'gi candle',
'gi_candle_fire' : 'gi candle-fire',
'gi_cancer' : 'gi cancer',
'gi_cancel' : 'gi cancel',
'gi_campfire' : 'gi campfire',
'gi_butterfly' : 'gi butterfly',
'gi_burst_blob' : 'gi burst-blob',
'gi_burning_meteor' : 'gi burning-meteor',
'gi_burning_eye' : 'gi burning-eye',
'gi_burning_embers' : 'gi burning-embers',
'gi_burning_book' : 'gi burning-book',
'gi_bullets' : 'gi bullets',
'gi_bubbling_potion' : 'gi bubbling-potion',
'gi_broken_skull' : 'gi broken-skull',
'gi_broken_shield' : 'gi broken-shield',
'gi_broken_heart' : 'gi broken-heart',
'gi_broken_bottle' : 'gi broken-bottle',
'gi_broken_bone' : 'gi broken-bone',
'gi_broadsword' : 'gi broadsword',
'gi_broadhead_arrow' : 'gi broadhead-arrow',
'gi_bridge' : 'gi bridge',
'gi_brandy_bottle' : 'gi brandy-bottle',
'gi_brain_freeze' : 'gi brain-freeze',
'gi_bowling_pin' : 'gi bowling-pin',
'gi_bowie_knife' : 'gi bowie-knife',
'gi_bottom_right' : 'gi bottom-right',
'gi_bottled_bolt' : 'gi bottled-bolt',
'gi_bottle_vapors' : 'gi bottle-vapors',
'gi_boot_stomp' : 'gi boot-stomp',
'gi_boomerang' : 'gi boomerang',
'gi_book' : 'gi book',
'gi_bone_knife' : 'gi bone-knife',
'gi_bone_bite' : 'gi bone-bite',
'gi_bombs' : 'gi bombs',
'gi_bomb_explosion' : 'gi bomb-explosion',
'gi_bolt_shield' : 'gi bolt-shield',
'gi_bleeding_hearts' : 'gi bleeding-hearts',
'gi_bleeding_eye' : 'gi bleeding-eye',
'gi_blaster' : 'gi blaster',
'gi_blast' : 'gi blast',
'gi_blade_bite' : 'gi blade-bite',
'gi_bird_mask' : 'gi bird-mask',
'gi_bird_claw' : 'gi bird-claw',
'gi_biohazard' : 'gi biohazard',
'gi_bell' : 'gi bell',
'gi_beetle' : 'gi beetle',
'gi_beer' : 'gi beer',
'gi_bear_trap' : 'gi bear-trap',
'gi_beam_wake' : 'gi beam-wake',
'gi_batwings' : 'gi batwings',
'gi_battery_white' : 'gi battery-white',
'gi_battery_positive' : 'gi battery-positive',
'gi_battery_negative' : 'gi battery-negative',
'gi_battery_black' : 'gi battery-black',
'gi_battery_75' : 'gi battery-75',
'gi_battery_50' : 'gi battery-50',
'gi_battery_25' : 'gi battery-25',
'gi_battery_100' : 'gi battery-100',
'gi_battery_0' : 'gi battery-0',
'gi_batteries' : 'gi batteries',
'gi_battered_axe' : 'gi battered-axe',
'gi_bat_sword' : 'gi bat-sword',
'gi_barrier' : 'gi barrier',
'gi_barbed_arrow' : 'gi barbed-arrow',
'gi_ball' : 'gi ball',
'gi_axe' : 'gi axe',
'gi_axe_swing' : 'gi axe-swing',
'gi_aware' : 'gi aware',
'gi_aura' : 'gi aura',
'gi_arson' : 'gi arson',
'gi_arrow_flights' : 'gi arrow-flights',
'gi_arrow_cluster' : 'gi arrow-cluster',
'gi_aries' : 'gi aries',
'gi_arena' : 'gi arena',
'gi_archery_target' : 'gi archery-target',
'gi_archer' : 'gi archer',
'gi_arcane_mask' : 'gi arcane-mask',
'gi_aquarius' : 'gi aquarius',
'gi_apple' : 'gi apple',
'gi_anvil' : 'gi anvil',
'gi_ankh' : 'gi ankh',
'gi_angel_wings' : 'gi angel-wings',
'gi_anchor' : 'gi anchor',
'gi_ammo_bag' : 'gi ammo-bag',
'gi_alligator_clip' : 'gi alligator-clip',
'gi_all_for_one' : 'gi all-for-one',
'gi_alien_fire' : 'gi alien-fire',
'gi_acorn' : 'gi acorn',
'gi_acid' : 'gi acid'
};
module.exports = gameIcons;

View File

@@ -0,0 +1,516 @@
@font-face {
font-family : 'Game-Icons';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/iconFonts/gameIcons.woff') format('woff');
font-display : block;
}
.gi {
/* use !important to prevent issues with browser extensions that change fonts */
display : inline;
font-family : 'Game-Icons' !important;
line-height : 1;
vertical-align : baseline;
text-rendering : auto;
/* Better Font Rendering =========== */
-webkit-font-smoothing : antialiased;
-moz-osx-font-smoothing : grayscale;
&.zigzag-leaf::before { content : '\e900'; }
&.zebra-shield::before { content : '\e901'; }
&.x-mark::before { content : '\e902'; }
&.wyvern::before { content : '\e903'; }
&.wrench::before { content : '\e904'; }
&.wooden-sign::before { content : '\e905'; }
&.wolf-howl::before { content : '\e906'; }
&.wolf-head::before { content : '\e907'; }
&.wireless-signal::before { content : '\e908'; }
&.wifi::before { content : '\e909'; }
&.water-drop::before { content : '\e90a'; }
&.virgo::before { content : '\e90b'; }
&.vine-whip::before { content : '\e90c'; }
&.vial::before { content : '\e90d'; }
&.vest::before { content : '\e90e'; }
&.venomous-snake::before { content : '\e90f'; }
&.vase::before { content : '\e910'; }
&.unplugged::before { content : '\e911'; }
&.underhand::before { content : '\e912'; }
&.uncertainty::before { content : '\e913'; }
&.two-hearts::before { content : '\e914'; }
&.two-dragons::before { content : '\e915'; }
&.turd::before { content : '\e916'; }
&.trophy::before { content : '\e917'; }
&.triforce::before { content : '\e918'; }
&.trident::before { content : '\e919'; }
&.trefoil-lily::before { content : '\e91a'; }
&.trail::before { content : '\e91b'; }
&.tower::before { content : '\e91c'; }
&.torch::before { content : '\e91d'; }
&.tooth::before { content : '\e91e'; }
&.tombstone::before { content : '\e91f'; }
&.toast::before { content : '\e920'; }
&.tic-tac-toe::before { content : '\e921'; }
&.three-keys::before { content : '\e922'; }
&.thorny-vine::before { content : '\e923'; }
&.thorn-arrow::before { content : '\e924'; }
&.tesla::before { content : '\e925'; }
&.tentacle::before { content : '\e926'; }
&.telescope::before { content : '\e927'; }
&.taurus::before { content : '\e928'; }
&.targeted::before { content : '\e929'; }
&.target-laser::before { content : '\e92a'; }
&.target-arrows::before { content : '\e92b'; }
&.syringe::before { content : '\e92c'; }
&.surveillance-camera::before { content : '\e92d'; }
&.supersonic-arrow::before { content : '\e92e'; }
&.super-mushroom::before { content : '\e92f'; }
&.sunbeams::before { content : '\e930'; }
&.sun::before { content : '\e931'; }
&.sun-symbol::before { content : '\e932'; }
&.suits::before { content : '\e933'; }
&.suckered-tentacle::before { content : '\e934'; }
&.stopwatch::before { content : '\e935'; }
&.sprout::before { content : '\e936'; }
&.sprout-emblem::before { content : '\e937'; }
&.spray-can::before { content : '\e938'; }
&.splash::before { content : '\e939'; }
&.spiral-shell::before { content : '\e93a'; }
&.spinning-sword::before { content : '\e93b'; }
&.spiked-tentacle::before { content : '\e93c'; }
&.spiked-mace::before { content : '\e93d'; }
&.spikeball::before { content : '\e93e'; }
&.spider-face::before { content : '\e93f'; }
&.speech-bubbles::before { content : '\e940'; }
&.speech-bubble::before { content : '\e941'; }
&.spear-head::before { content : '\e942'; }
&.spawn-node::before { content : '\e943'; }
&.spades::before { content : '\e944'; }
&.spades-card::before { content : '\e945'; }
&.soccer-ball::before { content : '\e946'; }
&.snowflake::before { content : '\e947'; }
&.snorkel::before { content : '\e948'; }
&.snake::before { content : '\e949'; }
&.snail::before { content : '\e94a'; }
&.small-fire::before { content : '\e94b'; }
&.slash-ring::before { content : '\e94c'; }
&.skull::before { content : '\e94d'; }
&.skull-trophy::before { content : '\e94e'; }
&.site::before { content : '\e94f'; }
&.sideswipe::before { content : '\e950'; }
&.sickle::before { content : '\e951'; }
&.shuriken::before { content : '\e952'; }
&.shovel::before { content : '\e953'; }
&.shotgun-shell::before { content : '\e954'; }
&.shot-through-the-heart::before { content : '\e955'; }
&.shoe-prints::before { content : '\e956'; }
&.ship-emblem::before { content : '\e957'; }
&.shield::before { content : '\e958'; }
&.sheriff::before { content : '\e959'; }
&.sheep::before { content : '\e95a'; }
&.shark::before { content : '\e95b'; }
&.seagull::before { content : '\e95c'; }
&.sea-serpent::before { content : '\e95d'; }
&.scythe::before { content : '\e95e'; }
&.scroll-unfurled::before { content : '\e95f'; }
&.scorpio::before { content : '\e960'; }
&.save::before { content : '\e961'; }
&.satellite::before { content : '\e962'; }
&.sapphire::before { content : '\e963'; }
&.sagittarius::before { content : '\e964'; }
&.rune-stone::before { content : '\e965'; }
&.rss::before { content : '\e966'; }
&.round-shield::before { content : '\e967'; }
&.round-bottom-flask::before { content : '\e968'; }
&.robot-arm::before { content : '\e969'; }
&.roast-chicken::before { content : '\e96a'; }
&.ringing-bell::before { content : '\e96b'; }
&.rifle::before { content : '\e96c'; }
&.revolver::before { content : '\e96d'; }
&.reverse::before { content : '\e96e'; }
&.repair::before { content : '\e96f'; }
&.relic-blade::before { content : '\e970'; }
&.regeneration::before { content : '\e971'; }
&.recycle::before { content : '\e972'; }
&.reactor::before { content : '\e973'; }
&.raven::before { content : '\e974'; }
&.radioactive::before { content : '\e975'; }
&.radial-balance::before { content : '\e976'; }
&.radar-dish::before { content : '\e977'; }
&.rabbit::before { content : '\e978'; }
&.quill-ink::before { content : '\e979'; }
&.queen-crown::before { content : '\e97a'; }
&.pyramids::before { content : '\e97b'; }
&.potion::before { content : '\e97c'; }
&.poison-cloud::before { content : '\e97d'; }
&.podium::before { content : '\e97e'; }
&.player::before { content : '\e97f'; }
&.player-thunder-struck::before { content : '\e980'; }
&.player-teleport::before { content : '\e981'; }
&.player-shot::before { content : '\e982'; }
&.player-pyromaniac::before { content : '\e983'; }
&.player-pain::before { content : '\e984'; }
&.player-lift::before { content : '\e985'; }
&.player-king::before { content : '\e986'; }
&.player-dodge::before { content : '\e987'; }
&.player-despair::before { content : '\e988'; }
&.plain-dagger::before { content : '\e989'; }
&.pisces::before { content : '\e98a'; }
&.ping-pong::before { content : '\e98b'; }
&.pine-tree::before { content : '\e98c'; }
&.pills::before { content : '\e98d'; }
&.pill::before { content : '\e98e'; }
&.perspective-dice-three::before { content : '\e98f'; }
&.perspective-dice-six::before { content : '\e990'; }
&.perspective-dice-six-two::before { content : '\e991'; }
&.perspective-dice-random::before { content : '\e992'; }
&.perspective-dice-one::before { content : '\e993'; }
&.perspective-dice-four::before { content : '\e994'; }
&.perspective-dice-five::before { content : '\e995'; }
&.pawprint::before { content : '\e996'; }
&.pawn::before { content : '\e997'; }
&.palm-tree::before { content : '\e998'; }
&.overmind::before { content : '\e999'; }
&.overhead::before { content : '\e99a'; }
&.ophiuchus::before { content : '\e99b'; }
&.on-target::before { content : '\e99c'; }
&.omega::before { content : '\e99d'; }
&.octopus::before { content : '\e99e'; }
&.ocean-emblem::before { content : '\e99f'; }
&.ocarina::before { content : '\e9a0'; }
&.nuclear::before { content : '\e9a1'; }
&.noose::before { content : '\e9a2'; }
&.nodular::before { content : '\e9a3'; }
&.nails::before { content : '\e9a4'; }
&.musket::before { content : '\e9a5'; }
&.muscle-up::before { content : '\e9a6'; }
&.muscle-fat::before { content : '\e9a7'; }
&.mp5::before { content : '\e9a8'; }
&.moon-sun::before { content : '\e9a9'; }
&.montains::before { content : '\e9aa'; }
&.monster-skull::before { content : '\e9ab'; }
&.mirror::before { content : '\e9ac'; }
&.mining-diamonds::before { content : '\e9ad'; }
&.mine-wagon::before { content : '\e9ae'; }
&.microphone::before { content : '\e9af'; }
&.metal-gate::before { content : '\e9b0'; }
&.medical-pack::before { content : '\e9b1'; }
&.meat::before { content : '\e9b2'; }
&.meat-hook::before { content : '\e9b3'; }
&.match::before { content : '\e9b4'; }
&.mass-driver::before { content : '\e9b5'; }
&.magnet::before { content : '\e9b6'; }
&.maggot::before { content : '\e9b7'; }
&.love-howl::before { content : '\e9b8'; }
&.locked-fortress::before { content : '\e9b9'; }
&.load::before { content : '\e9ba'; }
&.lit-candelabra::before { content : '\e9bb'; }
&.lion::before { content : '\e9bc'; }
&.lightning::before { content : '\e9bd'; }
&.lightning-trio::before { content : '\e9be'; }
&.lightning-sword::before { content : '\e9bf'; }
&.lightning-storm::before { content : '\e9c0'; }
&.lightning-bolt::before { content : '\e9c1'; }
&.lighthouse::before { content : '\e9c2'; }
&.light-bulb::before { content : '\e9c3'; }
&.libra::before { content : '\e9c4'; }
&.lever::before { content : '\e9c5'; }
&.level-two::before { content : '\e9c6'; }
&.level-two-advanced::before { content : '\e9c7'; }
&.level-three::before { content : '\e9c8'; }
&.level-three-advanced::before { content : '\e9c9'; }
&.level-four::before { content : '\e9ca'; }
&.level-four-advanced::before { content : '\e9cb'; }
&.leo::before { content : '\e9cc'; }
&.leaf::before { content : '\e9cd'; }
&.lava::before { content : '\e9ce'; }
&.laser-site::before { content : '\e9cf'; }
&.laser-blast::before { content : '\e9d0'; }
&.large-hammer::before { content : '\e9d1'; }
&.lantern-flame::before { content : '\e9d2'; }
&.kunai::before { content : '\e9d3'; }
&.knight-helmet::before { content : '\e9d4'; }
&.knife::before { content : '\e9d5'; }
&.knife-fork::before { content : '\e9d6'; }
&.kitchen-knives::before { content : '\e9d7'; }
&.key::before { content : '\e9d8'; }
&.key-basic::before { content : '\e9d9'; }
&.kettlebell::before { content : '\e9da'; }
&.kaleidoscope::before { content : '\e9db'; }
&.jigsaw-piece::before { content : '\e9dc'; }
&.jetpack::before { content : '\e9dd'; }
&.interdiction::before { content : '\e9de'; }
&.insect-jaws::before { content : '\e9df'; }
&.incense::before { content : '\e9e0'; }
&.implosion::before { content : '\e9e1'; }
&.ice-cube::before { content : '\e9e2'; }
&.hydra::before { content : '\e9e3'; }
&.hydra-shot::before { content : '\e9e4'; }
&.hourglass::before { content : '\e9e5'; }
&.hot-surface::before { content : '\e9e6'; }
&.hospital-cross::before { content : '\e9e7'; }
&.horseshoe::before { content : '\e9e8'; }
&.horns::before { content : '\e9e9'; }
&.horn-call::before { content : '\e9ea'; }
&.hood::before { content : '\e9eb'; }
&.honeycomb::before { content : '\e9ec'; }
&.hole-ladder::before { content : '\e9ed'; }
&.hive-emblem::before { content : '\e9ee'; }
&.help::before { content : '\e9ef'; }
&.helmet::before { content : '\e9f0'; }
&.heavy-shield::before { content : '\e9f1'; }
&.heavy-fall::before { content : '\e9f2'; }
&.heat-haze::before { content : '\e9f3'; }
&.hearts::before { content : '\e9f4'; }
&.hearts-card::before { content : '\e9f5'; }
&.heartburn::before { content : '\e9f6'; }
&.heart-tower::before { content : '\e9f7'; }
&.heart-bottle::before { content : '\e9f8'; }
&.health::before { content : '\e9f9'; }
&.health-increase::before { content : '\e9fa'; }
&.health-decrease::before { content : '\e9fb'; }
&.harpoon-trident::before { content : '\e9fc'; }
&.hand::before { content : '\e9fd'; }
&.hand-saw::before { content : '\e9fe'; }
&.hand-emblem::before { content : '\e9ff'; }
&.hammer::before { content : '\ea00'; }
&.hammer-drop::before { content : '\ea01'; }
&.halberd::before { content : '\ea02'; }
&.guillotine::before { content : '\ea03'; }
&.guarded-tower::before { content : '\ea04'; }
&.groundbreaker::before { content : '\ea05'; }
&.grenade::before { content : '\ea06'; }
&.grass::before { content : '\ea07'; }
&.grass-patch::before { content : '\ea08'; }
&.grappling-hook::before { content : '\ea09'; }
&.gold-bar::before { content : '\ea0a'; }
&.gloop::before { content : '\ea0b'; }
&.glass-heart::before { content : '\ea0c'; }
&.gemini::before { content : '\ea0d'; }
&.gem::before { content : '\ea0e'; }
&.gem-pendant::before { content : '\ea0f'; }
&.gecko::before { content : '\ea10'; }
&.gears::before { content : '\ea11'; }
&.gear-heart::before { content : '\ea12'; }
&.gear-hammer::before { content : '\ea13'; }
&.gavel::before { content : '\ea14'; }
&.gamepad-cross::before { content : '\ea15'; }
&.frozen-arrow::before { content : '\ea16'; }
&.frostfire::before { content : '\ea17'; }
&.frost-emblem::before { content : '\ea18'; }
&.fox::before { content : '\ea19'; }
&.forward::before { content : '\ea1a'; }
&.forging::before { content : '\ea1b'; }
&.footprint::before { content : '\ea1c'; }
&.food-chain::before { content : '\ea1d'; }
&.focused-lightning::before { content : '\ea1e'; }
&.fluffy-swirl::before { content : '\ea1f'; }
&.flowers::before { content : '\ea20'; }
&.flower::before { content : '\ea21'; }
&.flat-hammer::before { content : '\ea22'; }
&.flask::before { content : '\ea23'; }
&.flaming-trident::before { content : '\ea24'; }
&.flaming-claw::before { content : '\ea25'; }
&.flaming-arrow::before { content : '\ea26'; }
&.flame-symbol::before { content : '\ea27'; }
&.fizzing-flask::before { content : '\ea28'; }
&.fish::before { content : '\ea29'; }
&.fireball-sword::before { content : '\ea2a'; }
&.fire::before { content : '\ea2b'; }
&.fire-symbol::before { content : '\ea2c'; }
&.fire-shield::before { content : '\ea2d'; }
&.fire-ring::before { content : '\ea2e'; }
&.fire-breath::before { content : '\ea2f'; }
&.fire-bomb::before { content : '\ea30'; }
&.fedora::before { content : '\ea31'; }
&.feathered-wing::before { content : '\ea32'; }
&.feather-wing::before { content : '\ea33'; }
&.fast-ship::before { content : '\ea34'; }
&.falling::before { content : '\ea35'; }
&.fall-down::before { content : '\ea36'; }
&.fairy::before { content : '\ea37'; }
&.fairy-wand::before { content : '\ea38'; }
&.eyeball::before { content : '\ea39'; }
&.eye-shield::before { content : '\ea3a'; }
&.eye-monster::before { content : '\ea3b'; }
&.explosive-materials::before { content : '\ea3c'; }
&.explosion::before { content : '\ea3d'; }
&.energise::before { content : '\ea3e'; }
&.emerald::before { content : '\ea3f'; }
&.eggplant::before { content : '\ea40'; }
&.egg::before { content : '\ea41'; }
&.egg-pod::before { content : '\ea42'; }
&.duel::before { content : '\ea43'; }
&.droplets::before { content : '\ea44'; }
&.droplet::before { content : '\ea45'; }
&.droplet-splash::before { content : '\ea46'; }
&.dripping-sword::before { content : '\ea47'; }
&.dripping-knife::before { content : '\ea48'; }
&.dripping-blade::before { content : '\ea49'; }
&.drill::before { content : '\ea4a'; }
&.dragonfly::before { content : '\ea4b'; }
&.dragon::before { content : '\ea4c'; }
&.dragon-wing::before { content : '\ea4d'; }
&.dragon-breath::before { content : '\ea4e'; }
&.doubled::before { content : '\ea4f'; }
&.double-team::before { content : '\ea50'; }
&.diving-dagger::before { content : '\ea51'; }
&.divert::before { content : '\ea52'; }
&.dinosaur::before { content : '\ea53'; }
&.dice-two::before { content : '\ea54'; }
&.dice-three::before { content : '\ea55'; }
&.dice-six::before { content : '\ea56'; }
&.dice-one::before { content : '\ea57'; }
&.dice-four::before { content : '\ea58'; }
&.dice-five::before { content : '\ea59'; }
&.diamonds::before { content : '\ea5a'; }
&.diamonds-card::before { content : '\ea5b'; }
&.diamond::before { content : '\ea5c'; }
&.desert-skull::before { content : '\ea5d'; }
&.dervish-swords::before { content : '\ea5e'; }
&.demolish::before { content : '\ea5f'; }
&.defibrillate::before { content : '\ea60'; }
&.decapitation::before { content : '\ea61'; }
&.death-skull::before { content : '\ea62'; }
&.dead-tree::before { content : '\ea63'; }
&.daisy::before { content : '\ea64'; }
&.daggers::before { content : '\ea65'; }
&.cycle::before { content : '\ea66'; }
&.cut-palm::before { content : '\ea67'; }
&.cubes::before { content : '\ea68'; }
&.crystals::before { content : '\ea69'; }
&.crystal-wand::before { content : '\ea6a'; }
&.crystal-cluster::before { content : '\ea6b'; }
&.crystal-ball::before { content : '\ea6c'; }
&.crush::before { content : '\ea6d'; }
&.crowned-heart::before { content : '\ea6e'; }
&.crown::before { content : '\ea6f'; }
&.crown-of-thorns::before { content : '\ea70'; }
&.crossed-swords::before { content : '\ea71'; }
&.crossed-sabres::before { content : '\ea72'; }
&.crossed-pistols::before { content : '\ea73'; }
&.crossed-bones::before { content : '\ea74'; }
&.crossed-axes::before { content : '\ea75'; }
&.crossbow::before { content : '\ea76'; }
&.croc-sword::before { content : '\ea77'; }
&.cracked-shield::before { content : '\ea78'; }
&.cracked-helm::before { content : '\ea79'; }
&.crab-claw::before { content : '\ea7a'; }
&.corked-tube::before { content : '\ea7b'; }
&.compass::before { content : '\ea7c'; }
&.cold-heart::before { content : '\ea7d'; }
&.cog::before { content : '\ea7e'; }
&.cog-wheel::before { content : '\ea7f'; }
&.coffee-mug::before { content : '\ea80'; }
&.cluster-bomb::before { content : '\ea81'; }
&.clovers::before { content : '\ea82'; }
&.clovers-card::before { content : '\ea83'; }
&.clover::before { content : '\ea84'; }
&.clockwork::before { content : '\ea85'; }
&.cloak-and-dagger::before { content : '\ea86'; }
&.circular-shield::before { content : '\ea87'; }
&.circular-saw::before { content : '\ea88'; }
&.circle-of-circles::before { content : '\ea89'; }
&.chicken-leg::before { content : '\ea8a'; }
&.chessboard::before { content : '\ea8b'; }
&.chemical-arrow::before { content : '\ea8c'; }
&.cheese::before { content : '\ea8d'; }
&.chain::before { content : '\ea8e'; }
&.cat::before { content : '\ea8f'; }
&.castle-flag::before { content : '\ea90'; }
&.castle-emblem::before { content : '\ea91'; }
&.carrot::before { content : '\ea92'; }
&.capricorn::before { content : '\ea93'; }
&.capitol::before { content : '\ea94'; }
&.cannon-shot::before { content : '\ea95'; }
&.candle::before { content : '\ea96'; }
&.candle-fire::before { content : '\ea97'; }
&.cancer::before { content : '\ea98'; }
&.cancel::before { content : '\ea99'; }
&.campfire::before { content : '\ea9a'; }
&.butterfly::before { content : '\ea9b'; }
&.burst-blob::before { content : '\ea9c'; }
&.burning-meteor::before { content : '\ea9d'; }
&.burning-eye::before { content : '\ea9e'; }
&.burning-embers::before { content : '\ea9f'; }
&.burning-book::before { content : '\eaa0'; }
&.bullets::before { content : '\eaa1'; }
&.bubbling-potion::before { content : '\eaa2'; }
&.broken-skull::before { content : '\eaa3'; }
&.broken-shield::before { content : '\eaa4'; }
&.broken-heart::before { content : '\eaa5'; }
&.broken-bottle::before { content : '\eaa6'; }
&.broken-bone::before { content : '\eaa7'; }
&.broadsword::before { content : '\eaa8'; }
&.broadhead-arrow::before { content : '\eaa9'; }
&.bridge::before { content : '\eaaa'; }
&.brandy-bottle::before { content : '\eaab'; }
&.brain-freeze::before { content : '\eaac'; }
&.bowling-pin::before { content : '\eaad'; }
&.bowie-knife::before { content : '\eaae'; }
&.bottom-right::before { content : '\eaaf'; }
&.bottled-bolt::before { content : '\eab0'; }
&.bottle-vapors::before { content : '\eab1'; }
&.boot-stomp::before { content : '\eab2'; }
&.boomerang::before { content : '\eab3'; }
&.book::before { content : '\eab4'; }
&.bone-knife::before { content : '\eab5'; }
&.bone-bite::before { content : '\eab6'; }
&.bombs::before { content : '\eab7'; }
&.bomb-explosion::before { content : '\eab8'; }
&.bolt-shield::before { content : '\eab9'; }
&.bleeding-hearts::before { content : '\eaba'; }
&.bleeding-eye::before { content : '\eabb'; }
&.blaster::before { content : '\eabc'; }
&.blast::before { content : '\eabd'; }
&.blade-bite::before { content : '\eabe'; }
&.bird-mask::before { content : '\eabf'; }
&.bird-claw::before { content : '\eac0'; }
&.biohazard::before { content : '\eac1'; }
&.bell::before { content : '\eac2'; }
&.beetle::before { content : '\eac3'; }
&.beer::before { content : '\eac4'; }
&.bear-trap::before { content : '\eac5'; }
&.beam-wake::before { content : '\eac6'; }
&.batwings::before { content : '\eac7'; }
&.battery-white::before { content : '\eac8'; }
&.battery-positive::before { content : '\eac9'; }
&.battery-negative::before { content : '\eaca'; }
&.battery-black::before { content : '\eacb'; }
&.battery-75::before { content : '\eacc'; }
&.battery-50::before { content : '\eacd'; }
&.battery-25::before { content : '\eace'; }
&.battery-100::before { content : '\eacf'; }
&.battery-0::before { content : '\ead0'; }
&.batteries::before { content : '\ead1'; }
&.battered-axe::before { content : '\ead2'; }
&.bat-sword::before { content : '\ead3'; }
&.barrier::before { content : '\ead4'; }
&.barbed-arrow::before { content : '\ead5'; }
&.ball::before { content : '\ead6'; }
&.axe::before { content : '\ead7'; }
&.axe-swing::before { content : '\ead8'; }
&.aware::before { content : '\ead9'; }
&.aura::before { content : '\eada'; }
&.arson::before { content : '\eadb'; }
&.arrow-flights::before { content : '\eadc'; }
&.arrow-cluster::before { content : '\eadd'; }
&.aries::before { content : '\eade'; }
&.arena::before { content : '\eadf'; }
&.archery-target::before { content : '\eae0'; }
&.archer::before { content : '\eae1'; }
&.arcane-mask::before { content : '\eae2'; }
&.aquarius::before { content : '\eae3'; }
&.apple::before { content : '\eae4'; }
&.anvil::before { content : '\eae5'; }
&.ankh::before { content : '\eae6'; }
&.angel-wings::before { content : '\eae7'; }
&.anchor::before { content : '\eae8'; }
&.ammo-bag::before { content : '\eae9'; }
&.alligator-clip::before { content : '\eaea'; }
&.all-for-one::before { content : '\eaeb'; }
&.alien-fire::before { content : '\eaec'; }
&.acorn::before { content : '\eaed'; }
&.acid::before { content : '\eaee'; }
}

Binary file not shown.