mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-01-27 07:23:09 +00:00
Compare commits
363 Commits
calculusch
...
pr/3585
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bd06250fc | ||
|
|
c82b62f953 | ||
|
|
4fe38e3929 | ||
|
|
b6d69173cd | ||
|
|
8b085e1806 | ||
|
|
cb9d24d5b4 | ||
|
|
23fd70e3c3 | ||
|
|
5b02132e57 | ||
|
|
f8841c068f | ||
|
|
da1d08f8a9 | ||
|
|
0a199e750f | ||
|
|
5433cda52f | ||
|
|
9c4de58161 | ||
|
|
1b96dae27f | ||
|
|
1564bc7448 | ||
|
|
8e20d3ba10 | ||
|
|
450baee66a | ||
|
|
4b588786c4 | ||
|
|
e07a04ebfa | ||
|
|
f707752c26 | ||
|
|
80e039b194 | ||
|
|
c888df28aa | ||
|
|
94cc1c642c | ||
|
|
9a02a351fa | ||
|
|
e8e7237a8e | ||
|
|
086c4f74f6 | ||
|
|
e987da498b | ||
|
|
d12f644f5b | ||
|
|
3eb071fbdc | ||
|
|
81e17b420c | ||
|
|
e8ccd094e8 | ||
|
|
7c60fbe655 | ||
|
|
2d570924d1 | ||
|
|
8ee70b0928 | ||
|
|
2cdd65b083 | ||
|
|
758a06e58a | ||
|
|
a87e420437 | ||
|
|
46085c8d44 | ||
|
|
179e21755c | ||
|
|
e9ca68e7d3 | ||
|
|
9886200fa9 | ||
|
|
9a1070bb06 | ||
|
|
3b8dbe8a04 | ||
|
|
68f95f6130 | ||
|
|
35ae5e09ee | ||
|
|
552a23585b | ||
|
|
e635877b66 | ||
|
|
954bcbdaf6 | ||
|
|
559de2527b | ||
|
|
4c14774f1a | ||
|
|
ea380ae6a9 | ||
|
|
e2a946674f | ||
|
|
75926e34a2 | ||
|
|
37bc37bd94 | ||
|
|
528359dd9f | ||
|
|
f745fdefb3 | ||
|
|
2d9b80a81e | ||
|
|
299acfb92c | ||
|
|
8fc97493c5 | ||
|
|
7c7c6341f9 | ||
|
|
227ab192c4 | ||
|
|
ad48c0cd76 | ||
|
|
958b168906 | ||
|
|
51d4b5042c | ||
|
|
371ac9680c | ||
|
|
f68af555de | ||
|
|
66fdf808a6 | ||
|
|
65770782c2 | ||
|
|
fdf6acd80a | ||
|
|
08b61a6bb4 | ||
|
|
33c2bee873 | ||
|
|
8bbf2e1ce4 | ||
|
|
476002ae4d | ||
|
|
54ec1b8827 | ||
|
|
7bb92bc790 | ||
|
|
a87d62c9c2 | ||
|
|
8c315980e9 | ||
|
|
359a64968c | ||
|
|
866548deec | ||
|
|
ed39852a8f | ||
|
|
38fc647495 | ||
|
|
fa7b3ea2a0 | ||
|
|
9e041d26bd | ||
|
|
978c0c4c7b | ||
|
|
4f4cef0f6c | ||
|
|
556ded9b08 | ||
|
|
0efcd5d258 | ||
|
|
31b6e0c4f6 | ||
|
|
423413e41b | ||
|
|
ec514cdb51 | ||
|
|
7272544724 | ||
|
|
99ff7fdf14 | ||
|
|
491b38c330 | ||
|
|
4033d3ad99 | ||
|
|
9285d355b2 | ||
|
|
24e67e2270 | ||
|
|
5f6d5f53cc | ||
|
|
865c5678bc | ||
|
|
05ba7b41d1 | ||
|
|
e7735e242a | ||
|
|
1111d8275c | ||
|
|
f3b01bc75c | ||
|
|
8685c5cae4 | ||
|
|
e0a457bf40 | ||
|
|
d20c9c502c | ||
|
|
8c5e68e571 | ||
|
|
fbe65a4e93 | ||
|
|
3875dabfd2 | ||
|
|
930709223a | ||
|
|
a6ce36689c | ||
|
|
2424d34682 | ||
|
|
8fc224e9a1 | ||
|
|
98fc007efd | ||
|
|
7fb23c7362 | ||
|
|
a2f0546a6d | ||
|
|
8a55658bd7 | ||
|
|
01d60c4520 | ||
|
|
b4349a0476 | ||
|
|
695b9916dd | ||
|
|
ac3168e365 | ||
|
|
e396211f92 | ||
|
|
4ce68b86ed | ||
|
|
24769d69d4 | ||
|
|
fc22e6cd53 | ||
|
|
62ed026757 | ||
|
|
7cef4316d7 | ||
|
|
0df53daa4c | ||
|
|
b496ef3597 | ||
|
|
3ae5d4c1e3 | ||
|
|
a227a792c0 | ||
|
|
d9d4d74b71 | ||
|
|
af82d71e4f | ||
|
|
f897cbfdf4 | ||
|
|
1773e77cb9 | ||
|
|
dcd34ccdaf | ||
|
|
2453b623db | ||
|
|
783e88b5e6 | ||
|
|
77c0af42d0 | ||
|
|
c21b4eb2d6 | ||
|
|
6043af81e4 | ||
|
|
7c3321b62f | ||
|
|
d1955951e4 | ||
|
|
e62e185214 | ||
|
|
0c38415372 | ||
|
|
73f879aa63 | ||
|
|
f12de7d953 | ||
|
|
933ac41774 | ||
|
|
54b4d490f1 | ||
|
|
193af61725 | ||
|
|
511c9ffada | ||
|
|
ea03538552 | ||
|
|
8fb9f3f823 | ||
|
|
7af919afd3 | ||
|
|
5bbe4016d6 | ||
|
|
0f3312a5d7 | ||
|
|
0bf432dd76 | ||
|
|
27b3da0144 | ||
|
|
b8b1b9660f | ||
|
|
f40d851d49 | ||
|
|
b64c835706 | ||
|
|
b7717171b3 | ||
|
|
92e27cda6c | ||
|
|
aef6605225 | ||
|
|
7c9cc25923 | ||
|
|
78ce8aa6e3 | ||
|
|
8ae22bdc27 | ||
|
|
46c14ef23b | ||
|
|
d3080c03a4 | ||
|
|
12eead3379 | ||
|
|
a2e065c5d8 | ||
|
|
0d1a3d55cf | ||
|
|
b748a597d2 | ||
|
|
5fb0e123e3 | ||
|
|
9a4a14fa97 | ||
|
|
0c76a546e4 | ||
|
|
fb299f898e | ||
|
|
afb5ccec81 | ||
|
|
c0beae6e46 | ||
|
|
9c6ece3e7f | ||
|
|
5494c02f00 | ||
|
|
b4ee62a1bd | ||
|
|
632efe8b9f | ||
|
|
bf38f95d25 | ||
|
|
f6daeb4acd | ||
|
|
10a7f34abb | ||
|
|
3a054f1ae0 | ||
|
|
25b4b3d906 | ||
|
|
f21d636846 | ||
|
|
8365841b89 | ||
|
|
e6bf8b59a1 | ||
|
|
b4a4934c5c | ||
|
|
a6b2dab9cc | ||
|
|
d692e88b96 | ||
|
|
62c9e081e6 | ||
|
|
5a52e76ff0 | ||
|
|
3b1f4a0d13 | ||
|
|
cdad9af453 | ||
|
|
5fd92ee72d | ||
|
|
5bcd3a1b01 | ||
|
|
d49d9fd755 | ||
|
|
41d817823b | ||
|
|
cfffb4961b | ||
|
|
6bd2f4d98d | ||
|
|
9d6076f642 | ||
|
|
dd82a1bebd | ||
|
|
d3f1fde9d9 | ||
|
|
d83e7bce0a | ||
|
|
8cd4a58304 | ||
|
|
0ef683222d | ||
|
|
ebbf162318 | ||
|
|
268d202562 | ||
|
|
4e0ec75e58 | ||
|
|
1af989c4a3 | ||
|
|
53480fdd5f | ||
|
|
ffa90c397c | ||
|
|
df3d1078f1 | ||
|
|
22bdb85dff | ||
|
|
2f5081156d | ||
|
|
c3f153a5fa | ||
|
|
5e0dda1bde | ||
|
|
b0379b0821 | ||
|
|
c506c9cee5 | ||
|
|
9184593bc0 | ||
|
|
1da70d54e8 | ||
|
|
55cdd016da | ||
|
|
10997898b9 | ||
|
|
76b66977e9 | ||
|
|
d695648d9b | ||
|
|
72160f5daf | ||
|
|
0751da42b6 | ||
|
|
babe1f30a2 | ||
|
|
cd35e91ea2 | ||
|
|
8d8a965241 | ||
|
|
2309887c92 | ||
|
|
d36e6e5834 | ||
|
|
dd205a14bc | ||
|
|
d854fe1202 | ||
|
|
58f487ac58 | ||
|
|
1761c506be | ||
|
|
9f19514b03 | ||
|
|
ade1056a02 | ||
|
|
e5fecaf9b6 | ||
|
|
5b8b0aa641 | ||
|
|
b7bc5cbad7 | ||
|
|
f2fc47a719 | ||
|
|
a5f9ab7897 | ||
|
|
39368c1a38 | ||
|
|
d879cf3cbb | ||
|
|
ae59c56ddd | ||
|
|
35431384bd | ||
|
|
dd31c0138b | ||
|
|
11f1e3fee8 | ||
|
|
aaaa8ed693 | ||
|
|
fec6bf290b | ||
|
|
2418e42655 | ||
|
|
dce86580ce | ||
|
|
f6997871be | ||
|
|
660a586a7c | ||
|
|
193cde0925 | ||
|
|
1a33e6e631 | ||
|
|
bb8ade435d | ||
|
|
94905f8151 | ||
|
|
05a30f00e3 | ||
|
|
3c1f8804af | ||
|
|
716e3d7143 | ||
|
|
a0e6487a7b | ||
|
|
076599f05c | ||
|
|
9fb0f37718 | ||
|
|
b86502aec7 | ||
|
|
822f8a2cd0 | ||
|
|
d2965e1122 | ||
|
|
37e211937c | ||
|
|
e7a03dc7d6 | ||
|
|
a469b88fd2 | ||
|
|
45244c8e5d | ||
|
|
fad5817353 | ||
|
|
c0a8b79acc | ||
|
|
34a41fd610 | ||
|
|
eb0440d36d | ||
|
|
cd82db16d5 | ||
|
|
bdad601ebc | ||
|
|
97a74902ef | ||
|
|
ab30b6a799 | ||
|
|
da6bc497fc | ||
|
|
06c3168868 | ||
|
|
86be90adb2 | ||
|
|
a296678d20 | ||
|
|
f768990fb1 | ||
|
|
313543d0d1 | ||
|
|
2ebe8d80e9 | ||
|
|
8c20422fef | ||
|
|
2197a9b782 | ||
|
|
928a8b351e | ||
|
|
2a148cb138 | ||
|
|
9426c6acd9 | ||
|
|
90ce48b170 | ||
|
|
448af683a0 | ||
|
|
ec5f8254f1 | ||
|
|
7ca38b88ad | ||
|
|
9f31a2c8a2 | ||
|
|
09cf5a9b04 | ||
|
|
4c6953a4e0 | ||
|
|
b4b4fbe375 | ||
|
|
4bc07ceb4e | ||
|
|
fde1706a0c | ||
|
|
1891d7c90a | ||
|
|
98d032913b | ||
|
|
80bcf92fa3 | ||
|
|
41d536b7ff | ||
|
|
1e5e3d5f41 | ||
|
|
19961c7ec5 | ||
|
|
08e273bfd6 | ||
|
|
9f45456066 | ||
|
|
6e69696b4a | ||
|
|
8b6be1cab8 | ||
|
|
93a490e881 | ||
|
|
83103a893a | ||
|
|
8cbc7a68e5 | ||
|
|
1177fd721c | ||
|
|
2c8908850b | ||
|
|
4622a74786 | ||
|
|
72cfca1158 | ||
|
|
67d824cac9 | ||
|
|
4f010d77e8 | ||
|
|
3b1f9b10e7 | ||
|
|
5e33d8b6c4 | ||
|
|
f7a2509405 | ||
|
|
52904eea09 | ||
|
|
ff84ded547 | ||
|
|
6220e4f63f | ||
|
|
b0c2521101 | ||
|
|
30d2a03fd0 | ||
|
|
61a4b558a8 | ||
|
|
3771d4bfd8 | ||
|
|
b087e849b5 | ||
|
|
963ec282d3 | ||
|
|
7690fb9287 | ||
|
|
2e54520b32 | ||
|
|
cdf5b29ac2 | ||
|
|
733b929940 | ||
|
|
211fe48e29 | ||
|
|
9d3f7fe556 | ||
|
|
5d87508d0e | ||
|
|
40d0e7e90e | ||
|
|
7ca10ff5a4 | ||
|
|
1705e66be2 | ||
|
|
1e4f804542 | ||
|
|
6a03be9d64 | ||
|
|
591278862a | ||
|
|
9848e4b600 | ||
|
|
f0a8020189 | ||
|
|
a957ea37f6 | ||
|
|
a4d426bc00 | ||
|
|
41d43e84a5 | ||
|
|
bfd3eff6f2 | ||
|
|
75c41f4466 | ||
|
|
85caf0a892 | ||
|
|
692205b0e6 | ||
|
|
02e6a3df99 | ||
|
|
b8ee696b69 | ||
|
|
26c4b1afa6 | ||
|
|
622827efda | ||
|
|
854c21639a |
10
.github/workflows/pr-check.yml
vendored
10
.github/workflows/pr-check.yml
vendored
@@ -11,14 +11,18 @@ permissions:
|
|||||||
statuses: write
|
statuses: write
|
||||||
jobs:
|
jobs:
|
||||||
limit-pull-requests:
|
limit-pull-requests:
|
||||||
if: always() && github.repository_owner == 'Homebrew'
|
if: always() && github.repository_owner == 'naturalcrit'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: Homebrew/actions/limit-pull-requests@master
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name : Run limit-pull-requests action
|
||||||
|
uses: ./.github/actions/limit-pull-requests
|
||||||
with:
|
with:
|
||||||
except-users: |
|
except-users: |
|
||||||
dependabot
|
dependabot
|
||||||
comment-limit: 1
|
comment-limit: 3
|
||||||
comment: |
|
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!
|
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
|
close-limit: 5
|
||||||
|
|||||||
49
changelog.md
49
changelog.md
@@ -84,6 +84,55 @@ pre {
|
|||||||
## changelog
|
## changelog
|
||||||
For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery).
|
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
|
### Monday 18/3/2024 - v3.12.0
|
||||||
{{taskList
|
{{taskList
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
require('./brewCleanup.less');
|
require('./brewCleanup.less');
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
const createClass = require('create-react-class');
|
const createClass = require('create-react-class');
|
||||||
const cx = require('classnames');
|
|
||||||
|
|
||||||
const request = require('superagent');
|
const request = require('superagent');
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
require('./brewCompress.less');
|
require('./brewCompress.less');
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
const createClass = require('create-react-class');
|
const createClass = require('create-react-class');
|
||||||
const cx = require('classnames');
|
|
||||||
|
|
||||||
const request = require('superagent');
|
const request = require('superagent');
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
const React = require('react');
|
const React = require('react');
|
||||||
const createClass = require('create-react-class');
|
const createClass = require('create-react-class');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const cx = require('classnames');
|
|
||||||
require('./combobox.less');
|
require('./combobox.less');
|
||||||
|
|
||||||
const Combobox = createClass({
|
const Combobox = createClass({
|
||||||
|
|||||||
29
client/components/dialog.jsx
Normal file
29
client/components/dialog.jsx
Normal 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;
|
||||||
@@ -13,6 +13,10 @@ const RenderWarnings = require('homebrewery/renderWarnings/renderWarnings.jsx');
|
|||||||
const NotificationPopup = require('./notificationPopup/notificationPopup.jsx');
|
const NotificationPopup = require('./notificationPopup/notificationPopup.jsx');
|
||||||
const Frame = require('react-frame-component').default;
|
const Frame = require('react-frame-component').default;
|
||||||
const dedent = require('dedent-tabs').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');
|
const Themes = require('themes/themes.json');
|
||||||
|
|
||||||
@@ -33,8 +37,9 @@ const BrewPage = (props)=>{
|
|||||||
index : 0,
|
index : 0,
|
||||||
...props
|
...props
|
||||||
};
|
};
|
||||||
|
const cleanText = props.contents; //DOMPurify.sanitize(props.contents, purifyConfig);
|
||||||
return <div className={props.className} id={`p${props.index + 1}`} >
|
return <div className={props.className} id={`p${props.index + 1}`} >
|
||||||
<div className='columnWrapper' dangerouslySetInnerHTML={{ __html: props.contents }} />
|
<div className='columnWrapper' dangerouslySetInnerHTML={{ __html: cleanText }} />
|
||||||
</div>;
|
</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -102,13 +107,6 @@ const BrewRenderer = (props)=>{
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const sanitizeScriptTags = (content)=>{
|
|
||||||
return content
|
|
||||||
?.replace(/<script/ig, '<script')
|
|
||||||
.replace(/<\/script>/ig, '</script>')
|
|
||||||
|| '';
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderPageInfo = ()=>{
|
const renderPageInfo = ()=>{
|
||||||
return <div className='pageInfo' ref={mainRef}>
|
return <div className='pageInfo' ref={mainRef}>
|
||||||
<div>
|
<div>
|
||||||
@@ -128,19 +126,18 @@ const BrewRenderer = (props)=>{
|
|||||||
|
|
||||||
const renderStyle = ()=>{
|
const renderStyle = ()=>{
|
||||||
if(!props.style) return;
|
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>@layer styleTab {\n${sanitizeScriptTags(props.style)}\n} </style>` }} />;
|
||||||
return <div style={{ display: 'none' }} dangerouslySetInnerHTML={{ __html: `<style> ${cleanStyle} </style>` }} />;
|
return <div style={{ display: 'none' }} dangerouslySetInnerHTML={{ __html: `<style> ${cleanStyle} </style>` }} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderPage = (pageText, index)=>{
|
const renderPage = (pageText, index)=>{
|
||||||
let cleanPageText = sanitizeScriptTags(pageText);
|
|
||||||
if(props.renderer == 'legacy') {
|
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} />;
|
return <BrewPage className='page phb' index={index} key={index} contents={html} />;
|
||||||
} else {
|
} else {
|
||||||
cleanPageText += `\n\n \n\\column\n `; //Artificial column break at page end to emulate column-fill:auto (until `wide` is used, when column-fill:balance will reappear)
|
pageText += `\n\n \n\\column\n `; //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);
|
const html = Markdown.render(pageText, index);
|
||||||
return <BrewPage className='page' index={index} key={index} contents={html} />;
|
return <BrewPage className='page' index={index} key={index} contents={html} />;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -163,6 +160,16 @@ const BrewRenderer = (props)=>{
|
|||||||
return renderedPages;
|
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"
|
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
|
setTimeout(()=>{ //We still see a flicker where the style isn't applied yet, so wait 100ms before showing iFrame
|
||||||
updateSize();
|
updateSize();
|
||||||
@@ -196,6 +203,12 @@ const BrewRenderer = (props)=>{
|
|||||||
</div>
|
</div>
|
||||||
: null}
|
: null}
|
||||||
|
|
||||||
|
<ErrorBar errors={props.errors} />
|
||||||
|
<div className='popups'>
|
||||||
|
<RenderWarnings />
|
||||||
|
<NotificationPopup />
|
||||||
|
</div>
|
||||||
|
|
||||||
{/*render in iFrame so broken code doesn't crash the site.*/}
|
{/*render in iFrame so broken code doesn't crash the site.*/}
|
||||||
<Frame id='BrewRenderer' initialContent={INITIAL_CONTENT}
|
<Frame id='BrewRenderer' initialContent={INITIAL_CONTENT}
|
||||||
style={{ width: '100%', height: '100%', visibility: state.visibility }}
|
style={{ width: '100%', height: '100%', visibility: state.visibility }}
|
||||||
@@ -204,18 +217,15 @@ const BrewRenderer = (props)=>{
|
|||||||
>
|
>
|
||||||
<div className={'brewRenderer'}
|
<div className={'brewRenderer'}
|
||||||
onScroll={handleScroll}
|
onScroll={handleScroll}
|
||||||
|
onKeyDown={handleControlKeys}
|
||||||
|
tabIndex={-1}
|
||||||
style={{ height: state.height }}>
|
style={{ height: state.height }}>
|
||||||
|
|
||||||
<ErrorBar errors={props.errors} />
|
<link href={`/themes/${rendererPath}/Blank/style.css`} type='text/css' rel='stylesheet'/>
|
||||||
<div className='popups'>
|
|
||||||
<RenderWarnings />
|
|
||||||
<NotificationPopup />
|
|
||||||
</div>
|
|
||||||
<link href={`/themes/${rendererPath}/Blank/style.css`} type="text/css" rel='stylesheet'/>
|
|
||||||
{baseThemePath &&
|
{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 */}
|
{/* Apply CSS from Style tab and render pages from Markdown tab */}
|
||||||
{state.isMounted
|
{state.isMounted
|
||||||
|
|||||||
@@ -64,3 +64,16 @@
|
|||||||
color : white;
|
color : white;
|
||||||
background-color : #333333;
|
background-color : #333333;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
.brewRenderer {
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: unset;
|
||||||
|
.pages {
|
||||||
|
margin: 0px;
|
||||||
|
&>.page {
|
||||||
|
box-shadow: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,6 @@ require('./errorBar.less');
|
|||||||
const React = require('react');
|
const React = require('react');
|
||||||
const createClass = require('create-react-class');
|
const createClass = require('create-react-class');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const cx = require('classnames');
|
|
||||||
|
|
||||||
const ErrorBar = createClass({
|
const ErrorBar = createClass({
|
||||||
displayName : 'ErrorBar',
|
displayName : 'ErrorBar',
|
||||||
|
|||||||
@@ -1,29 +1,20 @@
|
|||||||
require('./notificationPopup.less');
|
require('./notificationPopup.less');
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
const createClass = require('create-react-class');
|
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const cx = require('classnames'); //Unused variable
|
|
||||||
|
import Dialog from '../../../components/dialog.jsx';
|
||||||
|
|
||||||
const DISMISS_KEY = 'dismiss_notification12-04-23';
|
const DISMISS_KEY = 'dismiss_notification12-04-23';
|
||||||
|
const DISMISS_BUTTON = <i className='fas fa-times dismiss' />;
|
||||||
|
|
||||||
const NotificationPopup = createClass({
|
const NotificationPopup = ()=>{
|
||||||
displayName : 'NotificationPopup',
|
return <Dialog className='notificationPopup' dismissKey={DISMISS_KEY} closeText={DISMISS_BUTTON} >
|
||||||
getInitialState : function() {
|
<div className='header'>
|
||||||
return {
|
<i className='fas fa-info-circle info'></i>
|
||||||
notifications : {}
|
<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>
|
||||||
componentDidMount : function() {
|
<ul>
|
||||||
this.checkNotifications();
|
|
||||||
window.addEventListener('resize', this.checkNotifications);
|
|
||||||
},
|
|
||||||
componentWillUnmount : function() {
|
|
||||||
window.removeEventListener('resize', this.checkNotifications);
|
|
||||||
},
|
|
||||||
notifications : {
|
|
||||||
psa : function(){
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<li key='psa'>
|
<li key='psa'>
|
||||||
<em>Don't store IMAGES in Google Drive</em><br />
|
<em>Don't store IMAGES in Google Drive</em><br />
|
||||||
Google Drive is not an image service, and will block images from being used
|
Google Drive is not an image service, and will block images from being used
|
||||||
@@ -47,35 +38,8 @@ const NotificationPopup = createClass({
|
|||||||
See the FAQ
|
See the FAQ
|
||||||
</a> to learn how to avoid losing your work!
|
</a> to learn how to avoid losing your work!
|
||||||
</li>
|
</li>
|
||||||
</>
|
</ul>
|
||||||
);
|
</Dialog>;
|
||||||
}
|
};
|
||||||
},
|
|
||||||
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>;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = NotificationPopup;
|
module.exports = NotificationPopup;
|
||||||
|
|||||||
@@ -1,47 +1,45 @@
|
|||||||
.popups {
|
.popups {
|
||||||
position : fixed;
|
position : fixed;
|
||||||
top : @navbarHeight;
|
top : @navbarHeight;
|
||||||
right : 15px;
|
right : 24px;
|
||||||
z-index : 10001;
|
z-index : 10001;
|
||||||
width : 450px;
|
width : 450px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notificationPopup {
|
.notificationPopup {
|
||||||
position : relative;
|
position : relative;
|
||||||
display : inline-block;
|
|
||||||
width : 100%;
|
width : 100%;
|
||||||
padding : 15px;
|
padding : 15px;
|
||||||
padding-bottom : 10px;
|
padding-bottom : 10px;
|
||||||
padding-left : 25px;
|
padding-left : 25px;
|
||||||
background-color : @blue;
|
|
||||||
color : white;
|
color : white;
|
||||||
|
background-color : @blue;
|
||||||
|
border : none;
|
||||||
|
&[open] { display : inline-block; }
|
||||||
a {
|
a {
|
||||||
color : #e0e5c1;
|
|
||||||
font-weight : 800;
|
font-weight : 800;
|
||||||
|
color : #E0E5C1;
|
||||||
}
|
}
|
||||||
i.info {
|
i.info {
|
||||||
position : absolute;
|
position : absolute;
|
||||||
top : 12px;
|
top : 12px;
|
||||||
left : 12px;
|
left : 12px;
|
||||||
opacity : 0.8;
|
|
||||||
font-size : 2.5em;
|
font-size : 2.5em;
|
||||||
|
opacity : 0.8;
|
||||||
}
|
}
|
||||||
i.dismiss{
|
button.dismiss {
|
||||||
position : absolute;
|
position : absolute;
|
||||||
top : 10px;
|
top : 10px;
|
||||||
right : 10px;
|
right : 10px;
|
||||||
cursor : pointer;
|
cursor : pointer;
|
||||||
|
background-color : transparent;
|
||||||
opacity : 0.6;
|
opacity : 0.6;
|
||||||
&:hover{
|
&:hover { opacity : 1; }
|
||||||
opacity : 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.header {
|
|
||||||
padding-left : 50px;
|
|
||||||
}
|
}
|
||||||
|
.header { padding-left : 50px; }
|
||||||
small {
|
small {
|
||||||
opacity : 0.7;
|
|
||||||
font-size : 0.6em;
|
font-size : 0.6em;
|
||||||
|
opacity : 0.7;
|
||||||
}
|
}
|
||||||
h3 {
|
h3 {
|
||||||
font-size : 1.1em;
|
font-size : 1.1em;
|
||||||
@@ -53,12 +51,10 @@
|
|||||||
list-style-position : outside;
|
list-style-position : outside;
|
||||||
list-style-type : disc;
|
list-style-type : disc;
|
||||||
li {
|
li {
|
||||||
|
margin-top : 1.4em;
|
||||||
font-size : 0.8em;
|
font-size : 0.8em;
|
||||||
line-height : 1.4em;
|
line-height : 1.4em;
|
||||||
margin-top : 1.4em;
|
em { font-weight : 800; }
|
||||||
em{
|
|
||||||
font-weight : 800;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ const createClass = require('create-react-class');
|
|||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const cx = require('classnames');
|
const cx = require('classnames');
|
||||||
const dedent = require('dedent-tabs').default;
|
const dedent = require('dedent-tabs').default;
|
||||||
|
const Markdown = require('../../../shared/naturalcrit/markdown.js');
|
||||||
|
|
||||||
const CodeEditor = require('naturalcrit/codeEditor/codeEditor.jsx');
|
const CodeEditor = require('naturalcrit/codeEditor/codeEditor.jsx');
|
||||||
const SnippetBar = require('./snippetbar/snippetbar.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';},
|
isText : function() {return this.state.view == 'text';},
|
||||||
isStyle : function() {return this.state.view == 'style';},
|
isStyle : function() {return this.state.view == 'style';},
|
||||||
isMeta : function() {return this.state.view == 'meta';},
|
isMeta : function() {return this.state.view == 'meta';},
|
||||||
@@ -79,15 +83,15 @@ const Editor = createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
updateEditorSize : function() {
|
updateEditorSize : function() {
|
||||||
if(this.refs.codeEditor) {
|
if(this.codeEditor.current) {
|
||||||
let paneHeight = this.refs.main.parentNode.clientHeight;
|
let paneHeight = this.editor.current.parentNode.clientHeight;
|
||||||
paneHeight -= SNIPPETBAR_HEIGHT;
|
paneHeight -= SNIPPETBAR_HEIGHT;
|
||||||
this.refs.codeEditor.codeMirror.setSize(null, paneHeight);
|
this.codeEditor.current.codeMirror.setSize(null, paneHeight);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
handleInject : function(injectText){
|
handleInject : function(injectText){
|
||||||
this.refs.codeEditor?.injectText(injectText, false);
|
this.codeEditor.current?.injectText(injectText, false);
|
||||||
},
|
},
|
||||||
|
|
||||||
handleViewChange : function(newView){
|
handleViewChange : function(newView){
|
||||||
@@ -98,7 +102,7 @@ const Editor = createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
getCurrentPage : function(){
|
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)=>{
|
return _.reduce(lines, (r, line)=>{
|
||||||
if(
|
if(
|
||||||
(this.props.renderer == 'legacy' && line.indexOf('\\page') !== -1)
|
(this.props.renderer == 'legacy' && line.indexOf('\\page') !== -1)
|
||||||
@@ -110,9 +114,9 @@ const Editor = createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
highlightCustomMarkdown : function(){
|
highlightCustomMarkdown : function(){
|
||||||
if(!this.refs.codeEditor) return;
|
if(!this.codeEditor.current) return;
|
||||||
if(this.state.view === 'text') {
|
if(this.state.view === 'text') {
|
||||||
const codeMirror = this.refs.codeEditor.codeMirror;
|
const codeMirror = this.codeEditor.current.codeMirror;
|
||||||
|
|
||||||
codeMirror.operation(()=>{ // Batch CodeMirror styling
|
codeMirror.operation(()=>{ // Batch CodeMirror styling
|
||||||
//reset custom text styles
|
//reset custom text styles
|
||||||
@@ -219,6 +223,34 @@ const Editor = createClass({
|
|||||||
endCh = match.index+match[0].length;
|
endCh = match.index+match[0].length;
|
||||||
codeMirror.markText({ line: lineNumber, ch: 0 }, { line: lineNumber, ch: endCh }, { className: 'block' });
|
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.
|
targetLine = lineCount - 1; //Scroll to `\page`, which is one line back.
|
||||||
|
|
||||||
let currentY = this.refs.codeEditor.codeMirror.getScrollInfo().top;
|
let currentY = this.codeEditor.current.codeMirror.getScrollInfo().top;
|
||||||
let targetY = this.refs.codeEditor.codeMirror.heightAtLine(targetLine, 'local', true);
|
let targetY = this.codeEditor.current.codeMirror.heightAtLine(targetLine, 'local', true);
|
||||||
|
|
||||||
//Scroll 1/10 of the way every 10ms until 1px off.
|
//Scroll 1/10 of the way every 10ms until 1px off.
|
||||||
const incrementalScroll = setInterval(()=>{
|
const incrementalScroll = setInterval(()=>{
|
||||||
currentY += (targetY - currentY) / 10;
|
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
|
// Update target: target height is not accurate until within +-10 lines of the visible window
|
||||||
if(Math.abs(targetY - currentY > 100))
|
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
|
// End when close enough
|
||||||
if(Math.abs(targetY - currentY) < 1) {
|
if(Math.abs(targetY - currentY) < 1) {
|
||||||
this.refs.codeEditor.codeMirror.scrollTo(null, targetY); // Scroll any remaining difference
|
this.codeEditor.current.codeMirror.scrollTo(null, targetY); // Scroll any remaining difference
|
||||||
this.refs.codeEditor.setCursorPosition({ line: targetLine + 1, ch: 0 });
|
this.codeEditor.current.setCursorPosition({ line: targetLine + 1, ch: 0 });
|
||||||
this.refs.codeEditor.codeMirror.addLineClass(targetLine + 1, 'wrap', 'sourceMoveFlash');
|
this.codeEditor.current.codeMirror.addLineClass(targetLine + 1, 'wrap', 'sourceMoveFlash');
|
||||||
clearInterval(incrementalScroll);
|
clearInterval(incrementalScroll);
|
||||||
}
|
}
|
||||||
}, 10);
|
}, 10);
|
||||||
@@ -299,7 +331,7 @@ const Editor = createClass({
|
|||||||
|
|
||||||
//Called when there are changes to the editor's dimensions
|
//Called when there are changes to the editor's dimensions
|
||||||
update : function(){
|
update : function(){
|
||||||
this.refs.codeEditor?.updateSize();
|
this.codeEditor.current?.updateSize();
|
||||||
},
|
},
|
||||||
|
|
||||||
updateEditorTheme : function(newTheme){
|
updateEditorTheme : function(newTheme){
|
||||||
@@ -318,7 +350,7 @@ const Editor = createClass({
|
|||||||
if(this.isText()){
|
if(this.isText()){
|
||||||
return <>
|
return <>
|
||||||
<CodeEditor key='codeEditor'
|
<CodeEditor key='codeEditor'
|
||||||
ref='codeEditor'
|
ref={this.codeEditor}
|
||||||
language='gfm'
|
language='gfm'
|
||||||
view={this.state.view}
|
view={this.state.view}
|
||||||
value={this.props.brew.text}
|
value={this.props.brew.text}
|
||||||
@@ -330,12 +362,12 @@ const Editor = createClass({
|
|||||||
if(this.isStyle()){
|
if(this.isStyle()){
|
||||||
return <>
|
return <>
|
||||||
<CodeEditor key='codeEditor'
|
<CodeEditor key='codeEditor'
|
||||||
ref='codeEditor'
|
ref={this.codeEditor}
|
||||||
language='css'
|
language='css'
|
||||||
view={this.state.view}
|
view={this.state.view}
|
||||||
value={this.props.brew.style ?? DEFAULT_STYLE_TEXT}
|
value={this.props.brew.style ?? DEFAULT_STYLE_TEXT}
|
||||||
onChange={this.props.onStyleChange}
|
onChange={this.props.onStyleChange}
|
||||||
enableFolding={false}
|
enableFolding={true}
|
||||||
editorTheme={this.state.editorTheme}
|
editorTheme={this.state.editorTheme}
|
||||||
rerenderParent={this.rerenderParent} />
|
rerenderParent={this.rerenderParent} />
|
||||||
</>;
|
</>;
|
||||||
@@ -355,28 +387,28 @@ const Editor = createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
redo : function(){
|
redo : function(){
|
||||||
return this.refs.codeEditor?.redo();
|
return this.codeEditor.current?.redo();
|
||||||
},
|
},
|
||||||
|
|
||||||
historySize : function(){
|
historySize : function(){
|
||||||
return this.refs.codeEditor?.historySize();
|
return this.codeEditor.current?.historySize();
|
||||||
},
|
},
|
||||||
|
|
||||||
undo : function(){
|
undo : function(){
|
||||||
return this.refs.codeEditor?.undo();
|
return this.codeEditor.current?.undo();
|
||||||
},
|
},
|
||||||
|
|
||||||
foldCode : function(){
|
foldCode : function(){
|
||||||
return this.refs.codeEditor?.foldAllCode();
|
return this.codeEditor.current?.foldAllCode();
|
||||||
},
|
},
|
||||||
|
|
||||||
unfoldCode : function(){
|
unfoldCode : function(){
|
||||||
return this.refs.codeEditor?.unfoldAllCode();
|
return this.codeEditor.current?.unfoldAllCode();
|
||||||
},
|
},
|
||||||
|
|
||||||
render : function(){
|
render : function(){
|
||||||
return (
|
return (
|
||||||
<div className='editor' ref='main'>
|
<div className='editor' ref={this.editor}>
|
||||||
<SnippetBar
|
<SnippetBar
|
||||||
brew={this.props.brew}
|
brew={this.props.brew}
|
||||||
view={this.state.view}
|
view={this.state.view}
|
||||||
@@ -392,7 +424,7 @@ const Editor = createClass({
|
|||||||
historySize={this.historySize()}
|
historySize={this.historySize()}
|
||||||
currentEditorTheme={this.state.editorTheme}
|
currentEditorTheme={this.state.editorTheme}
|
||||||
updateEditorTheme={this.updateEditorTheme}
|
updateEditorTheme={this.updateEditorTheme}
|
||||||
cursorPos={this.refs.codeEditor?.getCursorPosition() || {}} />
|
cursorPos={this.codeEditor.current?.getCursorPosition() || {}} />
|
||||||
|
|
||||||
{this.renderEditor()}
|
{this.renderEditor()}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -43,6 +43,16 @@
|
|||||||
font-weight : bold;
|
font-weight : bold;
|
||||||
color : green;
|
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) {
|
.superscript:not(.cm-comment) {
|
||||||
font-weight : bold;
|
font-weight : bold;
|
||||||
color : goldenrod;
|
color : goldenrod;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ require('./metadataEditor.less');
|
|||||||
const React = require('react');
|
const React = require('react');
|
||||||
const createClass = require('create-react-class');
|
const createClass = require('create-react-class');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const cx = require('classnames');
|
|
||||||
const request = require('../../utils/request-middleware.js');
|
const request = require('../../utils/request-middleware.js');
|
||||||
const Nav = require('naturalcrit/nav/nav.jsx');
|
const Nav = require('naturalcrit/nav/nav.jsx');
|
||||||
const Combobox = require('client/components/combobox.jsx');
|
const Combobox = require('client/components/combobox.jsx');
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ const Snippetbar = createClass({
|
|||||||
onClick={this.props.unfoldCode} >
|
onClick={this.props.unfoldCode} >
|
||||||
<i className='fas fa-expand-alt' />
|
<i className='fas fa-expand-alt' />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ const UserPage = require('./pages/userPage/userPage.jsx');
|
|||||||
const SharePage = require('./pages/sharePage/sharePage.jsx');
|
const SharePage = require('./pages/sharePage/sharePage.jsx');
|
||||||
const NewPage = require('./pages/newPage/newPage.jsx');
|
const NewPage = require('./pages/newPage/newPage.jsx');
|
||||||
const ErrorPage = require('./pages/errorPage/errorPage.jsx');
|
const ErrorPage = require('./pages/errorPage/errorPage.jsx');
|
||||||
const PrintPage = require('./pages/printPage/printPage.jsx');
|
|
||||||
const AccountPage = require('./pages/accountPage/accountPage.jsx');
|
const AccountPage = require('./pages/accountPage/accountPage.jsx');
|
||||||
|
|
||||||
const WithRoute = (props)=>{
|
const WithRoute = (props)=>{
|
||||||
@@ -72,8 +71,6 @@ const Homebrew = createClass({
|
|||||||
<Route path='/new/:id' element={<WithRoute el={NewPage} brew={this.props.brew} />} />
|
<Route path='/new/:id' element={<WithRoute el={NewPage} brew={this.props.brew} />} />
|
||||||
<Route path='/new' element={<WithRoute el={NewPage}/>} />
|
<Route path='/new' element={<WithRoute el={NewPage}/>} />
|
||||||
<Route path='/user/:username' element={<WithRoute el={UserPage} brews={this.props.brews} />} />
|
<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='/changelog' element={<WithRoute el={SharePage} brew={this.props.brew} />} />
|
||||||
<Route path='/faq' 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='/account' element={<WithRoute el={AccountPage} brew={this.props.brew} accountDetails={this.props.brew.accountDetails} />} />
|
||||||
@@ -89,14 +86,3 @@ const Homebrew = createClass({
|
|||||||
});
|
});
|
||||||
|
|
||||||
module.exports = Homebrew;
|
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} />;
|
|
||||||
// },
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
const React = require('react');
|
const React = require('react');
|
||||||
const createClass = require('create-react-class');
|
|
||||||
const _ = require('lodash');
|
|
||||||
const dedent = require('dedent-tabs').default;
|
const dedent = require('dedent-tabs').default;
|
||||||
|
|
||||||
const Nav = require('naturalcrit/nav/nav.jsx');
|
const Nav = require('naturalcrit/nav/nav.jsx');
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
const React = require('react');
|
const React = require('react');
|
||||||
const createClass = require('create-react-class');
|
const createClass = require('create-react-class');
|
||||||
const _ = require('lodash');
|
|
||||||
const Moment = require('moment');
|
const Moment = require('moment');
|
||||||
|
|
||||||
const Nav = require('naturalcrit/nav/nav.jsx');
|
const Nav = require('naturalcrit/nav/nav.jsx');
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ const NewBrew = () => {
|
|||||||
color='purple'
|
color='purple'
|
||||||
icon='fa-solid fa-upload'
|
icon='fa-solid fa-upload'
|
||||||
onClick={()=>{ document.getElementById('uploadTxt').click(); }}>
|
onClick={()=>{ document.getElementById('uploadTxt').click(); }}>
|
||||||
<input id="uploadTxt" className='newFromLocal' type="file" onChange={handleFileChange} style={{ display: 'none' }} />
|
<input id='uploadTxt' className='newFromLocal' type='file' onChange={handleFileChange} style={{ display: 'none' }} />
|
||||||
from file
|
from file
|
||||||
</Nav.item>
|
</Nav.item>
|
||||||
</Nav.dropdown>
|
</Nav.dropdown>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
const React = require('react');
|
const React = require('react');
|
||||||
const createClass = require('create-react-class');
|
|
||||||
const Nav = require('naturalcrit/nav/nav.jsx');
|
const Nav = require('naturalcrit/nav/nav.jsx');
|
||||||
|
const { printCurrentBrew } = require('../../../shared/helpers.js');
|
||||||
|
|
||||||
module.exports = function(props){
|
module.exports = function(){
|
||||||
return <Nav.item newTab={true} href={`/print/${props.shareId}?dialog=true`} color='purple' icon='far fa-file-pdf'>
|
return <Nav.item onClick={printCurrentBrew} color='purple' icon='far fa-file-pdf'>
|
||||||
get PDF
|
get PDF
|
||||||
</Nav.item>;
|
</Nav.item>;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
const React = require('react');
|
const React = require('react');
|
||||||
const createClass = require('create-react-class');
|
const createClass = require('create-react-class');
|
||||||
const cx = require('classnames');
|
|
||||||
const Nav = require('naturalcrit/nav/nav.jsx');
|
const Nav = require('naturalcrit/nav/nav.jsx');
|
||||||
|
|
||||||
const MAX_URL_SIZE = 2083;
|
|
||||||
const MAIN_URL = 'https://www.reddit.com/r/UnearthedArcana/submit?selftext=true';
|
const MAIN_URL = 'https://www.reddit.com/r/UnearthedArcana/submit?selftext=true';
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
require('./brewItem.less');
|
require('./brewItem.less');
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
const createClass = require('create-react-class');
|
const createClass = require('create-react-class');
|
||||||
const _ = require('lodash');
|
|
||||||
const cx = require('classnames');
|
|
||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
const request = require('../../../../utils/request-middleware.js');
|
const request = require('../../../../utils/request-middleware.js');
|
||||||
|
|
||||||
|
|||||||
@@ -124,6 +124,7 @@
|
|||||||
opacity : 0.6;
|
opacity : 0.6;
|
||||||
font-size : 1.3em;
|
font-size : 1.3em;
|
||||||
color : white;
|
color : white;
|
||||||
|
text-decoration : unset;
|
||||||
&:hover{
|
&:hover{
|
||||||
opacity : 1;
|
opacity : 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -262,8 +262,8 @@ const ListPage = createClass({
|
|||||||
render : function(){
|
render : function(){
|
||||||
return <div className='listPage sitePage'>
|
return <div className='listPage sitePage'>
|
||||||
{/*<style>@layer V3_5ePHB, bundle;</style>*/}
|
{/*<style>@layer V3_5ePHB, bundle;</style>*/}
|
||||||
<link href='/themes/V3/Blank/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'/>
|
<link href='/themes/V3/5ePHB/style.css' type='text/css' rel='stylesheet'/>
|
||||||
{this.props.navItems}
|
{this.props.navItems}
|
||||||
{this.renderSortOptions()}
|
{this.renderSortOptions()}
|
||||||
{this.renderTagsOptions()}
|
{this.renderTagsOptions()}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const Navbar = require('../../navbar/navbar.jsx');
|
|||||||
|
|
||||||
const NewBrew = require('../../navbar/newbrew.navitem.jsx');
|
const NewBrew = require('../../navbar/newbrew.navitem.jsx');
|
||||||
const HelpNavItem = require('../../navbar/help.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 ErrorNavItem = require('../../navbar/error-navitem.jsx');
|
||||||
const Account = require('../../navbar/account.navitem.jsx');
|
const Account = require('../../navbar/account.navitem.jsx');
|
||||||
const RecentNavItem = require('../../navbar/recent.navitem.jsx').both;
|
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 Editor = require('../../editor/editor.jsx');
|
||||||
const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
|
const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
|
||||||
|
|
||||||
|
const LockNotification = require('./lockNotification/lockNotification.jsx');
|
||||||
|
|
||||||
const Markdown = require('naturalcrit/markdown.js');
|
const Markdown = require('naturalcrit/markdown.js');
|
||||||
|
|
||||||
const { DEFAULT_BREW_LOAD } = require('../../../../server/brewDefaults.js');
|
const { DEFAULT_BREW_LOAD } = require('../../../../server/brewDefaults.js');
|
||||||
|
const { printCurrentBrew } = require('../../../../shared/helpers.js');
|
||||||
|
|
||||||
const googleDriveIcon = require('../../googleDrive.svg');
|
const googleDriveIcon = require('../../googleDrive.svg');
|
||||||
|
|
||||||
@@ -51,9 +54,12 @@ const EditPage = createClass({
|
|||||||
autoSave : true,
|
autoSave : true,
|
||||||
autoSaveWarning : false,
|
autoSaveWarning : false,
|
||||||
unsavedTime : new Date(),
|
unsavedTime : new Date(),
|
||||||
currentEditorPage : 0
|
currentEditorPage : 0,
|
||||||
|
displayLockMessage : this.props.brew.lock || false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
editor : React.createRef(null),
|
||||||
savedBrew : null,
|
savedBrew : null,
|
||||||
|
|
||||||
componentDidMount : function(){
|
componentDidMount : function(){
|
||||||
@@ -93,7 +99,7 @@ const EditPage = createClass({
|
|||||||
const S_KEY = 83;
|
const S_KEY = 83;
|
||||||
const P_KEY = 80;
|
const P_KEY = 80;
|
||||||
if(e.keyCode == S_KEY) this.trySave(true);
|
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){
|
if(e.keyCode == P_KEY || e.keyCode == S_KEY){
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -101,7 +107,7 @@ const EditPage = createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleSplitMove : function(){
|
handleSplitMove : function(){
|
||||||
this.refs.editor.update();
|
this.editor.current.update();
|
||||||
},
|
},
|
||||||
|
|
||||||
handleTextChange : function(text){
|
handleTextChange : function(text){
|
||||||
@@ -113,7 +119,7 @@ const EditPage = createClass({
|
|||||||
brew : { ...prevState.brew, text: text },
|
brew : { ...prevState.brew, text: text },
|
||||||
isPending : true,
|
isPending : true,
|
||||||
htmlErrors : htmlErrors,
|
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();});
|
}), ()=>{if(this.state.autoSave) this.trySave();});
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -376,7 +382,7 @@ const EditPage = createClass({
|
|||||||
post to reddit
|
post to reddit
|
||||||
</Nav.item>
|
</Nav.item>
|
||||||
</Nav.dropdown>
|
</Nav.dropdown>
|
||||||
<PrintLink shareId={this.processShareId()} />
|
<PrintNavItem />
|
||||||
<RecentNavItem brew={this.state.brew} storageKey='edit' />
|
<RecentNavItem brew={this.state.brew} storageKey='edit' />
|
||||||
<Account />
|
<Account />
|
||||||
</Nav.section>
|
</Nav.section>
|
||||||
@@ -390,9 +396,10 @@ const EditPage = createClass({
|
|||||||
{this.renderNavbar()}
|
{this.renderNavbar()}
|
||||||
|
|
||||||
<div className='content'>
|
<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
|
<Editor
|
||||||
ref='editor'
|
ref={this.editor}
|
||||||
brew={this.state.brew}
|
brew={this.state.brew}
|
||||||
onTextChange={this.handleTextChange}
|
onTextChange={this.handleTextChange}
|
||||||
onStyleChange={this.handleStyleChange}
|
onStyleChange={this.handleStyleChange}
|
||||||
@@ -408,6 +415,7 @@ const EditPage = createClass({
|
|||||||
errors={this.state.htmlErrors}
|
errors={this.state.htmlErrors}
|
||||||
lang={this.state.brew.lang}
|
lang={this.state.brew.lang}
|
||||||
currentEditorPage={this.state.currentEditorPage}
|
currentEditorPage={this.state.currentEditorPage}
|
||||||
|
allowPrint={true}
|
||||||
/>
|
/>
|
||||||
</SplitPane>
|
</SplitPane>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -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; }
|
||||||
|
}
|
||||||
@@ -1,41 +1,25 @@
|
|||||||
require('./errorPage.less');
|
require('./errorPage.less');
|
||||||
const React = require('react');
|
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 UIPage = require('../basePages/uiPage/uiPage.jsx');
|
||||||
|
|
||||||
const Markdown = require('../../../../shared/naturalcrit/markdown.js');
|
const Markdown = require('../../../../shared/naturalcrit/markdown.js');
|
||||||
|
|
||||||
const ErrorIndex = require('./errors/errorIndex.js');
|
const ErrorIndex = require('./errors/errorIndex.js');
|
||||||
|
|
||||||
const ErrorPage = createClass({
|
const ErrorPage = ({ brew })=>{
|
||||||
displayName : 'ErrorPage',
|
// Retrieving the error text based on the brew's error code from ErrorIndex
|
||||||
|
const errorText = ErrorIndex({ brew })[brew.HBErrorCode.toString()] || '';
|
||||||
|
|
||||||
getDefaultProps : function() {
|
return (
|
||||||
return {
|
<UIPage brew={{ title: 'Crit Fail!' }}>
|
||||||
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!' }}>
|
|
||||||
<div className='dataGroup'>
|
<div className='dataGroup'>
|
||||||
<div className='errorTitle'>
|
<div className='errorTitle'>
|
||||||
<h1>{`Error ${this.props.brew.status || '000'}`}</h1>
|
<h1>{`Error ${brew?.status || '000'}`}</h1>
|
||||||
<h4>{this.props.brew.text || 'No error text'}</h4>
|
<h4>{brew?.text || 'No error text'}</h4>
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
<div dangerouslySetInnerHTML={{ __html: Markdown.render(errorText) }} />
|
<div dangerouslySetInnerHTML={{ __html: Markdown.render(errorText) }} />
|
||||||
</div>
|
</div>
|
||||||
</UIPage>;
|
</UIPage>
|
||||||
}
|
);
|
||||||
});
|
};
|
||||||
|
|
||||||
module.exports = ErrorPage;
|
module.exports = ErrorPage;
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ const errorIndex = (props)=>{
|
|||||||
'100' : dedent`
|
'100' : dedent`
|
||||||
## This brew has been locked.
|
## This brew has been locked.
|
||||||
|
|
||||||
Please contact the Administrators to unlock this document.
|
Only an author may request that this lock is removed.
|
||||||
|
|
||||||
:
|
:
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -37,6 +37,9 @@ const HomePage = createClass({
|
|||||||
currentEditorPage : 0
|
currentEditorPage : 0
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
editor : React.createRef(null),
|
||||||
|
|
||||||
handleSave : function(){
|
handleSave : function(){
|
||||||
request.post('/api')
|
request.post('/api')
|
||||||
.send(this.state.brew)
|
.send(this.state.brew)
|
||||||
@@ -50,12 +53,12 @@ const HomePage = createClass({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleSplitMove : function(){
|
handleSplitMove : function(){
|
||||||
this.refs.editor.update();
|
this.editor.current.update();
|
||||||
},
|
},
|
||||||
handleTextChange : function(text){
|
handleTextChange : function(text){
|
||||||
this.setState((prevState)=>({
|
this.setState((prevState)=>({
|
||||||
brew : { ...prevState.brew, text: text },
|
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(){
|
renderNavbar : function(){
|
||||||
@@ -79,9 +82,9 @@ const HomePage = createClass({
|
|||||||
{this.renderNavbar()}
|
{this.renderNavbar()}
|
||||||
|
|
||||||
<div className='content'>
|
<div className='content'>
|
||||||
<SplitPane onDragFinish={this.handleSplitMove} ref='pane'>
|
<SplitPane onDragFinish={this.handleSplitMove}>
|
||||||
<Editor
|
<Editor
|
||||||
ref='editor'
|
ref={this.editor}
|
||||||
brew={this.state.brew}
|
brew={this.state.brew}
|
||||||
onTextChange={this.handleTextChange}
|
onTextChange={this.handleTextChange}
|
||||||
renderer={this.state.brew.renderer}
|
renderer={this.state.brew.renderer}
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
require('./newPage.less');
|
require('./newPage.less');
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
const createClass = require('create-react-class');
|
const createClass = require('create-react-class');
|
||||||
const _ = require('lodash');
|
|
||||||
const request = require('../../utils/request-middleware.js');
|
const request = require('../../utils/request-middleware.js');
|
||||||
|
|
||||||
const Markdown = require('naturalcrit/markdown.js');
|
const Markdown = require('naturalcrit/markdown.js');
|
||||||
|
|
||||||
const Nav = require('naturalcrit/nav/nav.jsx');
|
const Nav = require('naturalcrit/nav/nav.jsx');
|
||||||
|
const PrintNavItem = require('../../navbar/print.navitem.jsx');
|
||||||
const Navbar = require('../../navbar/navbar.jsx');
|
const Navbar = require('../../navbar/navbar.jsx');
|
||||||
const AccountNavItem = require('../../navbar/account.navitem.jsx');
|
const AccountNavItem = require('../../navbar/account.navitem.jsx');
|
||||||
const ErrorNavItem = require('../../navbar/error-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 BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
|
||||||
|
|
||||||
const { DEFAULT_BREW } = require('../../../../server/brewDefaults.js');
|
const { DEFAULT_BREW } = require('../../../../server/brewDefaults.js');
|
||||||
|
const { printCurrentBrew } = require('../../../../shared/helpers.js');
|
||||||
|
|
||||||
const BREWKEY = 'homebrewery-new';
|
const BREWKEY = 'homebrewery-new';
|
||||||
const STYLEKEY = 'homebrewery-new-style';
|
const STYLEKEY = 'homebrewery-new-style';
|
||||||
@@ -47,6 +48,8 @@ const NewPage = createClass({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
editor : React.createRef(null),
|
||||||
|
|
||||||
componentDidMount : function() {
|
componentDidMount : function() {
|
||||||
document.addEventListener('keydown', this.handleControlKeys);
|
document.addEventListener('keydown', this.handleControlKeys);
|
||||||
|
|
||||||
@@ -88,7 +91,7 @@ const NewPage = createClass({
|
|||||||
const S_KEY = 83;
|
const S_KEY = 83;
|
||||||
const P_KEY = 80;
|
const P_KEY = 80;
|
||||||
if(e.keyCode == S_KEY) this.save();
|
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){
|
if(e.keyCode == P_KEY || e.keyCode == S_KEY){
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -96,7 +99,7 @@ const NewPage = createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleSplitMove : function(){
|
handleSplitMove : function(){
|
||||||
this.refs.editor.update();
|
this.editor.current.update();
|
||||||
},
|
},
|
||||||
|
|
||||||
handleTextChange : function(text){
|
handleTextChange : function(text){
|
||||||
@@ -107,7 +110,7 @@ const NewPage = createClass({
|
|||||||
this.setState((prevState)=>({
|
this.setState((prevState)=>({
|
||||||
brew : { ...prevState.brew, text: text },
|
brew : { ...prevState.brew, text: text },
|
||||||
htmlErrors : htmlErrors,
|
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);
|
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(){
|
renderNavbar : function(){
|
||||||
return <Navbar>
|
return <Navbar>
|
||||||
|
|
||||||
@@ -201,7 +194,7 @@ const NewPage = createClass({
|
|||||||
<ErrorNavItem error={this.state.error} parent={this}></ErrorNavItem> :
|
<ErrorNavItem error={this.state.error} parent={this}></ErrorNavItem> :
|
||||||
this.renderSaveButton()
|
this.renderSaveButton()
|
||||||
}
|
}
|
||||||
{this.renderLocalPrintButton()}
|
<PrintNavItem />
|
||||||
<HelpNavItem />
|
<HelpNavItem />
|
||||||
<RecentNavItem />
|
<RecentNavItem />
|
||||||
<AccountNavItem />
|
<AccountNavItem />
|
||||||
@@ -213,9 +206,9 @@ const NewPage = createClass({
|
|||||||
return <div className='newPage sitePage'>
|
return <div className='newPage sitePage'>
|
||||||
{this.renderNavbar()}
|
{this.renderNavbar()}
|
||||||
<div className='content'>
|
<div className='content'>
|
||||||
<SplitPane onDragFinish={this.handleSplitMove} ref='pane'>
|
<SplitPane onDragFinish={this.handleSplitMove}>
|
||||||
<Editor
|
<Editor
|
||||||
ref='editor'
|
ref={this.editor}
|
||||||
brew={this.state.brew}
|
brew={this.state.brew}
|
||||||
onTextChange={this.handleTextChange}
|
onTextChange={this.handleTextChange}
|
||||||
onStyleChange={this.handleStyleChange}
|
onStyleChange={this.handleStyleChange}
|
||||||
@@ -230,6 +223,7 @@ const NewPage = createClass({
|
|||||||
errors={this.state.htmlErrors}
|
errors={this.state.htmlErrors}
|
||||||
lang={this.state.brew.lang}
|
lang={this.state.brew.lang}
|
||||||
currentEditorPage={this.state.currentEditorPage}
|
currentEditorPage={this.state.currentEditorPage}
|
||||||
|
allowPrint={true}
|
||||||
/>
|
/>
|
||||||
</SplitPane>
|
</SplitPane>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -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 \n\\column\n `; //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;
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
.printPage{
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -6,14 +6,13 @@ const { Meta } = require('vitreum/headtags');
|
|||||||
const Nav = require('naturalcrit/nav/nav.jsx');
|
const Nav = require('naturalcrit/nav/nav.jsx');
|
||||||
const Navbar = require('../../navbar/navbar.jsx');
|
const Navbar = require('../../navbar/navbar.jsx');
|
||||||
const MetadataNav = require('../../navbar/metadata.navitem.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 RecentNavItem = require('../../navbar/recent.navitem.jsx').both;
|
||||||
const Account = require('../../navbar/account.navitem.jsx');
|
const Account = require('../../navbar/account.navitem.jsx');
|
||||||
|
|
||||||
|
|
||||||
const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
|
const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
|
||||||
|
|
||||||
const { DEFAULT_BREW_LOAD } = require('../../../../server/brewDefaults.js');
|
const { DEFAULT_BREW_LOAD } = require('../../../../server/brewDefaults.js');
|
||||||
|
const { printCurrentBrew } = require('../../../../shared/helpers.js');
|
||||||
|
|
||||||
const SharePage = createClass({
|
const SharePage = createClass({
|
||||||
displayName : 'SharePage',
|
displayName : 'SharePage',
|
||||||
@@ -35,7 +34,7 @@ const SharePage = createClass({
|
|||||||
if(!(e.ctrlKey || e.metaKey)) return;
|
if(!(e.ctrlKey || e.metaKey)) return;
|
||||||
const P_KEY = 80;
|
const P_KEY = 80;
|
||||||
if(e.keyCode == P_KEY){
|
if(e.keyCode == P_KEY){
|
||||||
window.open(`/print/${this.processShareId()}?dialog=true`, '_blank').focus();
|
if(e.keyCode == P_KEY) printCurrentBrew();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
@@ -47,6 +46,19 @@ const SharePage = createClass({
|
|||||||
this.props.brew.shareId;
|
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(){
|
render : function(){
|
||||||
return <div className='sharePage sitePage'>
|
return <div className='sharePage sitePage'>
|
||||||
<Meta name='robots' content='noindex, nofollow' />
|
<Meta name='robots' content='noindex, nofollow' />
|
||||||
@@ -59,18 +71,19 @@ const SharePage = createClass({
|
|||||||
|
|
||||||
<Nav.section>
|
<Nav.section>
|
||||||
{this.props.brew.shareId && <>
|
{this.props.brew.shareId && <>
|
||||||
<PrintLink shareId={this.processShareId()} />
|
<PrintNavItem/>
|
||||||
<Nav.dropdown>
|
<Nav.dropdown>
|
||||||
<Nav.item color='red' icon='fas fa-code'>
|
<Nav.item color='red' icon='fas fa-code'>
|
||||||
source
|
source
|
||||||
</Nav.item>
|
</Nav.item>
|
||||||
<Nav.item color='blue' href={`/source/${this.processShareId()}`}>
|
<Nav.item color='blue' icon='fas fa-eye' href={`/source/${this.processShareId()}`}>
|
||||||
view
|
view
|
||||||
</Nav.item>
|
</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
|
download
|
||||||
</Nav.item>
|
</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
|
clone to new
|
||||||
</Nav.item>
|
</Nav.item>
|
||||||
</Nav.dropdown>
|
</Nav.dropdown>
|
||||||
@@ -81,7 +94,13 @@ const SharePage = createClass({
|
|||||||
</Navbar>
|
</Navbar>
|
||||||
|
|
||||||
<div className='content'>
|
<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>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
const React = require('react');
|
const React = require('react');
|
||||||
const createClass = require('create-react-class');
|
const createClass = require('create-react-class');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const cx = require('classnames');
|
|
||||||
|
|
||||||
const ListPage = require('../basePages/listPage/listPage.jsx');
|
const ListPage = require('../basePages/listPage/listPage.jsx');
|
||||||
|
|
||||||
|
|||||||
1723
package-lock.json
generated
1723
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
41
package.json
41
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "homebrewery",
|
"name": "homebrewery",
|
||||||
"description": "Create authentic looking D&D homebrews using only markdown",
|
"description": "Create authentic looking D&D homebrews using only markdown",
|
||||||
"version": "3.12.0",
|
"version": "3.13.1",
|
||||||
"engines": {
|
"engines": {
|
||||||
"npm": "^10.2.x",
|
"npm": "^10.2.x",
|
||||||
"node": "^20.8.x"
|
"node": "^20.8.x"
|
||||||
@@ -27,11 +27,12 @@
|
|||||||
"test:dev": "jest --verbose --watch",
|
"test:dev": "jest --verbose --watch",
|
||||||
"test:basic": "jest tests/markdown/basic.test.js --verbose",
|
"test:basic": "jest tests/markdown/basic.test.js --verbose",
|
||||||
"test:variables": "jest tests/markdown/variables.test.js --verbose",
|
"test:variables": "jest tests/markdown/variables.test.js --verbose",
|
||||||
"test:mustache-syntax": "jest '.*(mustache-syntax).*' --verbose --noStackTrace",
|
"test:mustache-syntax": "jest \".*(mustache-syntax).*\" --verbose --noStackTrace",
|
||||||
"test:mustache-syntax:inline": "jest '.*(mustache-syntax).*' -t '^Inline:.*' --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:block": "jest \".*(mustache-syntax).*\" -t '^Block:.*' --verbose --noStackTrace",
|
||||||
"test:mustache-syntax:injection": "jest '.*(mustache-syntax).*' -t '^Injection:.*' --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: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",
|
"test:route": "jest tests/routes/static-pages.test.js --verbose",
|
||||||
"phb": "node scripts/phb.js",
|
"phb": "node scripts/phb.js",
|
||||||
"prod": "set NODE_ENV=production && npm run build",
|
"prod": "set NODE_ENV=production && npm run build",
|
||||||
@@ -81,17 +82,18 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.24.4",
|
"@babel/core": "^7.24.7",
|
||||||
"@babel/plugin-transform-runtime": "^7.24.3",
|
"@babel/plugin-transform-runtime": "^7.24.7",
|
||||||
"@babel/preset-env": "^7.24.4",
|
"@babel/preset-env": "^7.24.7",
|
||||||
"@babel/preset-react": "^7.24.1",
|
"@babel/preset-react": "^7.24.7",
|
||||||
"@googleapis/drive": "^8.7.0",
|
"@googleapis/drive": "^8.11.0",
|
||||||
"body-parser": "^1.20.2",
|
"body-parser": "^1.20.2",
|
||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
"codemirror": "^5.65.6",
|
"codemirror": "^5.65.6",
|
||||||
"cookie-parser": "^1.4.6",
|
"cookie-parser": "^1.4.6",
|
||||||
"create-react-class": "^15.7.0",
|
"create-react-class": "^15.7.0",
|
||||||
"dedent-tabs": "^0.10.3",
|
"dedent-tabs": "^0.10.3",
|
||||||
|
"dompurify": "^3.1.5",
|
||||||
"expr-eval": "^2.0.2",
|
"expr-eval": "^2.0.2",
|
||||||
"express": "^4.19.2",
|
"express": "^4.19.2",
|
||||||
"express-async-handler": "^1.2.0",
|
"express-async-handler": "^1.2.0",
|
||||||
@@ -102,26 +104,27 @@
|
|||||||
"less": "^3.13.1",
|
"less": "^3.13.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"marked": "11.2.0",
|
"marked": "11.2.0",
|
||||||
|
"marked-emoji": "^1.4.1",
|
||||||
"marked-extended-tables": "^1.0.8",
|
"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",
|
"marked-smartypants-lite": "^1.0.2",
|
||||||
"markedLegacy": "npm:marked@^0.3.19",
|
"markedLegacy": "npm:marked@^0.3.19",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"mongoose": "^8.3.1",
|
"mongoose": "^8.4.5",
|
||||||
"nanoid": "3.3.4",
|
"nanoid": "3.3.4",
|
||||||
"nconf": "^0.12.1",
|
"nconf": "^0.12.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.3.1",
|
||||||
"react-frame-component": "^4.1.3",
|
"react-frame-component": "^4.1.3",
|
||||||
"react-router-dom": "6.22.3",
|
"react-router-dom": "6.24.1",
|
||||||
"sanitize-filename": "1.6.3",
|
"sanitize-filename": "1.6.3",
|
||||||
"superagent": "^8.1.2",
|
"superagent": "^9.0.2",
|
||||||
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
|
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-plugin-jest": "^28.2.0",
|
"eslint-plugin-jest": "^28.6.0",
|
||||||
"eslint-plugin-react": "^7.34.1",
|
"eslint-plugin-react": "^7.34.3",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"jest-expect-message": "^1.1.3",
|
"jest-expect-message": "^1.1.3",
|
||||||
"postcss-less": "^6.0.0",
|
"postcss-less": "^6.0.0",
|
||||||
@@ -129,6 +132,6 @@
|
|||||||
"stylelint-config-recess-order": "^4.6.0",
|
"stylelint-config-recess-order": "^4.6.0",
|
||||||
"stylelint-config-recommended": "^13.0.0",
|
"stylelint-config-recommended": "^13.0.0",
|
||||||
"stylelint-stylistic": "^0.4.3",
|
"stylelint-stylistic": "^0.4.3",
|
||||||
"supertest": "^6.3.4"
|
"supertest": "^7.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
"codemirror/addon/edit/closetag.js",
|
"codemirror/addon/edit/closetag.js",
|
||||||
"codemirror/addon/edit/trailingspace.js",
|
"codemirror/addon/edit/trailingspace.js",
|
||||||
"codemirror/addon/selection/active-line.js",
|
"codemirror/addon/selection/active-line.js",
|
||||||
|
"codemirror/addon/hint/show-hint.js",
|
||||||
"moment",
|
"moment",
|
||||||
"superagent"
|
"superagent"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ DB.connect(config).then(()=>{
|
|||||||
|
|
||||||
console.log(`\n\tserver started at: ${new Date().toLocaleString()}`);
|
console.log(`\n\tserver started at: ${new Date().toLocaleString()}`);
|
||||||
console.log(`\tserver on port: ${PORT}`);
|
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`);
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const { splitTextStyleAndMetadata } = require('../shared/helpers.js');
|
|||||||
const sanitizeBrew = (brew, accessType)=>{
|
const sanitizeBrew = (brew, accessType)=>{
|
||||||
brew._id = undefined;
|
brew._id = undefined;
|
||||||
brew.__v = undefined;
|
brew.__v = undefined;
|
||||||
if(accessType !== 'edit'){
|
if(accessType !== 'edit' && accessType !== 'shareAuthor') {
|
||||||
brew.editId = undefined;
|
brew.editId = undefined;
|
||||||
}
|
}
|
||||||
return brew;
|
return brew;
|
||||||
@@ -307,7 +307,6 @@ app.get('/new/:id', asyncHandler(getBrew('share')), (req, res, next)=>{
|
|||||||
//Share Page
|
//Share Page
|
||||||
app.get('/share/:id', asyncHandler(getBrew('share')), asyncHandler(async (req, res, next)=>{
|
app.get('/share/:id', asyncHandler(getBrew('share')), asyncHandler(async (req, res, next)=>{
|
||||||
const { brew } = req;
|
const { brew } = req;
|
||||||
|
|
||||||
req.ogMeta = { ...defaultMetaTags,
|
req.ogMeta = { ...defaultMetaTags,
|
||||||
title : req.brew.title || 'Untitled Brew',
|
title : req.brew.title || 'Untitled Brew',
|
||||||
description : req.brew.description || 'No description.',
|
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 });
|
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);
|
splitTextStyleAndMetadata(req.brew);
|
||||||
return next();
|
return next();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
//Print Page
|
|
||||||
app.get('/print/:id', asyncHandler(getBrew('share')), (req, res, next)=>{
|
|
||||||
sanitizeBrew(req.brew, 'share');
|
|
||||||
splitTextStyleAndMetadata(req.brew);
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
|
|
||||||
//Account Page
|
//Account Page
|
||||||
app.get('/account', asyncHandler(async (req, res, next)=>{
|
app.get('/account', asyncHandler(async (req, res, next)=>{
|
||||||
const data = {};
|
const data = {};
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
/* eslint-disable max-lines */
|
/* eslint-disable max-lines */
|
||||||
const _ = require('lodash');
|
|
||||||
const googleDrive = require('@googleapis/drive');
|
const googleDrive = require('@googleapis/drive');
|
||||||
const { nanoid } = require('nanoid');
|
const { nanoid } = require('nanoid');
|
||||||
const token = require('./token.js');
|
const token = require('./token.js');
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ const api = {
|
|||||||
stub = stub?.toObject();
|
stub = stub?.toObject();
|
||||||
|
|
||||||
if(stub?.lock?.locked && accessType != 'edit') {
|
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
|
// If there is a google id, try to find the google brew
|
||||||
|
|||||||
@@ -300,7 +300,7 @@ describe('Tests for api', ()=>{
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('access is denied to a locked brew', async()=>{
|
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));
|
model.get = jest.fn(()=>toBrewPromise(lockBrew));
|
||||||
api.getId = jest.fn(()=>({ id: '1', googleId: undefined }));
|
api.getId = jest.fn(()=>({ id: '1', googleId: undefined }));
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,18 @@ const splitTextStyleAndMetadata = (brew) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
const printCurrentBrew = ()=>{
|
||||||
splitTextStyleAndMetadata
|
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,
|
||||||
|
printCurrentBrew
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ require('./renderWarnings.less');
|
|||||||
const React = require('react');
|
const React = require('react');
|
||||||
const createClass = require('create-react-class');
|
const createClass = require('create-react-class');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const cx = require('classnames');
|
|
||||||
|
|
||||||
const DISMISS_KEY = 'dismiss_render_warning';
|
import Dialog from '../../../client/components/dialog.jsx';
|
||||||
|
|
||||||
const RenderWarnings = createClass({
|
const RenderWarnings = createClass({
|
||||||
displayName : 'RenderWarnings',
|
displayName : 'RenderWarnings',
|
||||||
@@ -35,9 +34,6 @@ const RenderWarnings = createClass({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
checkWarnings : function(){
|
checkWarnings : function(){
|
||||||
const hideDismiss = localStorage.getItem(DISMISS_KEY);
|
|
||||||
if(hideDismiss) return this.setState({ warnings: {} });
|
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
warnings : _.reduce(this.warnings, (r, fn, type)=>{
|
warnings : _.reduce(this.warnings, (r, fn, type)=>{
|
||||||
const element = fn();
|
const element = fn();
|
||||||
@@ -46,20 +42,18 @@ const RenderWarnings = createClass({
|
|||||||
}, {})
|
}, {})
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
dismiss : function(){
|
|
||||||
localStorage.setItem(DISMISS_KEY, true);
|
|
||||||
this.checkWarnings();
|
|
||||||
},
|
|
||||||
render : function(){
|
render : function(){
|
||||||
if(_.isEmpty(this.state.warnings)) return null;
|
if(_.isEmpty(this.state.warnings)) return null;
|
||||||
|
|
||||||
return <div className='renderWarnings'>
|
const DISMISS_KEY = 'dismiss_render_warning';
|
||||||
<i className='fas fa-times dismiss' onClick={this.dismiss}/>
|
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' />
|
<i className='fas fa-exclamation-triangle ohno' />
|
||||||
<h3>Render Warnings</h3>
|
<h3>Render Warnings</h3>
|
||||||
<small>If this homebrew is rendering badly if might be because of the following:</small>
|
<small>If this homebrew is rendering badly if might be because of the following:</small>
|
||||||
<ul>{_.values(this.state.warnings)}</ul>
|
<ul>{_.values(this.state.warnings)}</ul>
|
||||||
</div>;
|
</Dialog>;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +1,34 @@
|
|||||||
.renderWarnings {
|
.renderWarnings {
|
||||||
position : relative;
|
position : relative;
|
||||||
float : right;
|
float : right;
|
||||||
display : inline-block;
|
|
||||||
width : 350px;
|
width : 350px;
|
||||||
padding : 20px;
|
padding : 20px;
|
||||||
padding-bottom : 10px;
|
padding-bottom : 10px;
|
||||||
padding-left : 85px;
|
padding-left : 85px;
|
||||||
margin-bottom : 10px;
|
margin-bottom : 10px;
|
||||||
background-color : @yellow;
|
|
||||||
color : white;
|
color : white;
|
||||||
a{
|
background-color : @yellow;
|
||||||
font-weight : 800;
|
border : none;
|
||||||
}
|
a { font-weight : 800; }
|
||||||
i.ohno {
|
i.ohno {
|
||||||
position : absolute;
|
position : absolute;
|
||||||
top : 24px;
|
top : 24px;
|
||||||
left : 24px;
|
left : 24px;
|
||||||
opacity : 0.8;
|
|
||||||
font-size : 2.5em;
|
font-size : 2.5em;
|
||||||
|
opacity : 0.8;
|
||||||
}
|
}
|
||||||
i.dismiss{
|
button.dismiss {
|
||||||
position : absolute;
|
position : absolute;
|
||||||
top : 10px;
|
top : 10px;
|
||||||
right : 10px;
|
right : 10px;
|
||||||
cursor : pointer;
|
cursor : pointer;
|
||||||
|
background-color : transparent;
|
||||||
opacity : 0.6;
|
opacity : 0.6;
|
||||||
&:hover{
|
&:hover { opacity : 1; }
|
||||||
opacity : 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
small {
|
small {
|
||||||
opacity : 0.7;
|
|
||||||
font-size : 0.6em;
|
font-size : 0.6em;
|
||||||
|
opacity : 0.7;
|
||||||
}
|
}
|
||||||
h3 {
|
h3 {
|
||||||
font-size : 1.1em;
|
font-size : 1.1em;
|
||||||
@@ -45,9 +42,7 @@
|
|||||||
li {
|
li {
|
||||||
font-size : 0.8em;
|
font-size : 0.8em;
|
||||||
line-height : 1.6em;
|
line-height : 1.6em;
|
||||||
em{
|
em { font-weight : 800; }
|
||||||
font-weight : 800;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
84
shared/naturalcrit/codeEditor/autocompleteEmoji.js
Normal file
84
shared/naturalcrit/codeEditor/autocompleteEmoji.js
Normal 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
|
||||||
|
};
|
||||||
@@ -3,8 +3,8 @@ require('./codeEditor.less');
|
|||||||
const React = require('react');
|
const React = require('react');
|
||||||
const createClass = require('create-react-class');
|
const createClass = require('create-react-class');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const cx = require('classnames');
|
|
||||||
const closeTag = require('./close-tag');
|
const closeTag = require('./close-tag');
|
||||||
|
const autoCompleteEmoji = require('./autocompleteEmoji');
|
||||||
|
|
||||||
let CodeMirror;
|
let CodeMirror;
|
||||||
if(typeof window !== 'undefined'){
|
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
|
//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/fold/xml-fold.js');
|
||||||
require('codemirror/addon/edit/closetag.js');
|
require('codemirror/addon/edit/closetag.js');
|
||||||
|
//Autocompletion
|
||||||
|
require('codemirror/addon/hint/show-hint.js');
|
||||||
|
|
||||||
const foldCode = require('./fold-code');
|
const foldPagesCode = require('./fold-pages');
|
||||||
foldCode.registerHomebreweryHelper(CodeMirror);
|
foldPagesCode.registerHomebreweryHelper(CodeMirror);
|
||||||
|
const foldCSSCode = require('./fold-css');
|
||||||
|
foldCSSCode.registerHomebreweryHelper(CodeMirror);
|
||||||
}
|
}
|
||||||
|
|
||||||
const CodeEditor = createClass({
|
const CodeEditor = createClass({
|
||||||
@@ -60,6 +64,8 @@ const CodeEditor = createClass({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
editor : React.createRef(null),
|
||||||
|
|
||||||
componentDidMount : function() {
|
componentDidMount : function() {
|
||||||
this.buildEditor();
|
this.buildEditor();
|
||||||
const newDoc = CodeMirror.Doc(this.props.value, this.props.language);
|
const newDoc = CodeMirror.Doc(this.props.value, this.props.language);
|
||||||
@@ -99,7 +105,7 @@ const CodeEditor = createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
buildEditor : function() {
|
buildEditor : function() {
|
||||||
this.codeMirror = CodeMirror(this.refs.editor, {
|
this.codeMirror = CodeMirror(this.editor.current, {
|
||||||
lineNumbers : true,
|
lineNumbers : true,
|
||||||
lineWrapping : this.props.wrap,
|
lineWrapping : this.props.wrap,
|
||||||
indentWithTabs : false,
|
indentWithTabs : false,
|
||||||
@@ -177,7 +183,10 @@ const CodeEditor = createClass({
|
|||||||
// return el;
|
// return el;
|
||||||
// }
|
// }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add custom behaviors (auto-close curlies and auto-complete emojis)
|
||||||
closeTag.autoCloseCurlyBraces(CodeMirror, this.codeMirror);
|
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.
|
// Note: codeMirror passes a copy of itself in this callback. cm === this.codeMirror. Either one works.
|
||||||
this.codeMirror.on('change', (cm)=>{this.props.onChange(cm.getValue());});
|
this.codeMirror.on('change', (cm)=>{this.props.onChange(cm.getValue());});
|
||||||
@@ -404,7 +413,7 @@ const CodeEditor = createClass({
|
|||||||
foldOptions : function(cm){
|
foldOptions : function(cm){
|
||||||
return {
|
return {
|
||||||
scanUp : true,
|
scanUp : true,
|
||||||
rangeFinder : CodeMirror.fold.homebrewery,
|
rangeFinder : this.props.language === 'css' ? CodeMirror.fold.homebrewerycss : CodeMirror.fold.homebrewery,
|
||||||
widget : (from, to)=>{
|
widget : (from, to)=>{
|
||||||
let text = '';
|
let text = '';
|
||||||
let currentLine = from.line;
|
let currentLine = from.line;
|
||||||
@@ -436,10 +445,11 @@ const CodeEditor = createClass({
|
|||||||
|
|
||||||
render : function(){
|
render : function(){
|
||||||
return <>
|
return <>
|
||||||
<link href={`../homebrew/cm-themes/${this.props.editorTheme}.css`} type="text/css" rel='stylesheet' />
|
<link href={`../homebrew/cm-themes/${this.props.editorTheme}.css`} type='text/css' rel='stylesheet' />
|
||||||
<div className='codeEditor' ref='editor' style={this.props.style}/>
|
<div className='codeEditor' ref={this.editor} style={this.props.style}/>
|
||||||
</>;
|
</>;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = CodeEditor;
|
module.exports = CodeEditor;
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,13 @@
|
|||||||
@import (less) 'codemirror/addon/fold/foldgutter.css';
|
@import (less) 'codemirror/addon/fold/foldgutter.css';
|
||||||
@import (less) 'codemirror/addon/search/matchesonscrollbar.css';
|
@import (less) 'codemirror/addon/search/matchesonscrollbar.css';
|
||||||
@import (less) 'codemirror/addon/dialog/dialog.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 {
|
@keyframes sourceMoveAnimation {
|
||||||
50% {background-color: red; color: white;}
|
50% {background-color: red; color: white;}
|
||||||
@@ -34,6 +41,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//.cm-tab {
|
//.cm-tab {
|
||||||
// background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAQAAACOs/baAAAARUlEQVR4nGJgIAG8JkXxUAcCtDWemcGR1lY4MvgzCEKY7jSBjgxBDAG09UEQzAe0AMwMHrSOAwEGRtpaMIwAAAAA//8DAG4ID9EKs6YqAAAAAElFTkSuQmCC) no-repeat right;
|
// 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;
|
||||||
|
}
|
||||||
44
shared/naturalcrit/codeEditor/fold-css.js
Normal file
44
shared/naturalcrit/codeEditor/fold-css.js
Normal 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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -4,6 +4,14 @@ const Marked = require('marked');
|
|||||||
const MarkedExtendedTables = require('marked-extended-tables');
|
const MarkedExtendedTables = require('marked-extended-tables');
|
||||||
const { markedSmartypantsLite: MarkedSmartypantsLite } = require('marked-smartypants-lite');
|
const { markedSmartypantsLite: MarkedSmartypantsLite } = require('marked-smartypants-lite');
|
||||||
const { gfmHeadingId: MarkedGFMHeadingId } = require('marked-gfm-heading-id');
|
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 MathParser = require('expr-eval').Parser;
|
||||||
const renderer = new Marked.Renderer();
|
const renderer = new Marked.Renderer();
|
||||||
const tokenizer = new Marked.Tokenizer();
|
const tokenizer = new Marked.Tokenizer();
|
||||||
@@ -50,7 +58,7 @@ renderer.html = function (html) {
|
|||||||
return 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){
|
renderer.paragraph = function(text){
|
||||||
let match;
|
let match;
|
||||||
if(text.startsWith('<div') || text.startsWith('</div'))
|
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
|
start(src) { return src.match(/{{[^{]/)?.index; }, // Hint to Marked.js to stop and check for a match
|
||||||
tokenizer(src, tokens) {
|
tokenizer(src, tokens) {
|
||||||
const completeSpan = /^{{[^\n]*}}/; // Regex for the complete token
|
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);
|
const match = completeSpan.exec(src);
|
||||||
if(match) {
|
if(match) {
|
||||||
//Find closing delimiter
|
//Find closing delimiter
|
||||||
let blockCount = 0;
|
let blockCount = 0;
|
||||||
let tags = '';
|
let tags = {};
|
||||||
let endTags = 0;
|
let endTags = 0;
|
||||||
let endToken = 0;
|
let endToken = 0;
|
||||||
let delim;
|
let delim;
|
||||||
while (delim = inlineRegex.exec(match[0])) {
|
while (delim = inlineRegex.exec(match[0])) {
|
||||||
if(!tags) {
|
if(_.isEmpty(tags)) {
|
||||||
tags = `${processStyleTags(delim[0].substring(2))}`;
|
tags = processStyleTags(delim[0].substring(2));
|
||||||
endTags = delim[0].length;
|
endTags = delim[0].length;
|
||||||
}
|
}
|
||||||
if(delim[0].startsWith('{{')) {
|
if(delim[0].startsWith('{{')) {
|
||||||
@@ -134,7 +142,14 @@ const mustacheSpans = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
renderer(token) {
|
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
|
start(src) { return src.match(/\n *{{[^{]/m)?.index; }, // Hint to Marked.js to stop and check for a match
|
||||||
tokenizer(src, tokens) {
|
tokenizer(src, tokens) {
|
||||||
const completeBlock = /^ *{{[^\n}]* *\n.*\n *}}/s; // Regex for the complete token
|
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);
|
const match = completeBlock.exec(src);
|
||||||
if(match) {
|
if(match) {
|
||||||
//Find closing delimiter
|
//Find closing delimiter
|
||||||
let blockCount = 0;
|
let blockCount = 0;
|
||||||
let tags = '';
|
let tags = {};
|
||||||
let endTags = 0;
|
let endTags = 0;
|
||||||
let endToken = 0;
|
let endToken = 0;
|
||||||
let delim;
|
let delim;
|
||||||
while (delim = blockRegex.exec(match[0])?.[0].trim()) {
|
while (delim = blockRegex.exec(match[0])?.[0].trim()) {
|
||||||
if(!tags) {
|
if(_.isEmpty(tags)) {
|
||||||
tags = `${processStyleTags(delim.substring(2))}`;
|
tags = processStyleTags(delim.substring(2));
|
||||||
endTags = delim.length + src.indexOf(delim);
|
endTags = delim.length + src.indexOf(delim);
|
||||||
}
|
}
|
||||||
if(delim.startsWith('{{')) {
|
if(delim.startsWith('{{')) {
|
||||||
@@ -183,7 +198,14 @@ const mustacheDivs = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
renderer(token) {
|
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',
|
level : 'inline',
|
||||||
start(src) { return src.match(/ *{[^{\n]/)?.index; }, // Hint to Marked.js to stop and check for a match
|
start(src) { return src.match(/ *{[^{\n]/)?.index; }, // Hint to Marked.js to stop and check for a match
|
||||||
tokenizer(src, tokens) {
|
tokenizer(src, tokens) {
|
||||||
const inlineRegex = /^ *{(?=((?:[:=](?:"['\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"=':{}\s]*)*))\1}/g;
|
const inlineRegex = /^ *{(?=((?:[:=](?:"['\w,\-()#%=?. ]*"|[\w\-()#%.]*)|[^"=':{}\s]*)*))\1}/g;
|
||||||
const match = inlineRegex.exec(src);
|
const match = inlineRegex.exec(src);
|
||||||
if(match) {
|
if(match) {
|
||||||
const lastToken = tokens[tokens.length - 1];
|
const lastToken = tokens[tokens.length - 1];
|
||||||
if(!lastToken || lastToken.type == 'mustacheInjectInline')
|
if(!lastToken || lastToken.type == 'mustacheInjectInline')
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const tags = `${processStyleTags(match[1])}`;
|
const tags = processStyleTags(match[1]);
|
||||||
lastToken.originalType = lastToken.type;
|
lastToken.originalType = lastToken.type;
|
||||||
lastToken.type = 'mustacheInjectInline';
|
lastToken.type = 'mustacheInjectInline';
|
||||||
lastToken.tags = tags;
|
lastToken.injectedTags = tags;
|
||||||
return {
|
return {
|
||||||
type : 'text', // Should match "name" above
|
type : 'mustacheInjectInline', // Should match "name" above
|
||||||
raw : match[0], // Text to consume from the source
|
raw : match[0], // Text to consume from the source
|
||||||
text : ''
|
text : ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
renderer(token) {
|
renderer(token) {
|
||||||
|
if(!token.originalType){
|
||||||
|
return;
|
||||||
|
}
|
||||||
token.type = token.originalType;
|
token.type = token.originalType;
|
||||||
const text = this.parser.parseInline([token]);
|
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) {
|
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;
|
return text;
|
||||||
}
|
}
|
||||||
@@ -227,7 +265,7 @@ const mustacheInjectBlock = {
|
|||||||
level : 'block',
|
level : 'block',
|
||||||
start(src) { return src.match(/\n *{[^{\n]/m)?.index; }, // Hint to Marked.js to stop and check for a match
|
start(src) { return src.match(/\n *{[^{\n]/m)?.index; }, // Hint to Marked.js to stop and check for a match
|
||||||
tokenizer(src, tokens) {
|
tokenizer(src, tokens) {
|
||||||
const inlineRegex = /^ *{(?=((?:[:=](?:"['\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"=':{}\s]*)*))\1}/ym;
|
const inlineRegex = /^ *{(?=((?:[:=](?:"['\w,\-()#%=?. ]*"|[\w\-()#%.]*)|[^"=':{}\s]*)*))\1}/ym;
|
||||||
const match = inlineRegex.exec(src);
|
const match = inlineRegex.exec(src);
|
||||||
if(match) {
|
if(match) {
|
||||||
const lastToken = tokens[tokens.length - 1];
|
const lastToken = tokens[tokens.length - 1];
|
||||||
@@ -235,7 +273,7 @@ const mustacheInjectBlock = {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
lastToken.originalType = 'mustacheInjectBlock';
|
lastToken.originalType = 'mustacheInjectBlock';
|
||||||
lastToken.tags = `${processStyleTags(match[1])}`;
|
lastToken.injectedTags = processStyleTags(match[1]);
|
||||||
return {
|
return {
|
||||||
type : 'mustacheInjectBlock', // Should match "name" above
|
type : 'mustacheInjectBlock', // Should match "name" above
|
||||||
raw : match[0], // Text to consume from the source
|
raw : match[0], // Text to consume from the source
|
||||||
@@ -249,9 +287,22 @@ const mustacheInjectBlock = {
|
|||||||
}
|
}
|
||||||
token.type = token.originalType;
|
token.type = token.originalType;
|
||||||
const text = this.parser.parse([token]);
|
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) {
|
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;
|
return text;
|
||||||
}
|
}
|
||||||
@@ -304,10 +355,19 @@ const definitionListsSingleLine = {
|
|||||||
let endIndex = 0;
|
let endIndex = 0;
|
||||||
const definitions = [];
|
const definitions = [];
|
||||||
while (match = regex.exec(src)) {
|
while (match = regex.exec(src)) {
|
||||||
|
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({
|
definitions.push({
|
||||||
dt : this.lexer.inlineTokens(match[1].trim()),
|
dt : this.lexer.inlineTokens(originalLine.slice(0, newMatch[1].length).trim()),
|
||||||
dd : this.lexer.inlineTokens(match[2].trim())
|
dd : this.lexer.inlineTokens(originalLine.slice(newMatch[1].length + 2).trim())
|
||||||
});
|
});
|
||||||
|
} // End of emoji hack.
|
||||||
endIndex = regex.lastIndex;
|
endIndex = regex.lastIndex;
|
||||||
}
|
}
|
||||||
if(definitions.length) {
|
if(definitions.length) {
|
||||||
@@ -616,11 +676,30 @@ function MarkedVariables() {
|
|||||||
};
|
};
|
||||||
//^=====--------------------< Variable Handling >-------------------=====^//
|
//^=====--------------------< 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(MarkedVariables());
|
||||||
Marked.use({ extensions: [definitionListsMultiLine, definitionListsSingleLine, superSubScripts, mustacheSpans, mustacheDivs, mustacheInjectInline] });
|
Marked.use({ extensions: [definitionListsMultiLine, definitionListsSingleLine, superSubScripts, mustacheSpans, mustacheDivs, mustacheInjectInline] });
|
||||||
Marked.use(mustacheInjectBlock);
|
Marked.use(mustacheInjectBlock);
|
||||||
Marked.use({ renderer: renderer, tokenizer: tokenizer, mangle: false });
|
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 nonWordAndColonTest = /[^\w:]/g;
|
||||||
const cleanUrl = function (sanitize, base, href) {
|
const cleanUrl = function (sanitize, base, href) {
|
||||||
@@ -687,15 +766,49 @@ const processStyleTags = (string)=>{
|
|||||||
//TODO: can we simplify to just split on commas?
|
//TODO: can we simplify to just split on commas?
|
||||||
const tags = string.match(/(?:[^, ":=]+|[:=](?:"[^"]*"|))+/g);
|
const tags = string.match(/(?:[^, ":=]+|[:=](?:"[^"]*"|))+/g);
|
||||||
|
|
||||||
const id = _.remove(tags, (tag)=>tag.startsWith('#')).map((tag)=>tag.slice(1))[0];
|
const id = _.remove(tags, (tag)=>tag.startsWith('#')).map((tag)=>tag.slice(1))[0] || null;
|
||||||
const classes = _.remove(tags, (tag)=>(!tag.includes(':')) && (!tag.includes('=')));
|
const classes = _.remove(tags, (tag)=>(!tag.includes(':')) && (!tag.includes('='))).join(' ') || null;
|
||||||
const attributes = _.remove(tags, (tag)=>(tag.includes('='))).map((tag)=>tag.replace(/="?([^"]*)"?/g, '="$1"'));
|
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()) : [];
|
?.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(' ')}` : ''}"` +
|
return {
|
||||||
`${id ? ` id="${id}"` : ''}` +
|
id : id,
|
||||||
`${styles?.length ? ` style="${styles.join(' ')}"` : ''}` +
|
classes : classes,
|
||||||
`${attributes?.length ? ` ${attributes.join(' ')}` : ''}`;
|
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 = {};
|
const globalVarsList = {};
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ const Nav = {
|
|||||||
color : null
|
color : null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
handleClick : function(){
|
handleClick : function(e){
|
||||||
this.props.onClick();
|
this.props.onClick(e);
|
||||||
},
|
},
|
||||||
render : function(){
|
render : function(){
|
||||||
const classes = cx('navItem', this.props.color, this.props.className);
|
const classes = cx('navItem', this.props.color, this.props.className);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
require('./splitPane.less');
|
require('./splitPane.less');
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
const createClass = require('create-react-class');
|
const createClass = require('create-react-class');
|
||||||
const _ = require('lodash');
|
|
||||||
const cx = require('classnames');
|
const cx = require('classnames');
|
||||||
|
|
||||||
const SplitPane = createClass({
|
const SplitPane = createClass({
|
||||||
@@ -24,6 +23,9 @@ const SplitPane = createClass({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
pane1 : React.createRef(null),
|
||||||
|
pane2 : React.createRef(null),
|
||||||
|
|
||||||
componentDidMount : function() {
|
componentDidMount : function() {
|
||||||
const dividerPos = window.localStorage.getItem(this.props.storageKey);
|
const dividerPos = window.localStorage.getItem(this.props.storageKey);
|
||||||
if(dividerPos){
|
if(dividerPos){
|
||||||
@@ -137,7 +139,6 @@ const SplitPane = createClass({
|
|||||||
render : function(){
|
render : function(){
|
||||||
return <div className='splitPane' onPointerMove={this.handleMove} onPointerUp={this.handleUp}>
|
return <div className='splitPane' onPointerMove={this.handleMove} onPointerUp={this.handleUp}>
|
||||||
<Pane
|
<Pane
|
||||||
ref='pane1'
|
|
||||||
width={this.state.currentDividerPos}
|
width={this.state.currentDividerPos}
|
||||||
>
|
>
|
||||||
{React.cloneElement(this.props.children[0], {
|
{React.cloneElement(this.props.children[0], {
|
||||||
@@ -147,7 +148,7 @@ const SplitPane = createClass({
|
|||||||
})}
|
})}
|
||||||
</Pane>
|
</Pane>
|
||||||
{this.renderDivider()}
|
{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>;
|
</div>;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
58
tests/markdown/emojis.test.js
Normal file
58
tests/markdown/emojis.test.js
Normal 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
|
||||||
|
});
|
||||||
@@ -243,118 +243,212 @@ describe(`Block: When using the Block syntax {{tags\\ntext\\n}}`, ()=>{
|
|||||||
describe('Injection: When an injection tag follows an element', ()=>{
|
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.
|
// 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', ()=>{
|
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 source = '{{ text}}{}';
|
||||||
const rendered = Markdown.render(source);
|
const rendered = Markdown.render(source);
|
||||||
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block">text</span>');
|
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 source = '{{ text}}{ClassName}';
|
||||||
const rendered = Markdown.render(source);
|
const rendered = Markdown.render(source);
|
||||||
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block ClassName">text</span>');
|
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 source = '{{ text}}{a="b and c"}';
|
||||||
const rendered = Markdown.render(source);
|
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 source = '{{ text}}{color:red}';
|
||||||
const rendered = Markdown.render(source);
|
const rendered = Markdown.render(source);
|
||||||
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block" style="color:red;">text</span>');
|
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 source = `{{ text}}{--stringVariable:"'string'"}`;
|
||||||
const rendered = Markdown.render(source);
|
const rendered = Markdown.render(source);
|
||||||
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<span class="inline-block" style="--stringVariable:'string';">text</span>`);
|
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 source = '{{ text}}{color:red,background:blue}';
|
||||||
const rendered = Markdown.render(source);
|
const rendered = Markdown.render(source);
|
||||||
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block" style="color:red; background:blue;">text</span>');
|
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 source = '*emphasis*{big}';
|
||||||
const rendered = Markdown.render(source).trimReturns();
|
const rendered = Markdown.render(source).trimReturns();
|
||||||
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<p><em class="big">emphasis</em></p>');
|
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 source = '`code`{background:gray}';
|
||||||
const rendered = Markdown.render(source).trimReturns();
|
const rendered = Markdown.render(source).trimReturns();
|
||||||
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<p><code style="background:gray;">code</code></p>');
|
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 = '{position:absolute}';
|
const source = '{position:absolute}';
|
||||||
const rendered = Markdown.render(source).trimReturns();
|
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 source = '{{ text}}{color:red}{background:blue}';
|
||||||
const rendered = Markdown.render(source).trimReturns();
|
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>');
|
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() {
|
it('Renders an image with added attributes', function() {
|
||||||
const source = ` {position:absolute,bottom:20px,left:130px,width:220px,a="b and c",d=e}`;
|
const source = ` {position:absolute,bottom:20px,left:130px,width:220px,a="b and c",d=e}`;
|
||||||
const rendered = Markdown.render(source).trimReturns();
|
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 = ` {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 = ` {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', ()=>{
|
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 source = '{{\ntext\n}}\n{}';
|
||||||
const rendered = Markdown.render(source).trimReturns();
|
const rendered = Markdown.render(source).trimReturns();
|
||||||
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<div class="block"><p>text</p></div>');
|
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 source = '{{\ntext\n}}\n{ClassName}';
|
||||||
const rendered = Markdown.render(source).trimReturns();
|
const rendered = Markdown.render(source).trimReturns();
|
||||||
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<div class="block ClassName"><p>text</p></div>');
|
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 source = '{{\ntext\n}}\n{color:red}';
|
||||||
const rendered = Markdown.render(source).trimReturns();
|
const rendered = Markdown.render(source).trimReturns();
|
||||||
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<div class="block" style="color:red;"><p>text</p></div>');
|
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`{{
|
const source = dedent`{{
|
||||||
text
|
text
|
||||||
}}
|
}}
|
||||||
{color:red,background:blue}`;
|
{color:red,background:blue}`;
|
||||||
const rendered = Markdown.render(source).trimReturns();
|
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`{{
|
const source = dedent`{{
|
||||||
text
|
text
|
||||||
}}
|
}}
|
||||||
{--stringVariable:"'string'"}`;
|
{--stringVariable:"'string'"}`;
|
||||||
const rendered = Markdown.render(source).trimReturns();
|
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
|
const source = dedent`## text
|
||||||
{ClassName}`;
|
{ClassName}`;
|
||||||
const rendered = Markdown.render(source).trimReturns();
|
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 |
|
const source = dedent`| Experience Points | Level |
|
||||||
|:------------------|:-----:|
|
|:------------------|:-----:|
|
||||||
| 0 | 1 |
|
| 0 | 1 |
|
||||||
@@ -376,15 +470,15 @@ 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>
|
// 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
|
const source = dedent`## text
|
||||||
{ClassName}
|
{ClassName}
|
||||||
{secondInjection}`;
|
{secondInjection}`;
|
||||||
const rendered = Markdown.render(source).trimReturns();
|
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`{{
|
const source = dedent`{{
|
||||||
outer text
|
outer text
|
||||||
{{
|
{{
|
||||||
|
|||||||
@@ -329,7 +329,7 @@ describe('Normal Links and Images', ()=>{
|
|||||||
const source = `{width:100px}`;
|
const source = `{width:100px}`;
|
||||||
const rendered = Markdown.render(source).trimReturns();
|
const rendered = Markdown.render(source).trimReturns();
|
||||||
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(dedent`
|
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() {
|
it('Renders normal links', function() {
|
||||||
|
|||||||
@@ -23,7 +23,41 @@ module.exports = [
|
|||||||
{
|
{
|
||||||
name : 'Table of Contents',
|
name : 'Table of Contents',
|
||||||
icon : 'fas fa-book',
|
icon : 'fas fa-book',
|
||||||
gen : TableOfContentsGen
|
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',
|
name : 'Index',
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ module.exports = {
|
|||||||
**Condition Immunities** :: ${genList(['groggy', 'swagged', 'weak-kneed', 'buzzed', 'groovy', 'melancholy', 'drunk'], 3)}
|
**Condition Immunities** :: ${genList(['groggy', 'swagged', 'weak-kneed', 'buzzed', 'groovy', 'melancholy', 'drunk'], 3)}
|
||||||
**Senses** :: darkvision 60 ft., passive Perception ${_.random(3, 20)}
|
**Senses** :: darkvision 60 ft., passive Perception ${_.random(3, 20)}
|
||||||
**Languages** :: ${genList(['Common', 'Pottymouth', 'Gibberish', 'Latin', 'Jive'], 2)}
|
**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')}
|
${_.times(_.random(genLines, genLines + 2), function(){return genAbilities();}).join('\n:\n')}
|
||||||
:
|
:
|
||||||
|
|||||||
@@ -1,43 +1,43 @@
|
|||||||
const _ = require("lodash");
|
const _ = require('lodash');
|
||||||
|
|
||||||
const quotes = [
|
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 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 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 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 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 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 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 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 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 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 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 = [
|
const authors = [
|
||||||
"Unknown",
|
'Unknown',
|
||||||
"James Wyatt",
|
'James Wyatt',
|
||||||
"Eolande Blackwood",
|
'Eolande Blackwood',
|
||||||
"Ragnar Ironheart",
|
'Ragnar Ironheart',
|
||||||
"Lyra Nightshade",
|
'Lyra Nightshade',
|
||||||
"Valtorius Darkstar",
|
'Valtorius Darkstar',
|
||||||
"Isadora Fireheart",
|
'Isadora Fireheart',
|
||||||
"Theron Shadowbane",
|
'Theron Shadowbane',
|
||||||
"Lirien Starweaver",
|
'Lirien Starweaver',
|
||||||
"Drogathar Bonecrusher",
|
'Drogathar Bonecrusher',
|
||||||
"Kaelen Frostblade",
|
'Kaelen Frostblade',
|
||||||
];
|
];
|
||||||
|
|
||||||
const books = [
|
const books = [
|
||||||
"The Blade of Destiny",
|
'The Blade of Destiny',
|
||||||
"Dragonfire and Steel",
|
'Dragonfire and Steel',
|
||||||
"The Bard's Tale",
|
'The Bard\'s Tale',
|
||||||
"Darkness Rising",
|
'Darkness Rising',
|
||||||
"The Sacred Quest",
|
'The Sacred Quest',
|
||||||
"Shadows in the Forest",
|
'Shadows in the Forest',
|
||||||
"The Starweaver Chronicles",
|
'The Starweaver Chronicles',
|
||||||
"Beneath the Bones",
|
'Beneath the Bones',
|
||||||
"Moonlit Magic",
|
'Moonlit Magic',
|
||||||
"Frost and Fury",
|
'Frost and Fury',
|
||||||
|
|
||||||
];
|
];
|
||||||
module.exports = ()=>{
|
module.exports = ()=>{
|
||||||
|
|||||||
@@ -2,77 +2,68 @@ const _ = require('lodash');
|
|||||||
const dedent = require('dedent-tabs').default;
|
const dedent = require('dedent-tabs').default;
|
||||||
|
|
||||||
const getTOC = (pages)=>{
|
const getTOC = (pages)=>{
|
||||||
const add1 = (title, page)=>{
|
|
||||||
res.push({
|
const recursiveAdd = (title, page, targetDepth, child, curDepth=0)=>{
|
||||||
|
if(curDepth > 5) return; // Something went wrong.
|
||||||
|
if(curDepth == targetDepth) {
|
||||||
|
child.push({
|
||||||
title : title,
|
title : title,
|
||||||
page : page + 1,
|
page : page,
|
||||||
children : []
|
children : []
|
||||||
});
|
});
|
||||||
};
|
} else {
|
||||||
const add2 = (title, page)=>{
|
if(child.length == 0) {
|
||||||
if(!_.last(res)) add1(null, page);
|
child.push({
|
||||||
_.last(res).children.push({
|
title : null,
|
||||||
title : title,
|
page : page,
|
||||||
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 : []
|
children : []
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
recursiveAdd(title, page, targetDepth, _.last(child).children, curDepth+1,);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = [];
|
const res = [];
|
||||||
_.each(pages, (page, pageNum)=>{
|
|
||||||
if(!page.includes("{{frontCover}}") && !page.includes("{{insideCover}}") && !page.includes("{{partCover}}") && !page.includes("{{backCover}}")) {
|
const iframe = document.getElementById('BrewRenderer');
|
||||||
const lines = page.split('\n');
|
const iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
|
||||||
_.each(lines, (line)=>{
|
const headings = iframeDocument.querySelectorAll('h1, h2, h3, h4, h5, h6');
|
||||||
if(_.startsWith(line, '# ')){
|
const headerDepth = ['H1', 'H2', 'H3', 'H4', 'H5', 'H6'];
|
||||||
const title = line.replace('# ', '');
|
|
||||||
add1(title, pageNum);
|
_.each(headings, (heading)=>{
|
||||||
}
|
const onPage = parseInt(heading.closest('.page').id?.replace(/^p/, ''));
|
||||||
if(_.startsWith(line, '## ')){
|
const ToCExclude = getComputedStyle(heading).getPropertyValue('--TOC');
|
||||||
const title = line.replace('## ', '');
|
|
||||||
add2(title, pageNum);
|
if(ToCExclude != 'exclude') {
|
||||||
}
|
recursiveAdd(heading.innerText.trim(), onPage, headerDepth.indexOf(heading.tagName), res);
|
||||||
if(_.startsWith(line, '### ')){
|
|
||||||
const title = line.replace('### ', '');
|
|
||||||
add3(title, pageNum);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return 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){
|
module.exports = function(props){
|
||||||
const pages = props.brew.text.split('\\page');
|
const pages = props.brew.text.split('\\page');
|
||||||
const TOC = getTOC(pages);
|
const TOC = getTOC(pages);
|
||||||
const markdown = _.reduce(TOC, (r, g1, idx1)=>{
|
const markdown = _.reduce(TOC, (r, g1, idx1)=>{
|
||||||
if(g1.title !== null) {
|
r.push(ToCIterate(g1).join('\n'));
|
||||||
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})`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return r;
|
return r;
|
||||||
}, []).join('\n');
|
}, []).join('\n');
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
@import (less) './themes/assets/assets.less';
|
@import (less) './themes/assets/assets.less';
|
||||||
@import (less) './themes/fonts/icon fonts/font-icons.less';
|
|
||||||
@import (less) './themes/fonts/icon fonts/diceFont.less';
|
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
//Colors
|
//Colors
|
||||||
@@ -356,6 +354,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bonus {
|
||||||
|
float: right;
|
||||||
|
padding-right: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
// Monster Ability table
|
// Monster Ability table
|
||||||
hr + table:first-of-type {
|
hr + table:first-of-type {
|
||||||
margin : 0;
|
margin : 0;
|
||||||
@@ -543,10 +546,8 @@
|
|||||||
color : white;
|
color : white;
|
||||||
text-shadow : unset;
|
text-shadow : unset;
|
||||||
text-transform : uppercase;
|
text-transform : uppercase;
|
||||||
filter : drop-shadow(0 0 1.5px black) drop-shadow(0 0 0 black)
|
-webkit-text-stroke: 0.2cm black;
|
||||||
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black)
|
paint-order:stroke;
|
||||||
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black)
|
|
||||||
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black);
|
|
||||||
}
|
}
|
||||||
h2 {
|
h2 {
|
||||||
font-family : 'NodestoCapsCondensed';
|
font-family : 'NodestoCapsCondensed';
|
||||||
@@ -554,10 +555,8 @@
|
|||||||
font-weight : normal;
|
font-weight : normal;
|
||||||
color : white;
|
color : white;
|
||||||
letter-spacing : 0.1cm;
|
letter-spacing : 0.1cm;
|
||||||
filter : drop-shadow(0 0 1px black) drop-shadow(0 0 0 black)
|
-webkit-text-stroke: 0.14cm black;
|
||||||
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black)
|
paint-order:stroke;
|
||||||
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black)
|
|
||||||
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black);
|
|
||||||
}
|
}
|
||||||
hr {
|
hr {
|
||||||
position : relative;
|
position : relative;
|
||||||
@@ -603,10 +602,8 @@
|
|||||||
font-size : 0.496cm;
|
font-size : 0.496cm;
|
||||||
color : white;
|
color : white;
|
||||||
text-align : center;
|
text-align : center;
|
||||||
filter : drop-shadow(0 0 0.7px black) drop-shadow(0 0 0 black)
|
-webkit-text-stroke: 0.1cm black;
|
||||||
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black)
|
paint-order:stroke;
|
||||||
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black)
|
|
||||||
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black);
|
|
||||||
}
|
}
|
||||||
.logo {
|
.logo {
|
||||||
position : absolute;
|
position : absolute;
|
||||||
@@ -789,6 +786,39 @@
|
|||||||
// *****************************
|
// *****************************
|
||||||
// * TABLE OF CONTENTS
|
// * 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 {
|
.page {
|
||||||
&:has(.toc)::after { display : none; }
|
&:has(.toc)::after { display : none; }
|
||||||
.toc {
|
.toc {
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
@import (less) './themes/fonts/5e/fonts.less';
|
@import (less) './themes/fonts/5e/fonts.less';
|
||||||
@import (less) './themes/assets/assets.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 {
|
:root {
|
||||||
//Colors
|
//Colors
|
||||||
|
|||||||
@@ -58,7 +58,7 @@
|
|||||||
background-color: rgba(35,153,153,0.5);
|
background-color: rgba(35,153,153,0.5);
|
||||||
}
|
}
|
||||||
.pageLine {
|
.pageLine {
|
||||||
background-color: rgba(255,255,255,0.75);
|
background-color: rgba(255,255,255,0.5);
|
||||||
& ~ pre.CodeMirror-line {
|
& ~ pre.CodeMirror-line {
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,8 +74,9 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: SolberaImitationRemake; //Tweaked 5e version
|
font-family: SolberaImitationRemake; //Tweaked 5e version
|
||||||
src: url('../../../fonts/5e/Solbera Imitation Tweak.woff2');
|
src: url('../../../fonts/5e/Solbera Imitation Tweak.woff2');
|
||||||
font-weight: normal;
|
font-weight: 100 1000;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cover Page */
|
/* Cover Page */
|
||||||
|
|||||||
@@ -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'; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
96
themes/fonts/iconFonts/diceFont.js
Normal file
96
themes/fonts/iconFonts/diceFont.js
Normal 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;
|
||||||
@@ -3,11 +3,11 @@
|
|||||||
font-family : 'DiceFont';
|
font-family : 'DiceFont';
|
||||||
font-style : normal;
|
font-style : normal;
|
||||||
font-weight : normal;
|
font-weight : normal;
|
||||||
src : url('../../../fonts/icon fonts/diceFont.woff2');
|
src : url('../../../fonts/iconFonts/diceFont.woff2');
|
||||||
}
|
}
|
||||||
|
|
||||||
.df {
|
.df {
|
||||||
display : inline-block;
|
display : inline;
|
||||||
font-family : 'DiceFont';
|
font-family : 'DiceFont';
|
||||||
font-style : normal;
|
font-style : normal;
|
||||||
font-weight : normal;
|
font-weight : normal;
|
||||||
@@ -16,8 +16,11 @@
|
|||||||
text-decoration : inherit;
|
text-decoration : inherit;
|
||||||
text-transform : none;
|
text-transform : none;
|
||||||
text-rendering : optimizeLegibility;
|
text-rendering : optimizeLegibility;
|
||||||
-moz-osx-font-smoothing : grayscale;
|
|
||||||
|
/* Better Font Rendering =========== */
|
||||||
-webkit-font-smoothing : antialiased;
|
-webkit-font-smoothing : antialiased;
|
||||||
|
-moz-osx-font-smoothing : grayscale;
|
||||||
|
|
||||||
&.F::before { content : '\f190'; }
|
&.F::before { content : '\f190'; }
|
||||||
&.F-minus::before { content : '\f191'; }
|
&.F-minus::before { content : '\f191'; }
|
||||||
&.F-plus::before { content : '\f192'; }
|
&.F-plus::before { content : '\f192'; }
|
||||||
209
themes/fonts/iconFonts/elderberryInn.js
Normal file
209
themes/fonts/iconFonts/elderberryInn.js
Normal 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;
|
||||||
225
themes/fonts/iconFonts/elderberryInn.less
Normal file
225
themes/fonts/iconFonts/elderberryInn.less
Normal 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'; }
|
||||||
|
}
|
||||||
2054
themes/fonts/iconFonts/fontAwesome.js
Normal file
2054
themes/fonts/iconFonts/fontAwesome.js
Normal file
File diff suppressed because it is too large
Load Diff
2
themes/fonts/iconFonts/fontAwesome.less
Normal file
2
themes/fonts/iconFonts/fontAwesome.less
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
/* Icon Font: Font Awesome */
|
||||||
|
.far,.fas,.fab { display : inline; }
|
||||||
13
themes/fonts/iconFonts/game-icons_license.md
Normal file
13
themes/fonts/iconFonts/game-icons_license.md
Normal 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.
|
||||||
509
themes/fonts/iconFonts/gameIcons.js
Normal file
509
themes/fonts/iconFonts/gameIcons.js
Normal 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;
|
||||||
516
themes/fonts/iconFonts/gameIcons.less
Normal file
516
themes/fonts/iconFonts/gameIcons.less
Normal 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'; }
|
||||||
|
}
|
||||||
BIN
themes/fonts/iconFonts/gameIcons.woff
Normal file
BIN
themes/fonts/iconFonts/gameIcons.woff
Normal file
Binary file not shown.
Reference in New Issue
Block a user