Merge branch 'master' into pr/1586
297
changelog.md
@@ -1,11 +1,279 @@
|
|||||||
<style>
|
```css
|
||||||
h5 {
|
h5 {
|
||||||
font-size: .35cm !important;
|
font-size: .35cm !important;
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
|
.taskList li {
|
||||||
|
list-style-type : none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskList li input {
|
||||||
|
margin-left : -0.52cm;
|
||||||
|
transform: translateY(.05cm);
|
||||||
|
filter: brightness(1.1) drop-shadow(1px 2px 1px #222);
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskList li input[checked] {
|
||||||
|
filter: sepia(100%) hue-rotate(60deg) saturate(3.5) contrast(4) brightness(1.1) drop-shadow(1px 2px 1px #222);
|
||||||
|
}
|
||||||
|
|
||||||
|
pre + * {
|
||||||
|
margin-top: 0.17cm;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
margin-top: 0.17cm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page p + pre {
|
||||||
|
margin-top : 0.1cm;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
# changelog
|
# changelog
|
||||||
|
|
||||||
|
### Friday, 17/09/2021 - v3.0.1
|
||||||
|
|
||||||
|
{{taskList
|
||||||
|
* [x] Updated V3 **PHB → Class Feature** snippet to use V3 syntax.
|
||||||
|
|
||||||
|
Fixes issues: [Reported on Reddit](https://www.reddit.com/r/homebrewery/comments/pm6ki7/two_version_of_class_features_making_it_look_more/)
|
||||||
|
|
||||||
|
* [x] Improved V3 **PHB → Monster Stat Block** snippet and styling to allow for easier control of paragraph indentation in the Abilities text.
|
||||||
|
|
||||||
|
Fixes issues: [#181](https://github.com/naturalcrit/homebrewery/issues/181)
|
||||||
|
|
||||||
|
* [x] Improved Legacy **TABLES → Split Table** snippet by removing unneeded column-break backticks.
|
||||||
|
|
||||||
|
Fixes issues: [#844](https://github.com/naturalcrit/homebrewery/issues/844)
|
||||||
|
|
||||||
|
* [x] Changed block elements to use CSS `width` instead of `min-width`. This should make custom styles behave more predictably when trying to resize items.
|
||||||
|
|
||||||
|
Fixes issues: [Reported on Reddit](https://www.reddit.com/r/homebrewery/comments/pohoy3/looking_for_help_with_basic_stuff_in_v3/)
|
||||||
|
|
||||||
|
* [x] Fixed Partial Page Rendering in V3 for large brews
|
||||||
|
|
||||||
|
Fixes issues: [Reported on Reddit](https://www.reddit.com/r/homebrewery/comments/pori3a/weird_behaviour_of_the_brew_after_page_50/)
|
||||||
|
|
||||||
|
* [x] Fixed HTML validation to handle tags starting with 'a', as in `<aside>`.
|
||||||
|
|
||||||
|
Fixes issues: [#230](https://github.com/naturalcrit/homebrewery/issues/230)
|
||||||
|
|
||||||
|
* [x] Fixed page footers switching side when printing.
|
||||||
|
|
||||||
|
Fixes issues: [#1612](https://github.com/naturalcrit/homebrewery/issues/1612)
|
||||||
|
}}
|
||||||
|
|
||||||
|
|
||||||
|
\page
|
||||||
|
|
||||||
|
### Saturday, 11/09/2021 - v3.0.0
|
||||||
|
|
||||||
|
We have been working on v3 for a *very* long time. We want to thank everyone for being paitent.
|
||||||
|
|
||||||
|
|
||||||
|
Some features planned for V3 have actually been released over the recent months as part of V2, and some are still on the way. But at its core, V3 provides brand new Markdown-to-Brew rendering system, which was no simple task. This has opened up access to all sorts of bugfixes, tweaks, and potential for new features that just wouldn't be possible on the old system.
|
||||||
|
|
||||||
|
***BE WARNED:*** As we continue to develop V3, expect small tweaks in the styling, fonts, and snippets; your brews may look slightly different from day-to-day; some things might break completely while we tackle any bugs in this early stage. All of your old documents will continue to work as normal. We are not touching them. If you don't want to deal With the possibility of slight formatting changes, you may choose to stick with the Legacy renderer on any of your brews for as long as you like. However, most new features added from now on will only be available for brews using the V3 renderer.
|
||||||
|
|
||||||
|
Massive changelog incoming:
|
||||||
|
|
||||||
|
#### Markdown+
|
||||||
|
With the latest major update to *The Homebrewery*, we've implemented an extended Markdown-like syntax for block and span elements, plus a few other changes, eliminating the need for HTML tags like `div`, and `span` in most cases. This should hopefully aid non-coders with readability, and also allows us a few tricks in the background to fix some old issues. No raw HTML tags should be needed in a brew, and going forward, raw HTML will no longer receive debugging support (*but can still be used if you insist*).
|
||||||
|
|
||||||
|
All brews made prior to the release of v3.0.0 will still render normally, and you may switch between the "Legacy" brew renderer and the newer "V3" renderer via the {{fa,fa-info-circle}} **Properties** button on your brew. Much of the syntax and styling has changed in V3, so code in one version may be broken in the other.
|
||||||
|
|
||||||
|
Visit [this page](/v3_preview) for brief examples of the new syntax!
|
||||||
|
|
||||||
|
#### Extended Markdown Syntax:
|
||||||
|
|
||||||
|
{{taskList
|
||||||
|
* [x] Add Divs and Spans for all your custom styling needs, via a simplified Markdown-like syntax:
|
||||||
|
```
|
||||||
|
{{myDivClass,#myId,color:red
|
||||||
|
My Div content
|
||||||
|
}}
|
||||||
|
|
||||||
|
Hello {{mySpan,color:blue World}} !
|
||||||
|
```
|
||||||
|
|
||||||
|
Fixes issues: [#348](https://github.com/naturalcrit/homebrewery/issues/348)
|
||||||
|
}}
|
||||||
|
|
||||||
|
\column
|
||||||
|
|
||||||
|
{{taskList
|
||||||
|
* [x] Add inline CSS to Markdown objects via "curly injection" syntax:
|
||||||
|
```
|
||||||
|
Hello *world*{myClass,#id,color:red}
|
||||||
|
```
|
||||||
|
Fixes issues: [#403](https://github.com/naturalcrit/homebrewery/issues/403)
|
||||||
|
|
||||||
|
* [x] Rowspan, Colspan, and multiple header rows with extended table syntax:
|
||||||
|
```
|
||||||
|
| Header 1a | Header 1b | Header 1c |
|
||||||
|
| Header 2a | Header 2b | Header 2c |
|
||||||
|
|:---------:|:----------|:---------:|
|
||||||
|
| Span 2 columns || Span 2 |
|
||||||
|
| one col | one col | rows ^|
|
||||||
|
```
|
||||||
|
Fixes issues: [#773](https://github.com/naturalcrit/homebrewery/issues/773), [#191](https://github.com/naturalcrit/homebrewery/issues/191)
|
||||||
|
|
||||||
|
* [x] Hanging indents via `<dl>` tags, as seen in the **PHB → Spell** snippet. Add via "double-colon" syntax:
|
||||||
|
```
|
||||||
|
Term :: big long definition that bleeds onto multiple lines
|
||||||
|
```
|
||||||
|
Fixes issues: [#182](https://github.com/naturalcrit/homebrewery/issues/182), [#149](https://github.com/naturalcrit/homebrewery/issues/149)
|
||||||
|
|
||||||
|
* [x] Easier vertical spacing via colons alone on a line:
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
```
|
||||||
|
Fixes issues: [#374](https://github.com/naturalcrit/homebrewery/issues/374)
|
||||||
|
|
||||||
|
* [x] Avoid paragraph indendation by ending the previous paragraph with a backslash `\` or two spaces ` `
|
||||||
|
```
|
||||||
|
Paragraph one\
|
||||||
|
Paragraph two
|
||||||
|
```
|
||||||
|
Fixes issues: [#636](https://github.com/naturalcrit/homebrewery/issues/636)
|
||||||
|
|
||||||
|
* [x] Code blocks can be inserted by surrounding it with rows of three backticks ` ``` `, for demonstration purposes or to share custom styles. Inline-code can be inserted with single backticks <code>`code`</code>
|
||||||
|
<pre><code>```
|
||||||
|
Here is some code!
|
||||||
|
```
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
Fixes issues: [#465](https://github.com/naturalcrit/homebrewery/issues/465)
|
||||||
|
|
||||||
|
#### New and Fixed Snippets
|
||||||
|
|
||||||
|
* [x] Column breaks now use `\column` instead of ` ``` ` backticks.
|
||||||
|
|
||||||
|
Fixes issues: [#607](https://github.com/naturalcrit/homebrewery/issues/607)
|
||||||
|
|
||||||
|
* [x] Page breaks using `\page` now only trigger when placed alone at the start of a line.
|
||||||
|
|
||||||
|
Fixes issues: [#1147](https://github.com/naturalcrit/homebrewery/issues/1147)
|
||||||
|
}}
|
||||||
|
|
||||||
|
\page
|
||||||
|
{{taskList
|
||||||
|
* [x] New **EDITOR → QR Code** snippet.
|
||||||
|
|
||||||
|
Fixes issues: [#538](https://github.com/naturalcrit/homebrewery/issues/538)
|
||||||
|
|
||||||
|
* [x] New **IMAGES → Watercolor Splatter** snippet, which adds one of a range of stylish stains to your brew.
|
||||||
|
|
||||||
|
* [x] New **IMAGES → Watermark** snippet, which adds transparent text diagonally across the page.
|
||||||
|
|
||||||
|
* [x] New **PHB → Magic Item** snippet.
|
||||||
|
|
||||||
|
Fixes issues: [#671](https://github.com/naturalcrit/homebrewery/issues/671)
|
||||||
|
|
||||||
|
* [x] New **TABLES → 1/3 Class Table** snippet for 1/3 casters.
|
||||||
|
|
||||||
|
Fixes issues: [#191](https://github.com/naturalcrit/homebrewery/issues/191)
|
||||||
|
|
||||||
|
* [x] Improved **EDITOR → Table of Contents** snippet to actually look like the PHB style. Will auto-generate based on the headers in your brew.
|
||||||
|
|
||||||
|
Fixes issues: [#304](https://github.com/naturalcrit/homebrewery/issues/304)
|
||||||
|
|
||||||
|
* [x] Improved **PHB → Monster Stat Block** snippet with textures, and an option to remove the frame entirely.
|
||||||
|
|
||||||
|
* [x] Improved **PHB → Spell List** snippet can now be made single-column.
|
||||||
|
|
||||||
|
Fixes issues: [#509](https://github.com/naturalcrit/homebrewery/issues/509), [#914](https://github.com/naturalcrit/homebrewery/issues/914)
|
||||||
|
|
||||||
|
* [x] Improved **TABLES → Class Table** snippet is now cleaned up, has an option to remove the frame entirely, and includes additional boundary decorations.
|
||||||
|
|
||||||
|
Fixes issues: [#773](https://github.com/naturalcrit/homebrewery/issues/773), [#302](https://github.com/naturalcrit/homebrewery/issues/302)
|
||||||
|
|
||||||
|
#### Miscellaneous Formatting Fixes
|
||||||
|
|
||||||
|
* [x] Paragraphs are now able to split across columns.
|
||||||
|
|
||||||
|
Fixes issues: [#239](https://github.com/naturalcrit/homebrewery/issues/239)
|
||||||
|
|
||||||
|
* [x] Multiple fixes for bold/italicize using asterisks `* *`
|
||||||
|
|
||||||
|
Fixes issues: [#1321](https://github.com/naturalcrit/homebrewery/issues/1321), [#852](https://github.com/naturalcrit/homebrewery/issues/852)
|
||||||
|
|
||||||
|
* [x] Multiple for list items not displaying correctly.
|
||||||
|
|
||||||
|
Fixes issues: [#1085](https://github.com/naturalcrit/homebrewery/issues/1085), [#588](https://github.com/naturalcrit/homebrewery/issues/588)
|
||||||
|
|
||||||
|
* [x] "Smart quotes", so left and right quotes are different.
|
||||||
|
|
||||||
|
Fixes issues: [#849](https://github.com/naturalcrit/homebrewery/issues/849)
|
||||||
|
|
||||||
|
* [x] Long URLs in links now wrap properly.
|
||||||
|
|
||||||
|
Fixes issues: [#1136](https://github.com/naturalcrit/homebrewery/issues/1136)
|
||||||
|
|
||||||
|
* [x] Better support for `wide` blocks that span across the whole page! No more problems with contents getting shunted off the edge, and each new wide element in a page will restart the next item back at column one. Manual `\column` breaks will help organize subsequent content between the columns as needed.
|
||||||
|
|
||||||
|
Fixes issues: [#144](https://github.com/naturalcrit/homebrewery/issues/144), [#1024](https://github.com/naturalcrit/homebrewery/issues/1024)
|
||||||
|
|
||||||
|
* [x] Fonts now support a wider range of latin characters for non-English brews, including áéíóúñ¡¿, etc...
|
||||||
|
|
||||||
|
Fixes issues: [#116](https://github.com/naturalcrit/homebrewery/issues/116)
|
||||||
|
|
||||||
|
* [x] Drop-caps (fancy first letters) have been re-styled and re-aligned to correct the ugly overlapping and cut-off on some characters like K and Y.
|
||||||
|
|
||||||
|
Fixes issues: [#848](https://github.com/naturalcrit/homebrewery/issues/848)
|
||||||
|
}}
|
||||||
|
|
||||||
|
\column
|
||||||
|
|
||||||
|
### Under-the-Hood Stuff
|
||||||
|
We had to make a whole lot of background upgrades and changes to get all of this working, and now that the framework is in place, there's a lot more planned and upcoming *"sometime"* :
|
||||||
|
|
||||||
|
{{taskList
|
||||||
|
* [ ] New Themes to style your brews. DMG, MM, a custom Homebrewery theme, and others.
|
||||||
|
* [ ] The ability to build your own custom themes using CSS, apply it to other brews, and share it with others!
|
||||||
|
* [ ] Easy control of item colors. Change your monster blocks, tables, and notes from yellow to green to red!
|
||||||
|
* [ ] New image-based snippets, including handwritten notes, title illustrations, and alternative decorations.
|
||||||
|
* [ ] New fun fonts like Elvish, Draconic, Orcish, etc.
|
||||||
|
* [ ] Better organization of personal brews using tags.
|
||||||
|
* [ ] ....a log-out button...?
|
||||||
|
* [ ] AND MORE.
|
||||||
|
}}
|
||||||
|
|
||||||
|
### Interface
|
||||||
|
::
|
||||||
|
#### Style Editor Panel
|
||||||
|
|
||||||
|
{{fa,fa-paint-brush}} Technically released prior to v3 but still new to many users, check out the new **Style Editor** located on the right side of the Snippet bar. This editor accepts CSS for styling without requiring `<style>` tags-- anything that would have gone inside style tags before can now be placed here, and snippets that insert CSS styles are now located on that tab.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
\page
|
||||||
|
### Thursday, 09/09/2021 - v2.13.5
|
||||||
|
- Slightly better error logging and messages for users.
|
||||||
|
|
||||||
|
##### G-Ambatte :
|
||||||
|
- Added a search bar to the User page to help find your brews.
|
||||||
|
- Added page counts to brews in the User page; page count will be updated the next time a brew is edited.
|
||||||
|
- Fixed edge case where view counts could get reset.
|
||||||
|
- Fixed edge case where last-modified time was not accurate for Google Doc brews.
|
||||||
|
|
||||||
|
##### Gazook89 :
|
||||||
|
- Fixed typo in the **PRINT → Ink-Friendly** snippet.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Tuesday, 17/08/2021 - v2.13.4
|
||||||
|
- Fixed User page crashing when user has an untitled brew
|
||||||
|
|
||||||
|
##### G-Ambatte:
|
||||||
|
- Tweaks to user page tool tips
|
||||||
|
- Fix view counts being reset on Google Drive files
|
||||||
|
|
||||||
|
##### Gazook89 :
|
||||||
|
- New **PHB → Artist Credit** snippet
|
||||||
|
- **PRINT** snippets moved to the **Style Editor** tab
|
||||||
|
|
||||||
### Monday, 09/08/2021 - v2.13.3
|
### Monday, 09/08/2021 - v2.13.3
|
||||||
|
|
||||||
##### G-Ambatte :
|
##### G-Ambatte :
|
||||||
@@ -48,7 +316,6 @@ myStyle {color: black}
|
|||||||
- Pasting your brew into a "New" page and saving will transfer any CSS in the code fence to the Style tab.
|
- Pasting your brew into a "New" page and saving will transfer any CSS in the code fence to the Style tab.
|
||||||
- Unsaved work in the New page Style tab is now cached to your browser storage if you navigate away.
|
- Unsaved work in the New page Style tab is now cached to your browser storage if you navigate away.
|
||||||
|
|
||||||
|
|
||||||
### Thursday, 10/6/2021 - v2.12.0
|
### Thursday, 10/6/2021 - v2.12.0
|
||||||
|
|
||||||
- New "style" tab to better organize custom CSS in preparation for new themes and sharable styles.
|
- New "style" tab to better organize custom CSS in preparation for new themes and sharable styles.
|
||||||
@@ -59,6 +326,8 @@ myStyle {color: black}
|
|||||||
- Fix for edge case where brews could accidentally transfer from Google Drive back to Homebrewery.
|
- Fix for edge case where brews could accidentally transfer from Google Drive back to Homebrewery.
|
||||||
- Move cursor to end of snippet after insertion
|
- Move cursor to end of snippet after insertion
|
||||||
|
|
||||||
|
\page
|
||||||
|
|
||||||
### Saturday, 20/3/2021 - v2.11.1
|
### Saturday, 20/3/2021 - v2.11.1
|
||||||
|
|
||||||
- Warning when opening brew in your Google Drive trash
|
- Warning when opening brew in your Google Drive trash
|
||||||
@@ -99,6 +368,8 @@ myStyle {color: black}
|
|||||||
### Wednesday, 25/11/2020 - v2.10.4
|
### Wednesday, 25/11/2020 - v2.10.4
|
||||||
- Fixed Google Drive brews not saving metadata (view count, description, etc.) Note that we are still working on making published Google brews visible to the public when viewing your profile page.
|
- Fixed Google Drive brews not saving metadata (view count, description, etc.) Note that we are still working on making published Google brews visible to the public when viewing your profile page.
|
||||||
|
|
||||||
|
\column
|
||||||
|
|
||||||
### Thursday, 22/10/2020 - v2.10.3
|
### Thursday, 22/10/2020 - v2.10.3
|
||||||
- Fixed brews with broken code crashing the edit page when loaded (the "blue screen of death" bug).
|
- Fixed brews with broken code crashing the edit page when loaded (the "blue screen of death" bug).
|
||||||
|
|
||||||
@@ -109,8 +380,6 @@ myStyle {color: black}
|
|||||||
- Fixed issue with users unable to create new brews
|
- Fixed issue with users unable to create new brews
|
||||||
- Fixing brews being lost when loaded via back button
|
- Fixing brews being lost when loaded via back button
|
||||||
|
|
||||||
\page
|
|
||||||
|
|
||||||
### Wednesday, 07/10/2020 - v2.10.0
|
### Wednesday, 07/10/2020 - v2.10.0
|
||||||
- Google Drive integration -- Sign in with your Google account to link it with your Homebrewery profile. A new button in the Edit page will let you transfer your file to your personal Google Drive storage, and Google will keep a backup of each version! No more lost work surprises!
|
- Google Drive integration -- Sign in with your Google account to link it with your Homebrewery profile. A new button in the Edit page will let you transfer your file to your personal Google Drive storage, and Google will keep a backup of each version! No more lost work surprises!
|
||||||
|
|
||||||
@@ -140,8 +409,10 @@ myStyle {color: black}
|
|||||||
- "Report Issue" navbar button now links to the subreddit
|
- "Report Issue" navbar button now links to the subreddit
|
||||||
- Refactored background code
|
- Refactored background code
|
||||||
|
|
||||||
|
\page
|
||||||
|
|
||||||
### Sunday, 04/06/2017 - v2.7.5
|
### Sunday, 04/06/2017 - v2.7.5
|
||||||
- Fixed the class feature snippet duplicating the entire brew
|
- Fixed Class Feature snippet duplicating entire brew
|
||||||
- Fixed headers in tables being duplicated
|
- Fixed headers in tables being duplicated
|
||||||
- Fixed border-image being scrambled on class tables and descriptive text boxes
|
- Fixed border-image being scrambled on class tables and descriptive text boxes
|
||||||
- Fixed pages going out of sync in large brews, causing them to be rendered off-page
|
- Fixed pages going out of sync in large brews, causing them to be rendered off-page
|
||||||
@@ -167,7 +438,7 @@ myStyle {color: black}
|
|||||||
|
|
||||||
### Sunday, 25/12/2016 - v2.7.0
|
### Sunday, 25/12/2016 - v2.7.0
|
||||||
- Switching over to using Vitreum v4
|
- Switching over to using Vitreum v4
|
||||||
- Removed gulp, all tasks are run through npm scripts
|
- Removed gulp, all tasks are run through npm scripts
|
||||||
- Updating docs for local dev
|
- Updating docs for local dev
|
||||||
- Removing support for Docker. I have never used it, nor will I ever test for it, so I don't want to continue to explictly support it on this repo. Feel free to make a fork and make it docker-able though :)
|
- Removing support for Docker. I have never used it, nor will I ever test for it, so I don't want to continue to explictly support it on this repo. Feel free to make a fork and make it docker-able though :)
|
||||||
- Changed icon for the metadata
|
- Changed icon for the metadata
|
||||||
@@ -177,6 +448,8 @@ myStyle {color: black}
|
|||||||
- Removed a lot of unused files in shared
|
- Removed a lot of unused files in shared
|
||||||
- vitreum v4 now lets me use codemirror as a pure node dependacy
|
- vitreum v4 now lets me use codemirror as a pure node dependacy
|
||||||
|
|
||||||
|
\column
|
||||||
|
|
||||||
### Saturday, 03/12/2016 - v2.6.0
|
### Saturday, 03/12/2016 - v2.6.0
|
||||||
- Added report back to the edit page
|
- Added report back to the edit page
|
||||||
- Changed metaeditor icon
|
- Changed metaeditor icon
|
||||||
@@ -197,8 +470,6 @@ myStyle {color: black}
|
|||||||
- Added a hover tooltip to fully read the brew description
|
- Added a hover tooltip to fully read the brew description
|
||||||
- Made the brew items take up only 25% allowing you to view more per row.
|
- Made the brew items take up only 25% allowing you to view more per row.
|
||||||
|
|
||||||
\page
|
|
||||||
|
|
||||||
### Wednesday, 23/11/2016 - v2.5.0
|
### Wednesday, 23/11/2016 - v2.5.0
|
||||||
- Metadata can now be added to brews
|
- Metadata can now be added to brews
|
||||||
- Added a metadata editor onto the edit and new pages
|
- Added a metadata editor onto the edit and new pages
|
||||||
@@ -218,6 +489,8 @@ myStyle {color: black}
|
|||||||
- Added final touches to the html validator and updating the rest of the branch
|
- Added final touches to the html validator and updating the rest of the branch
|
||||||
- If anyone finds issues with the new HTML validator, please let me know. I hope this will bring a more consistent feel to Homebrewery rendering.
|
- If anyone finds issues with the new HTML validator, please let me know. I hope this will bring a more consistent feel to Homebrewery rendering.
|
||||||
|
|
||||||
|
\page
|
||||||
|
|
||||||
### Friday, 09/09/2016 - v2.4.0
|
### Friday, 09/09/2016 - v2.4.0
|
||||||
- Adding in a HTML validator that will display warnings whenever you save. This should stop a lot of the issues generated with pages not showing up.
|
- Adding in a HTML validator that will display warnings whenever you save. This should stop a lot of the issues generated with pages not showing up.
|
||||||
|
|
||||||
@@ -245,7 +518,7 @@ myStyle {color: black}
|
|||||||
- Even works after you print to pdf!
|
- Even works after you print to pdf!
|
||||||
|
|
||||||
### Tuesday, 07/06/2016 - v2.2.2
|
### Tuesday, 07/06/2016 - v2.2.2
|
||||||
- Fixed bug with new markdown lexer and aprser not working on print page
|
- Fixed bug with new markdown lexer and parser not working on print page
|
||||||
|
|
||||||
### Sunday, 05/06/2016 - v2.2.1
|
### Sunday, 05/06/2016 - v2.2.1
|
||||||
- Adding in a new Class table div block. The old Class table block used weird stacking of HTML elements, resulting is difficult to control behaviour and poor interactiosn with the rest of the page. This new block is much easier to style and work with.
|
- Adding in a new Class table div block. The old Class table block used weird stacking of HTML elements, resulting is difficult to control behaviour and poor interactiosn with the rest of the page. This new block is much easier to style and work with.
|
||||||
@@ -253,8 +526,10 @@ myStyle {color: black}
|
|||||||
- Added in a new auto-incremeting page number snippet (thakns u/Ryrok!)
|
- Added in a new auto-incremeting page number snippet (thakns u/Ryrok!)
|
||||||
- Lists in monster stat blocks should be fixed now
|
- Lists in monster stat blocks should be fixed now
|
||||||
|
|
||||||
|
\column
|
||||||
|
|
||||||
### Saturday, 04/06/2016 - v2.2.0
|
### Saturday, 04/06/2016 - v2.2.0
|
||||||
- MIgrating The Homebrewery over to hombrewery.naturalcrit.com. It know runs on it's own server, with it's own repo separate from the other tools I'm working on. Makes updating and deploying much easier.
|
- Migrating The Homebrewery over to hombrewery.naturalcrit.com. It now runs on it's own server, with it's own repo separate from the other tools I'm working on. Makes updating and deploying much easier.
|
||||||
|
|
||||||
### Sunday, 29/05/2016 - v2.1.0
|
### Sunday, 29/05/2016 - v2.1.0
|
||||||
- Finally added a syntax for doing spell lists. A bit in-depth about why this took so long. Essentially I'm running out of syntax to use in stardard Markdown. There are too many unique elements in the PHB-style to be mapped. I solved this earlier by stacking certain elements together (eg. an `<hr>` before a `blockquote` turns it into moster state block), but those are getting unweildly. I would like to simply wrap these in `div`s with classes, but unfortunately Markdown stops processing when within HTML blocks. To get around this I wrote my own override to the Markdown parser and lexer to process Markdown within a simple div class wrapper. This should open the door for more unique syntaxes in the future. Big step!
|
- Finally added a syntax for doing spell lists. A bit in-depth about why this took so long. Essentially I'm running out of syntax to use in stardard Markdown. There are too many unique elements in the PHB-style to be mapped. I solved this earlier by stacking certain elements together (eg. an `<hr>` before a `blockquote` turns it into moster state block), but those are getting unweildly. I would like to simply wrap these in `div`s with classes, but unfortunately Markdown stops processing when within HTML blocks. To get around this I wrote my own override to the Markdown parser and lexer to process Markdown within a simple div class wrapper. This should open the door for more unique syntaxes in the future. Big step!
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ const BrewRenderer = createClass({
|
|||||||
if(this.props.renderer == 'legacy') {
|
if(this.props.renderer == 'legacy') {
|
||||||
pages = this.props.text.split('\\page');
|
pages = this.props.text.split('\\page');
|
||||||
} else {
|
} else {
|
||||||
pages = this.props.text.split(/^\\page/gm);
|
pages = this.props.text.split(/^\\page$/gm);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -62,7 +62,7 @@ const BrewRenderer = createClass({
|
|||||||
if(this.props.renderer == 'legacy') {
|
if(this.props.renderer == 'legacy') {
|
||||||
pages = this.props.text.split('\\page');
|
pages = this.props.text.split('\\page');
|
||||||
} else {
|
} else {
|
||||||
pages = this.props.text.split(/^\\page/gm);
|
pages = this.props.text.split(/^\\page$/gm);
|
||||||
}
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
pages : pages,
|
pages : pages,
|
||||||
@@ -117,7 +117,7 @@ const BrewRenderer = createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
renderDummyPage : function(index){
|
renderDummyPage : function(index){
|
||||||
return <div className='phb' id={`p${index + 1}`} key={index}>
|
return <div className='phb page' id={`p${index + 1}`} key={index}>
|
||||||
<i className='fas fa-spinner fa-spin' />
|
<i className='fas fa-spinner fa-spin' />
|
||||||
</div>;
|
</div>;
|
||||||
},
|
},
|
||||||
@@ -130,8 +130,14 @@ const BrewRenderer = createClass({
|
|||||||
renderPage : function(pageText, index){
|
renderPage : function(pageText, index){
|
||||||
if(this.props.renderer == 'legacy')
|
if(this.props.renderer == 'legacy')
|
||||||
return <div className='phb page' id={`p${index + 1}`} dangerouslySetInnerHTML={{ __html: MarkdownLegacy.render(pageText) }} key={index} />;
|
return <div className='phb page' id={`p${index + 1}`} dangerouslySetInnerHTML={{ __html: MarkdownLegacy.render(pageText) }} key={index} />;
|
||||||
else
|
else {
|
||||||
return <div className='phb3 page' id={`p${index + 1}`} dangerouslySetInnerHTML={{ __html: Markdown.render(pageText) }} key={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>
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
renderPages : function(){
|
renderPages : function(){
|
||||||
@@ -182,7 +188,6 @@ const BrewRenderer = createClass({
|
|||||||
: null}
|
: null}
|
||||||
|
|
||||||
<Frame initialContent={this.state.initialContent}
|
<Frame initialContent={this.state.initialContent}
|
||||||
head = <link href={`${this.props.renderer == 'legacy' ? '/themes/5ePhbLegacy.style.css' : '/themes/5ePhb.style.css'}`} rel='stylesheet'/>
|
|
||||||
style={{ width: '100%', height: '100%', visibility: this.state.visibility }}
|
style={{ width: '100%', height: '100%', visibility: this.state.visibility }}
|
||||||
contentDidMount={this.frameDidMount}>
|
contentDidMount={this.frameDidMount}>
|
||||||
<div className={'brewRenderer'}
|
<div className={'brewRenderer'}
|
||||||
@@ -194,17 +199,17 @@ const BrewRenderer = createClass({
|
|||||||
<RenderWarnings />
|
<RenderWarnings />
|
||||||
<NotificationPopup />
|
<NotificationPopup />
|
||||||
</div>
|
</div>
|
||||||
|
<link href={`${this.props.renderer == 'legacy' ? '/themes/5ePhbLegacy.style.css' : '/themes/5ePhb.style.css'}`} rel='stylesheet'/>
|
||||||
<div className='pages' ref='pages'>
|
{/* Apply CSS from Style tab and render pages from Markdown tab */}
|
||||||
{/* Apply CSS from Style tab and render pages from Markdown tab */}
|
{this.state.isMounted
|
||||||
{this.state.isMounted
|
&&
|
||||||
&&
|
<>
|
||||||
<>
|
{this.renderStyle()}
|
||||||
{this.renderStyle()}
|
<div className='pages' ref='pages'>
|
||||||
{this.renderPages()}
|
{this.renderPages()}
|
||||||
</>
|
</div>
|
||||||
}
|
</>
|
||||||
</div>
|
}
|
||||||
</div>
|
</div>
|
||||||
</Frame>
|
</Frame>
|
||||||
{this.renderPageInfo()}
|
{this.renderPageInfo()}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ const createClass = require('create-react-class');
|
|||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const cx = require('classnames'); //Unused variable
|
const cx = require('classnames'); //Unused variable
|
||||||
|
|
||||||
const DISMISS_KEY = 'dismiss_notification7-10-20';
|
const DISMISS_KEY = 'dismiss_notification09-9-21';
|
||||||
|
|
||||||
const NotificationPopup = createClass({
|
const NotificationPopup = createClass({
|
||||||
getInitialState : function() {
|
getInitialState : function() {
|
||||||
@@ -22,22 +22,39 @@ const NotificationPopup = createClass({
|
|||||||
notifications : {
|
notifications : {
|
||||||
psa : function(){
|
psa : function(){
|
||||||
return <li key='psa'>
|
return <li key='psa'>
|
||||||
<em>Google Drive Integration!</em> <br />
|
<em>V3.0.0 Released!</em> <br />
|
||||||
We have added Google Drive integration to the Homebrewery! <a target='_blank' href='https://www.naturalcrit.com/login'>Sign in</a> with
|
After a long and bumpy road, we decided it was high time we finally release version 3 of the homebrewery into the wild. You can check out a
|
||||||
your Google account to link it with your Homebrewery profile. A new button in the Edit page will let you transfer your file to your personal
|
brief overview and see how to opt-in to the new features here:
|
||||||
Google Drive storage, and Google will keep a backup of each version! No more lost work surprises!
|
<a target='_blank' href='https://homebrewery.naturalcrit.com/v3_preview'>V3 Welcome Page</a> and
|
||||||
|
<a target='_blank' href='https://homebrewery.naturalcrit.com/changelog'>the Changelog</a>.
|
||||||
<br /><br />
|
<br /><br />
|
||||||
However, we are aware that there may be uncaught bugs. We encourage you to copy your brew into a text document before transferring to Google
|
<em>BE WARNED:</em> As we continue to develop V3, expect small tweaks in the styling, fonts, and snippets; your brews may look slightly
|
||||||
Drive just in case any issues arise as this update is rolled out.
|
different from day-to-day. All of your old documents will continue to work as normal; we are not touching them. If you don't want to deal
|
||||||
|
with the possibility of slight formatting changes, you may choose to stick with the Legacy renderer on any of your brews for as long as you like.
|
||||||
<br /><br />
|
<br /><br />
|
||||||
<b>Note:</b> Transferring an existing brew to Google Drive will change the edit and share links of your document. If you have shared your
|
With this in mind, if you still wish to try out V3, you can opt-in any of your brews to the the V3 renderer.
|
||||||
document online, remember to update the links there as well.
|
This will likely break much of your formatting as a lot of the Markdown code has been updated, and starting from scratch may be cleaner.
|
||||||
|
(Don't worry, you can always change the renderer back to Legacy for any brew at any time).
|
||||||
|
</li>;
|
||||||
|
},
|
||||||
|
refreshGoogle : function (){
|
||||||
|
return <li key='refreshGoogle'>
|
||||||
|
<em>Refresh your Google Drive Credentials!</em> <br />
|
||||||
|
Currently a lot of people are striking issues with their Google credentials expiring, which happens one year after the last sign in via
|
||||||
|
Google. This can cause errors when trying to save your brews. If this happens, simply visit the
|
||||||
|
<a target='_blank' href='https://www.naturalcrit.com/login'>
|
||||||
|
logout page
|
||||||
|
</a>
|
||||||
|
, sign out, and then sign back in "with Google" to refresh your credentials. See
|
||||||
|
<a target='_blank' href='https://github.com/naturalcrit/homebrewery/discussions/1580'>
|
||||||
|
this discussion on Github
|
||||||
|
</a> for more details.
|
||||||
</li>;
|
</li>;
|
||||||
},
|
},
|
||||||
faq : function(){
|
faq : function(){
|
||||||
return <li key='faq'>
|
return <li key='faq'>
|
||||||
<em>Protect your work! </em> <br />
|
<em>Protect your work! </em> <br />
|
||||||
If you opt not to use your Google Drive, keep in mind that we do not save a history of your projects. Please make frequent backups of your brews!
|
If you opt not to use your Google Drive, keep in mind that we do not save a history of your projects. Please make frequent backups of your brews!
|
||||||
<a target='_blank' href='https://www.reddit.com/r/homebrewery/comments/adh6lh/faqs_psas_announcements/'>
|
<a target='_blank' href='https://www.reddit.com/r/homebrewery/comments/adh6lh/faqs_psas_announcements/'>
|
||||||
See the FAQ
|
See the FAQ
|
||||||
</a> to learn how to avoid losing your work!
|
</a> to learn how to avoid losing your work!
|
||||||
@@ -62,8 +79,10 @@ const NotificationPopup = createClass({
|
|||||||
return <div className='notificationPopup'>
|
return <div className='notificationPopup'>
|
||||||
<i className='fas fa-times dismiss' onClick={this.dismiss}/>
|
<i className='fas fa-times dismiss' onClick={this.dismiss}/>
|
||||||
<i className='fas fa-info-circle info' />
|
<i className='fas fa-info-circle info' />
|
||||||
<h3>Notice</h3>
|
<div className='header'>
|
||||||
<small>This website is always improving and we are still adding new features and squashing bugs. Keep the following in mind:</small>
|
<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>
|
<ul>{_.values(this.state.notifications)}</ul>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,22 @@
|
|||||||
.popups{
|
.popups{
|
||||||
position : fixed;
|
position : fixed;
|
||||||
top : @navbarHeight;
|
top : @navbarHeight;
|
||||||
right : 15px;
|
right : 15px;
|
||||||
z-index : 10001;
|
z-index : 10001;
|
||||||
width : 350px;
|
width : 450px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notificationPopup{
|
.notificationPopup{
|
||||||
position : relative;
|
position : relative;
|
||||||
float : right;
|
|
||||||
display : inline-block;
|
display : inline-block;
|
||||||
width : 350px;
|
width : 100%;
|
||||||
padding : 15px;
|
padding : 15px;
|
||||||
padding-bottom : 10px;
|
padding-bottom : 10px;
|
||||||
padding-left : 55px;
|
padding-left : 25px;
|
||||||
background-color : @blue;
|
background-color : @blue;
|
||||||
color : white;
|
color : white;
|
||||||
a{
|
a{
|
||||||
color : @steel;
|
color : #e0e5c1;
|
||||||
font-weight : 800;
|
font-weight : 800;
|
||||||
}
|
}
|
||||||
i.info{
|
i.info{
|
||||||
@@ -37,6 +36,9 @@
|
|||||||
opacity : 1;
|
opacity : 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.header {
|
||||||
|
padding-left : 50px;
|
||||||
|
}
|
||||||
small{
|
small{
|
||||||
opacity : 0.7;
|
opacity : 0.7;
|
||||||
font-size : 0.6em;
|
font-size : 0.6em;
|
||||||
|
|||||||
@@ -68,15 +68,18 @@ const Editor = createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleInject : function(injectText){
|
handleInject : function(injectText){
|
||||||
const text = (this.isText() ? this.props.brew.text : this.props.brew.style);
|
let text;
|
||||||
|
if(this.isText()) text = this.props.brew.text;
|
||||||
|
if(this.isStyle()) text = this.props.brew.style ?? DEFAULT_STYLE_TEXT;
|
||||||
|
|
||||||
const lines = text.split('\n');
|
const lines = text.split('\n');
|
||||||
const cursorPos = this.refs.codeEditor.getCursorPosition();
|
const cursorPos = this.refs.codeEditor.getCursorPosition();
|
||||||
lines[cursorPos.line] = splice(lines[cursorPos.line], cursorPos.ch, injectText);
|
lines[cursorPos.line] = splice(lines[cursorPos.line], cursorPos.ch, injectText);
|
||||||
|
|
||||||
this.refs.codeEditor.setCursorPosition(cursorPos.line + injectText.split('\n').length, cursorPos.ch + injectText.length);
|
const injectLines = injectText.split('\n');
|
||||||
|
this.refs.codeEditor.setCursorPosition(cursorPos.line + injectLines.length, cursorPos.ch + injectLines[injectLines.length - 1].length);
|
||||||
|
|
||||||
if(this.isText()) this.props.onTextChange(lines.join('\n'));
|
if(this.isText()) this.props.onTextChange(lines.join('\n'));
|
||||||
if(this.isStyle()) this.props.onStyleChange(lines.join('\n'));
|
if(this.isStyle()) this.props.onStyleChange(lines.join('\n'));
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -119,7 +122,7 @@ const Editor = createClass({
|
|||||||
|
|
||||||
// New Codemirror styling for V3 renderer
|
// New Codemirror styling for V3 renderer
|
||||||
if(this.props.renderer == 'V3') {
|
if(this.props.renderer == 'V3') {
|
||||||
if(line.startsWith('\\page')){
|
if(line.match(/^\\page$/)){
|
||||||
codeMirror.addLineClass(lineNumber, 'background', 'pageLine');
|
codeMirror.addLineClass(lineNumber, 'background', 'pageLine');
|
||||||
r.push(lineNumber);
|
r.push(lineNumber);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,9 +67,6 @@
|
|||||||
.button(@silver);
|
.button(@silver);
|
||||||
}
|
}
|
||||||
small{
|
small{
|
||||||
position : absolute;
|
|
||||||
bottom : -15px;
|
|
||||||
left : 0px;
|
|
||||||
font-size : 0.6em;
|
font-size : 0.6em;
|
||||||
font-style : italic;
|
font-style : italic;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
const dedent = require('dedent-tabs').default;
|
||||||
|
|
||||||
module.exports = function(classname){
|
module.exports = function(classname){
|
||||||
|
|
||||||
@@ -10,33 +11,32 @@ module.exports = function(classname){
|
|||||||
const hitDie = _.sample([4, 6, 8, 10, 12]);
|
const hitDie = _.sample([4, 6, 8, 10, 12]);
|
||||||
|
|
||||||
const abilityList = ['Strength', 'Dexerity', 'Constitution', 'Wisdom', 'Charisma', 'Intelligence'];
|
const abilityList = ['Strength', 'Dexerity', 'Constitution', 'Wisdom', 'Charisma', 'Intelligence'];
|
||||||
const skillList = ['Acrobatics ', 'Animal Handling', 'Arcana', 'Athletics', 'Deception', 'History', 'Insight', 'Intimidation', 'Investigation', 'Medicine', 'Nature', 'Perception', 'Performance', 'Persuasion', 'Religion', 'Sleight of Hand', 'Stealth', 'Survival'];
|
const skillList = ['Acrobatics', 'Animal Handling', 'Arcana', 'Athletics', 'Deception', 'History', 'Insight', 'Intimidation', 'Investigation', 'Medicine', 'Nature', 'Perception', 'Performance', 'Persuasion', 'Religion', 'Sleight of Hand', 'Stealth', 'Survival'];
|
||||||
|
|
||||||
|
|
||||||
return [
|
return dedent`
|
||||||
'## Class Features',
|
## Class Features
|
||||||
`As a ${classname}, you gain the following class features`,
|
As a ${classname}, you gain the following class features
|
||||||
'#### Hit Points',
|
#### Hit Points
|
||||||
'___',
|
|
||||||
`- **Hit Dice:** 1d${hitDie} per ${classname} level`,
|
**Hit Dice:** :: 1d${hitDie} per ${classname} level
|
||||||
`- **Hit Points at 1st Level:** ${hitDie} + your Constitution modifier`,
|
**Hit Points at 1st Level:** :: ${hitDie} + your Constitution modifier
|
||||||
`- **Hit Points at Higher Levels:** 1d${hitDie} (or ${hitDie/2 + 1}) + your Constitution modifier per ${classname} level after 1st`,
|
**Hit Points at Higher Levels:** :: 1d${hitDie} (or ${hitDie/2 + 1}) + your Constitution modifier per ${classname} level after 1st
|
||||||
'',
|
|
||||||
'#### Proficiencies',
|
#### Proficiencies
|
||||||
'___',
|
|
||||||
`- **Armor:** ${_.sampleSize(['Light armor', 'Medium armor', 'Heavy armor', 'Shields'], _.random(0, 3)).join(', ') || 'None'}`,
|
**Armor:** :: ${_.sampleSize(['Light armor', 'Medium armor', 'Heavy armor', 'Shields'], _.random(0, 3)).join(', ') || 'None'}
|
||||||
`- **Weapons:** ${_.sampleSize(['Squeegee', 'Rubber Chicken', 'Simple weapons', 'Martial weapons'], _.random(0, 2)).join(', ') || 'None'}`,
|
**Weapons:** :: ${_.sampleSize(['Squeegee', 'Rubber Chicken', 'Simple weapons', 'Martial weapons'], _.random(0, 2)).join(', ') || 'None'}
|
||||||
`- **Tools:** ${_.sampleSize(['Artian\'s tools', 'one musical instrument', 'Thieve\'s tools'], _.random(0, 2)).join(', ') || 'None'}`,
|
**Tools:** :: ${_.sampleSize(['Artian\'s tools', 'one musical instrument', 'Thieve\'s tools'], _.random(0, 2)).join(', ') || 'None'}
|
||||||
'',
|
|
||||||
'___',
|
**Saving Throws:** :: ${_.sampleSize(abilityList, 2).join(', ')}
|
||||||
`- **Saving Throws:** ${_.sampleSize(abilityList, 2).join(', ')}`,
|
**Skills:** :: Choose two from ${_.sampleSize(skillList, _.random(4, 6)).join(', ')}
|
||||||
`- **Skills:** Choose two from ${_.sampleSize(skillList, _.random(4, 6)).join(', ')}`,
|
|
||||||
'',
|
#### Equipment
|
||||||
'#### Equipment',
|
You start with the following equipment, in addition to the equipment granted by your background:
|
||||||
'You start with the following equipment, in addition to the equipment granted by your background:',
|
- *(a)* a martial weapon and a shield or *(b)* two martial weapons
|
||||||
'- *(a)* a martial weapon and a shield or *(b)* two martial weapons',
|
- *(a)* five javelins or *(b)* any simple melee weapon
|
||||||
'- *(a)* five javelins or *(b)* any simple melee weapon',
|
- ${_.sample(['10 lint fluffs', '1 button', 'a cherished lost sock'])}
|
||||||
`- ${_.sample(['10 lint fluffs', '1 button', 'a cherished lost sock'])}`,
|
|
||||||
'\n\n\n'
|
`;
|
||||||
].join('\n');
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,86 +2,77 @@ const _ = require('lodash');
|
|||||||
|
|
||||||
const features = [
|
const features = [
|
||||||
'Astrological Botany',
|
'Astrological Botany',
|
||||||
'Astrological Chemistry',
|
|
||||||
'Biochemical Sorcery',
|
'Biochemical Sorcery',
|
||||||
'Civil Alchemy',
|
'Civil Divination',
|
||||||
'Consecrated Biochemistry',
|
'Consecrated Augury',
|
||||||
'Demonic Anthropology',
|
'Demonic Anthropology',
|
||||||
'Divinatory Mineralogy',
|
'Divinatory Mineralogy',
|
||||||
'Genetic Banishing',
|
|
||||||
'Hermetic Geography',
|
|
||||||
'Immunological Incantations',
|
|
||||||
'Nuclear Illusionism',
|
|
||||||
'Ritual Astronomy',
|
|
||||||
'Seismological Divination',
|
|
||||||
'Spiritual Biochemistry',
|
|
||||||
'Statistical Occultism',
|
|
||||||
'Police Necromancer',
|
|
||||||
'Sixgun Poisoner',
|
|
||||||
'Pharmaceutical Gunslinger',
|
|
||||||
'Infernal Banker',
|
|
||||||
'Spell Analyst',
|
|
||||||
'Gunslinger Corruptor',
|
|
||||||
'Torque Interfacer',
|
|
||||||
'Exo Interfacer',
|
'Exo Interfacer',
|
||||||
|
'Genetic Banishing',
|
||||||
'Gunpowder Torturer',
|
'Gunpowder Torturer',
|
||||||
'Orbital Gravedigger',
|
'Gunslinger Corruptor',
|
||||||
'Phased Linguist',
|
'Hermetic Geography',
|
||||||
'Mathematical Pharmacist',
|
'Immunological Cultist',
|
||||||
'Plasma Outlaw',
|
|
||||||
'Malefic Chemist',
|
'Malefic Chemist',
|
||||||
'Police Cultist'
|
'Mathematical Pharmacy',
|
||||||
|
'Nuclear Biochemistry',
|
||||||
|
'Orbital Gravedigger',
|
||||||
|
'Pharmaceutical Outlaw',
|
||||||
|
'Phased Linguist',
|
||||||
|
'Plasma Gunslinger',
|
||||||
|
'Police Necromancer',
|
||||||
|
'Ritual Astronomy',
|
||||||
|
'Sixgun Poisoner',
|
||||||
|
'Seismological Alchemy',
|
||||||
|
'Spiritual Illusionism',
|
||||||
|
'Statistical Occultism',
|
||||||
|
'Spell Analyst',
|
||||||
|
'Torque Interfacer'
|
||||||
];
|
];
|
||||||
|
|
||||||
const classnames = ['Archivist', 'Fancyman', 'Linguist', 'Fletcher',
|
const classnames = ['Ackerman', 'Berserker-Typist', 'Concierge', 'Fishmonger',
|
||||||
'Notary', 'Berserker-Typist', 'Fishmongerer', 'Manicurist', 'Haberdasher', 'Concierge'];
|
'Haberdasher', 'Manicurist', 'Netrunner', 'Weirkeeper'];
|
||||||
|
|
||||||
const levels = ['1st', '2nd', '3rd', '4th', '5th', '6th', '7th', '8th', '9th', '10th', '11th', '12th', '13th', '14th', '15th', '16th', '17th', '18th', '19th', '20th'];
|
const levels = ['1st', '2nd', '3rd', '4th', '5th',
|
||||||
|
'6th', '7th', '8th', '9th', '10th',
|
||||||
|
'11th', '12th', '13th', '14th', '15th',
|
||||||
|
'16th', '17th', '18th', '19th', '20th'];
|
||||||
|
|
||||||
const profBonus = [2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6];
|
const profBonus = [2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6];
|
||||||
|
|
||||||
const getFeature = (level)=>{
|
const maxes = [4, 3, 3, 3, 3, 2, 2, 1, 1];
|
||||||
let res = [];
|
|
||||||
if(_.includes([4, 6, 8, 12, 14, 16, 19], level+1)){
|
const drawSlots = function(Slots, rows, padding){
|
||||||
res = ['Ability Score Improvement'];
|
let slots = Number(Slots);
|
||||||
}
|
return _.times(rows, function(i){
|
||||||
res = _.union(res, _.sampleSize(features, _.sample([0, 1, 1, 1, 1, 1])));
|
const max = maxes[i];
|
||||||
if(!res.length) return '─';
|
if(slots < 1) return _.pad('—', padding);
|
||||||
return res.join(', ');
|
const res = _.min([max, slots]);
|
||||||
|
slots -= res;
|
||||||
|
return _.pad(res.toString(), padding);
|
||||||
|
}).join(' | ');
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
full : function(){
|
full : function(classes){
|
||||||
const classname = _.sample(classnames);
|
const classname = _.sample(classnames);
|
||||||
|
|
||||||
const maxes = [4, 3, 3, 3, 3, 2, 2, 1, 1];
|
|
||||||
const drawSlots = function(Slots){
|
|
||||||
let slots = Number(Slots);
|
|
||||||
return _.times(9, function(i){
|
|
||||||
const max = maxes[i];
|
|
||||||
if(slots < 1) return '—';
|
|
||||||
const res = _.min([max, slots]);
|
|
||||||
slots -= res;
|
|
||||||
return res;
|
|
||||||
}).join(' | ');
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
let cantrips = 3;
|
let cantrips = 3;
|
||||||
let spells = 1;
|
let spells = 1;
|
||||||
let slots = 2;
|
let slots = 2;
|
||||||
return `{{classTable,wide\n##### The ${classname}\n` +
|
return `{{${classes}\n##### The ${classname}\n` +
|
||||||
`| Level | Proficiency | Features | Cantrips | Spells | --- Spell Slots Per Level --- |||||||||\n`+
|
`| Level | Proficiency | Features | Cantrips | Spells | --- Spell Slots Per Spell Level ---|||||||||\n`+
|
||||||
`| ^| Bonus ^| ^| Known ^| Known ^| 1st | 2nd | 3rd | 4th | 5th | 6th | 7th | 8th | 9th |\n`+
|
`| ^| Bonus ^| ^| Known ^| Known ^|1st |2nd |3rd |4th |5th |6th |7th |8th |9th |\n`+
|
||||||
`|:-----:|:-----------:|:---------|:--------:|:------:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|\n${
|
`|:-----:|:-----------:|:-------------|:--------:|:------:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|\n${
|
||||||
_.map(levels, function(levelName, level){
|
_.map(levels, function(levelName, level){
|
||||||
const res = [
|
const res = [
|
||||||
levelName,
|
_.pad(levelName, 5),
|
||||||
`+${profBonus[level]}`,
|
_.pad(`+${profBonus[level]}`, 2),
|
||||||
getFeature(level),
|
_.padEnd(_.sample(features), 21),
|
||||||
cantrips,
|
_.pad(cantrips.toString(), 8),
|
||||||
spells,
|
_.pad(spells.toString(), 6),
|
||||||
drawSlots(slots)
|
drawSlots(slots, 9, 2),
|
||||||
].join(' | ');
|
].join(' | ');
|
||||||
|
|
||||||
cantrips += _.random(0, 1);
|
cantrips += _.random(0, 1);
|
||||||
@@ -92,24 +83,50 @@ module.exports = {
|
|||||||
}).join('\n')}\n}}\n\n`;
|
}).join('\n')}\n}}\n\n`;
|
||||||
},
|
},
|
||||||
|
|
||||||
half : function(){
|
half : function(classes){
|
||||||
const classname = _.sample(classnames);
|
const classname = _.sample(classnames);
|
||||||
|
|
||||||
let featureScore = 1;
|
let featureScore = 1;
|
||||||
return `<div class='classTable'>\n##### The ${classname}\n` +
|
return `{{${classes}\n##### The ${classname}\n` +
|
||||||
`| Level | Proficiency Bonus | Features | ${_.sample(features)}|\n` +
|
`| Level | Proficiency Bonus | Features | ${_.pad(_.sample(features), 21)} |\n` +
|
||||||
`|:---:|:---:|:---|:---:|\n${
|
`|:-----:|:-----------------:|:---------|:---------------------:|\n${
|
||||||
_.map(levels, function(levelName, level){
|
_.map(levels, function(levelName, level){
|
||||||
const res = [
|
const res = [
|
||||||
levelName,
|
_.pad(levelName, 5),
|
||||||
`+${profBonus[level]}`,
|
_.pad(`+${profBonus[level]}`, 2),
|
||||||
getFeature(level),
|
_.padEnd(_.sample(features), 23),
|
||||||
`+${featureScore}`
|
_.pad(`+${featureScore}`, 21),
|
||||||
].join(' | ');
|
].join(' | ');
|
||||||
|
|
||||||
featureScore += _.random(0, 1);
|
featureScore += _.random(0, 1);
|
||||||
|
|
||||||
return `| ${res} |`;
|
return `| ${res} |`;
|
||||||
}).join('\n')}\n</div>\n\n`;
|
}).join('\n')}\n}}\n\n`;
|
||||||
|
},
|
||||||
|
|
||||||
|
third : function(classes){
|
||||||
|
const classname = _.sample(classnames);
|
||||||
|
|
||||||
|
let cantrips = 3;
|
||||||
|
let spells = 1;
|
||||||
|
let slots = 2;
|
||||||
|
return `{{${classes}\n##### ${classname} Spellcasting\n` +
|
||||||
|
`| Class | Cantrips | Spells |--- Spells Slots per Spell Level ---||||\n` +
|
||||||
|
`| Level ^| Known ^| Known ^| 1st | 2nd | 3rd | 4th |\n` +
|
||||||
|
`|:------:|:--------:|:-------:|:-------:|:-------:|:-------:|:-------:|\n${
|
||||||
|
_.map(levels, function(levelName, level){
|
||||||
|
const res = [
|
||||||
|
_.pad(levelName, 6),
|
||||||
|
_.pad(cantrips.toString(), 8),
|
||||||
|
_.pad(spells.toString(), 7),
|
||||||
|
drawSlots(slots, 4, 7),
|
||||||
|
].join(' | ');
|
||||||
|
|
||||||
|
cantrips += _.random(0, 1);
|
||||||
|
spells += _.random(0, 1);
|
||||||
|
slots += _.random(0, 1);
|
||||||
|
|
||||||
|
return `| ${res} |`;
|
||||||
|
}).join('\n')}\n}}\n\n`;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -60,13 +60,13 @@ module.exports = {
|
|||||||
const levels = ['Cantrips (0 Level)', '1st Level', '2nd Level', '3rd Level', '4th Level', '5th Level', '6th Level', '7th Level', '8th Level', '9th Level'];
|
const levels = ['Cantrips (0 Level)', '1st Level', '2nd Level', '3rd Level', '4th Level', '5th Level', '6th Level', '7th Level', '8th Level', '9th Level'];
|
||||||
|
|
||||||
const content = _.map(levels, (level)=>{
|
const content = _.map(levels, (level)=>{
|
||||||
const spells = _.map(_.sampleSize(spellNames, _.random(5, 15)), (spell)=>{
|
const spells = _.map(_.sampleSize(spellNames, _.random(4, 10)), (spell)=>{
|
||||||
return `- ${spell}`;
|
return `- ${spell}`;
|
||||||
}).join('\n');
|
}).join('\n');
|
||||||
return `##### ${level} \n${spells} \n`;
|
return `##### ${level} \n${spells} \n`;
|
||||||
}).join('\n');
|
}).join('\n');
|
||||||
|
|
||||||
return `{{spellList\n${content}\n}}`;
|
return `{{spellList,wide\n${content}\n}}`;
|
||||||
},
|
},
|
||||||
|
|
||||||
spell : function(){
|
spell : function(){
|
||||||
|
|||||||
@@ -105,6 +105,20 @@ const genAbilities = function(){
|
|||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const genLongAbilities = function(){
|
||||||
|
return _.sample([
|
||||||
|
dedent`***Pack Tactics.*** These guys work together like peanut butter and jelly. Jelly and peanut butter.
|
||||||
|
|
||||||
|
When one of these guys attacks, the target is covered with, well, peanut butter and jelly.`,
|
||||||
|
dedent`***Hangriness.*** This creature is angry, and hungry. It will refuse to do anything with you until its hunger is satisfied.
|
||||||
|
|
||||||
|
When in visual contact with this creature, you must purchase an extra order of fries, even if they say they aren't hungry.`,
|
||||||
|
dedent`***Full of Detergent.*** This creature has swallowed an entire bottle of dish detergent and is actually having a pretty good time.
|
||||||
|
|
||||||
|
While walking near this creature, you must make a dexterity check or become "a soapy mess" for three hours, after which your skin will get all dry and itchy.`
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
const genAction = function(){
|
const genAction = function(){
|
||||||
const name = _.sample([
|
const name = _.sample([
|
||||||
'Abdominal Drop',
|
'Abdominal Drop',
|
||||||
@@ -159,11 +173,11 @@ module.exports = {
|
|||||||
**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)
|
||||||
___
|
___
|
||||||
|
${_.times(_.random(genLines, genLines + 2), function(){return genAbilities();}).join('\n:\n')}
|
||||||
:
|
:
|
||||||
${_.times(_.random(genLines, genLines + 2), function(){return genAbilities();}).join('\n\t\t\t\n\t\t\t')}
|
${genLongAbilities()}
|
||||||
:
|
|
||||||
### Actions
|
### Actions
|
||||||
${_.times(_.random(genLines, genLines + 2), function(){return genAction();}).join('\n\t\t\t\n\t\t\t')}
|
${_.times(_.random(genLines, genLines + 2), function(){return genAction();}).join('\n:\n')}
|
||||||
}}
|
}}
|
||||||
\n`;
|
\n`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,13 @@ const ClassFeatureGen = require('./classfeature.gen.js');
|
|||||||
const CoverPageGen = require('./coverpage.gen.js');
|
const CoverPageGen = require('./coverpage.gen.js');
|
||||||
const TableOfContentsGen = require('./tableOfContents.gen.js');
|
const TableOfContentsGen = require('./tableOfContents.gen.js');
|
||||||
const dedent = require('dedent-tabs').default;
|
const dedent = require('dedent-tabs').default;
|
||||||
|
const watercolorGen = require('./watercolor.gen.js');
|
||||||
|
|
||||||
|
|
||||||
module.exports = [
|
module.exports = [
|
||||||
|
|
||||||
{
|
{
|
||||||
groupName : 'Editor',
|
groupName : 'Text Editor',
|
||||||
icon : 'fas fa-pencil-alt',
|
icon : 'fas fa-pencil-alt',
|
||||||
view : 'text',
|
view : 'text',
|
||||||
snippets : [
|
snippets : [
|
||||||
@@ -43,33 +44,11 @@ module.exports = [
|
|||||||
{{wide
|
{{wide
|
||||||
Everything in here will be extra wide. Tables, text, everything!
|
Everything in here will be extra wide. Tables, text, everything!
|
||||||
Beware though, CSS columns can behave a bit weird sometimes. You may
|
Beware though, CSS columns can behave a bit weird sometimes. You may
|
||||||
have to rely on the automatic column-break rather than \`\column\` if
|
have to manually place column breaks with \`\column\` to make the
|
||||||
you mix columns and wide blocks on the same page.
|
surrounding text flow with this wide block the way you want.
|
||||||
}}
|
}}
|
||||||
\n`
|
\n`
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name : 'Image',
|
|
||||||
icon : 'fas fa-image',
|
|
||||||
gen : dedent`
|
|
||||||
 {width:325px,mix-blend-mode:multiply}
|
|
||||||
|
|
||||||
{{artist,position:relative,top:-230px,left:-100px,margin-bottom:-30px
|
|
||||||
##### Cat Warrior
|
|
||||||
[Kyoung Hwan Kim](https://www.artstation.com/tahra)
|
|
||||||
}}`
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name : 'Background Image',
|
|
||||||
icon : 'fas fa-tree',
|
|
||||||
gen : dedent`
|
|
||||||
 {position:absolute,top:50px,right:30px,width:280px}
|
|
||||||
|
|
||||||
{{artist,top:90px,right:30px
|
|
||||||
##### Homebrew Mug
|
|
||||||
[naturalcrit](https://homebrew.naturalcrit.com)
|
|
||||||
}}`
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name : 'QR Code',
|
name : 'QR Code',
|
||||||
icon : 'fas fa-qrcode',
|
icon : 'fas fa-qrcode',
|
||||||
@@ -79,7 +58,6 @@ module.exports = [
|
|||||||
`https://homebrewery.naturalcrit.com/share/${brew.shareId}` +
|
`https://homebrewery.naturalcrit.com/share/${brew.shareId}` +
|
||||||
`&size=100x100) {width:100px;mix-blend-mode:multiply}`;
|
`&size=100x100) {width:100px;mix-blend-mode:multiply}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name : 'Page Number',
|
name : 'Page Number',
|
||||||
@@ -101,35 +79,83 @@ module.exports = [
|
|||||||
icon : 'fas fa-book',
|
icon : 'fas fa-book',
|
||||||
gen : TableOfContentsGen
|
gen : TableOfContentsGen
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name : 'Add Comment',
|
||||||
|
icon : 'fas fa-code',
|
||||||
|
gen : '<!-- This is a comment that will not be rendered into your brew. Hotkey (Ctrl/Cmd + /). -->'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
groupName : 'Style Editor',
|
||||||
|
icon : 'fas fa-pencil-alt',
|
||||||
|
view : 'style',
|
||||||
|
snippets : [
|
||||||
{
|
{
|
||||||
name : 'Remove Drop Cap',
|
name : 'Remove Drop Cap',
|
||||||
icon : 'fas fa-remove-format',
|
icon : 'fas fa-remove-format',
|
||||||
gen : '<style>\n' +
|
gen : dedent`/* Removes Drop Caps */
|
||||||
' .phb3 h1+p:first-letter {\n' +
|
.page h1+p:first-letter {
|
||||||
' all: unset;\n' +
|
all: unset;
|
||||||
' }\n' +
|
}\n\n`
|
||||||
'</style>'
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name : 'Tweak Drop Cap',
|
name : 'Tweak Drop Cap',
|
||||||
icon : 'fas fa-sliders-h',
|
icon : 'fas fa-sliders-h',
|
||||||
gen : '<style>\n' +
|
gen : dedent`/* Drop Cap settings */
|
||||||
' /* Drop Cap settings */\n' +
|
.page h1 + p::first-letter {
|
||||||
' .phb3 h1 + p::first-letter {\n' +
|
font-family: SolberaImitationRemake;
|
||||||
' float: left;\n' +
|
font-size: 3.5cm;
|
||||||
' font-family: SolberaImitationRemake;\n' +
|
background-image: linear-gradient(-45deg, #322814, #998250, #322814);
|
||||||
' font-size: 3.5cm;\n' +
|
line-height: 1em;
|
||||||
' color: #222;\n' +
|
}\n\n`
|
||||||
' line-height: .8em;\n' +
|
|
||||||
' }\n' +
|
|
||||||
'</style>'
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name : 'Add Comment',
|
name : 'Add Comment',
|
||||||
icon : 'fas fa-code', /* might need to be fa-solid fa-comment-code --not sure, Gazook */
|
icon : 'fas fa-code',
|
||||||
gen : dedent`\n
|
gen : '/* This is a comment that will not be rendered into your brew. */'
|
||||||
<!-- This is a comment that will not be rendered into your brew. Hotkey (Ctrl/Cmd + /). -->
|
},
|
||||||
`
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
/*********************** IMAGES *******************/
|
||||||
|
{
|
||||||
|
groupName : 'Images',
|
||||||
|
icon : 'fas fa-images',
|
||||||
|
view : 'text',
|
||||||
|
snippets : [
|
||||||
|
{
|
||||||
|
name : 'Image',
|
||||||
|
icon : 'fas fa-image',
|
||||||
|
gen : dedent`
|
||||||
|
 {width:325px,mix-blend-mode:multiply}
|
||||||
|
|
||||||
|
{{artist,position:relative,top:-230px,left:10px,margin-bottom:-30px
|
||||||
|
##### Cat Warrior
|
||||||
|
[Kyoung Hwan Kim](https://www.artstation.com/tahra)
|
||||||
|
}}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'Background Image',
|
||||||
|
icon : 'fas fa-tree',
|
||||||
|
gen : dedent`
|
||||||
|
 {position:absolute,top:50px,right:30px,width:280px}
|
||||||
|
|
||||||
|
{{artist,top:80px,right:30px
|
||||||
|
##### Homebrew Mug
|
||||||
|
[naturalcrit](https://homebrew.naturalcrit.com)
|
||||||
|
}}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'Watercolor Splatter',
|
||||||
|
icon : 'fas fa-fill-drip',
|
||||||
|
gen : watercolorGen,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'Watermark',
|
||||||
|
icon : 'fas fa-id-card',
|
||||||
|
gen : dedent`
|
||||||
|
{{watermark Homebrewery}}\n`
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -234,16 +260,6 @@ module.exports = [
|
|||||||
icon : 'fas fa-table',
|
icon : 'fas fa-table',
|
||||||
view : 'text',
|
view : 'text',
|
||||||
snippets : [
|
snippets : [
|
||||||
{
|
|
||||||
name : 'Class Table',
|
|
||||||
icon : 'fas fa-table',
|
|
||||||
gen : ClassTableGen.full,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name : 'Half Class Table',
|
|
||||||
icon : 'fas fa-list-alt',
|
|
||||||
gen : ClassTableGen.half,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name : 'Table',
|
name : 'Table',
|
||||||
icon : 'fas fa-th-list',
|
icon : 'fas fa-th-list',
|
||||||
@@ -303,6 +319,36 @@ module.exports = [
|
|||||||
}}
|
}}
|
||||||
\n`;
|
\n`;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'Class Table',
|
||||||
|
icon : 'fas fa-table',
|
||||||
|
gen : ClassTableGen.full('classTable,frame,decoration,wide'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'Class Table (unframed)',
|
||||||
|
icon : 'fas fa-border-none',
|
||||||
|
gen : ClassTableGen.full('classTable,wide'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : '1/2 Class Table',
|
||||||
|
icon : 'fas fa-list-alt',
|
||||||
|
gen : ClassTableGen.half('classTable,decoration,frame'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : '1/2 Class Table (unframed)',
|
||||||
|
icon : 'fas fa-border-none',
|
||||||
|
gen : ClassTableGen.half('classTable'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : '1/3 Class Table',
|
||||||
|
icon : 'fas fa-border-all',
|
||||||
|
gen : ClassTableGen.third('classTable,frame'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : '1/3 Class Table (unframed)',
|
||||||
|
icon : 'fas fa-border-none',
|
||||||
|
gen : ClassTableGen.third('classTable'),
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -320,44 +366,36 @@ module.exports = [
|
|||||||
{
|
{
|
||||||
name : 'A4 Page Size',
|
name : 'A4 Page Size',
|
||||||
icon : 'far fa-file',
|
icon : 'far fa-file',
|
||||||
gen : ['/* A4 Page Size */',
|
gen : dedent`/* A4 Page Size */
|
||||||
'.page{',
|
.page{
|
||||||
' width : 210mm;',
|
width : 210mm;
|
||||||
' height : 296.8mm;',
|
height : 296.8mm;
|
||||||
'}',
|
}\n\n`
|
||||||
''
|
|
||||||
].join('\n')
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name : 'Square Page Size',
|
name : 'Square Page Size',
|
||||||
icon : 'far fa-file',
|
icon : 'far fa-file',
|
||||||
gen : ['/* Square Page Size */',
|
gen : dedent`/* Square Page Size */
|
||||||
'.page {',
|
.page {
|
||||||
' width : 125mm;',
|
width : 125mm;
|
||||||
' height : 125mm;',
|
height : 125mm;
|
||||||
' padding : 12.5mm;',
|
padding : 12.5mm;
|
||||||
' columns : unset;',
|
columns : unset;
|
||||||
'}',
|
}\n\n`
|
||||||
''
|
|
||||||
].join('\n')
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name : 'Ink Friendly',
|
name : 'Ink Friendly',
|
||||||
icon : 'fas fa-tint',
|
icon : 'fas fa-tint',
|
||||||
gen : dedent`
|
gen : dedent`
|
||||||
/* Ink Friendly */
|
/* Ink Friendly */
|
||||||
.pages *:is(.page,.monster,.note,.descriptive) {
|
*:is(.page,.monster,.note,.descriptive) {
|
||||||
background : white !important;
|
background : white !important;
|
||||||
box-shadow : 0px 0px 3px !important;
|
filter : drop-shadow(0px 0px 3px #888) !important;
|
||||||
}
|
|
||||||
|
|
||||||
.page .note:before {
|
|
||||||
box-shadow : 0px 0px 3px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.page img {
|
.page img {
|
||||||
visibility : hidden;
|
visibility : hidden;
|
||||||
}`
|
}\n\n`
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -53,19 +53,19 @@ module.exports = function(brew){
|
|||||||
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) {
|
if(g1.title !== null) {
|
||||||
r.push(`\t\t- ### [{{ ${g1.title}}}{{ ${g1.page}}}](#p${g1.page})`);
|
r.push(`- ### [{{ ${g1.title}}}{{ ${g1.page}}}](#p${g1.page})`);
|
||||||
}
|
}
|
||||||
if(g1.children.length){
|
if(g1.children.length){
|
||||||
_.each(g1.children, (g2, idx2)=>{
|
_.each(g1.children, (g2, idx2)=>{
|
||||||
if(g2.title !== null) {
|
if(g2.title !== null) {
|
||||||
r.push(`\t\t - #### [{{ ${g2.title}}}{{ ${g2.page}}}](#p${g2.page})`);
|
r.push(` - #### [{{ ${g2.title}}}{{ ${g2.page}}}](#p${g2.page})`);
|
||||||
}
|
}
|
||||||
if(g2.children.length){
|
if(g2.children.length){
|
||||||
_.each(g2.children, (g3, idx3)=>{
|
_.each(g2.children, (g3, idx3)=>{
|
||||||
if(g2.title !== null) {
|
if(g2.title !== null) {
|
||||||
r.push(`\t\t - [{{ ${g3.title}}}{{ ${g3.page}}}](#p${g3.page})`);
|
r.push(` - [{{ ${g3.title}}}{{ ${g3.page}}}](#p${g3.page})`);
|
||||||
} else { // Don't over-indent if no level-2 parent entry
|
} else { // Don't over-indent if no level-2 parent entry
|
||||||
r.push(`\t\t - [{{ ${g3.title}}}{{ ${g3.page}}}](#p${g3.page})`);
|
r.push(` - [{{ ${g3.title}}}{{ ${g3.page}}}](#p${g3.page})`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -78,7 +78,7 @@ module.exports = function(brew){
|
|||||||
{{toc,wide
|
{{toc,wide
|
||||||
# Table Of Contents
|
# Table Of Contents
|
||||||
|
|
||||||
${markdown}
|
${markdown}
|
||||||
}}
|
}}
|
||||||
\n`;
|
\n`;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
const _ = require('lodash');
|
||||||
|
|
||||||
|
module.exports = ()=>{
|
||||||
|
return `{{watercolor${_.random(1, 12)},top:20px,left:30px,width:300px,background-color:#BBAD82,opacity:80%}}\n\n`;
|
||||||
|
};
|
||||||
@@ -11,7 +11,7 @@ const dedent = require('dedent-tabs').default;
|
|||||||
module.exports = [
|
module.exports = [
|
||||||
|
|
||||||
{
|
{
|
||||||
groupName : 'Editor',
|
groupName : 'Text Editor',
|
||||||
icon : 'fas fa-pencil-alt',
|
icon : 'fas fa-pencil-alt',
|
||||||
view : 'text',
|
view : 'text',
|
||||||
snippets : [
|
snippets : [
|
||||||
@@ -78,33 +78,44 @@ module.exports = [
|
|||||||
icon : 'fas fa-book',
|
icon : 'fas fa-book',
|
||||||
gen : TableOfContentsGen
|
gen : TableOfContentsGen
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name : 'Add Comment',
|
||||||
|
icon : 'fas fa-code',
|
||||||
|
gen : '<!-- This is a comment that will not be rendered into your brew. Hotkey (Ctrl/Cmd + /). -->'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
groupName : 'Style Editor',
|
||||||
|
icon : 'fas fa-pencil-alt',
|
||||||
|
view : 'style',
|
||||||
|
snippets : [
|
||||||
{
|
{
|
||||||
name : 'Remove Drop Cap',
|
name : 'Remove Drop Cap',
|
||||||
icon : 'fas fa-remove-format',
|
icon : 'fas fa-remove-format',
|
||||||
gen : '<style>\n' +
|
gen : dedent`/* Removes Drop Caps */
|
||||||
' .phb h1+p:first-letter {\n' +
|
.phb h1+p:first-letter {
|
||||||
' all: unset;\n' +
|
all: unset;
|
||||||
' }\n' +
|
}\n\n`
|
||||||
'</style>'
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name : 'Tweak Drop Cap',
|
name : 'Tweak Drop Cap',
|
||||||
icon : 'fas fa-sliders-h',
|
icon : 'fas fa-sliders-h',
|
||||||
gen : '<style>\n' +
|
gen : dedent`/* Drop Cap Settings */
|
||||||
' /* Drop Cap settings */\n' +
|
.phb h1 + p::first-letter {
|
||||||
' .phb h1 + p::first-letter {\n' +
|
float: left;
|
||||||
' float: left;\n' +
|
font-family: Solberry;
|
||||||
' font-family: Solberry;\n' +
|
font-size: 10em;
|
||||||
' font-size: 10em;\n' +
|
color: #222;
|
||||||
' color: #222;\n' +
|
line-height: .8em;
|
||||||
' line-height: .8em;\n' +
|
}\n\n`
|
||||||
' }\n' +
|
|
||||||
'</style>'
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name : 'Add Comment',
|
name : 'Add Comment',
|
||||||
icon : 'fas fa-code',
|
icon : 'fas fa-code',
|
||||||
gen : `\n<!-- This is a comment that will not be rendered into your brew. Hotkey (Ctrl/Cmd + /). -->\n\n`
|
gen : '/* This is a comment that will not be rendered into your brew. */'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -240,30 +251,25 @@ module.exports = [
|
|||||||
{
|
{
|
||||||
name : 'Split Table',
|
name : 'Split Table',
|
||||||
icon : 'fas fa-th-large',
|
icon : 'fas fa-th-large',
|
||||||
gen : function(){
|
gen : dedent`\n
|
||||||
return [
|
<div style='column-count:2'>
|
||||||
'<div style=\'column-count:2\'>',
|
| d10 | Damage Type |
|
||||||
'| d10 | Damage Type |',
|
|:---:|:------------|
|
||||||
'|:---:|:------------|',
|
| 1 | Acid |
|
||||||
'| 1 | Acid |',
|
| 2 | Cold |
|
||||||
'| 2 | Cold |',
|
| 3 | Fire |
|
||||||
'| 3 | Fire |',
|
| 4 | Force |
|
||||||
'| 4 | Force |',
|
| 5 | Lightning |
|
||||||
'| 5 | Lightning |',
|
|
||||||
'',
|
| d10 | Damage Type |
|
||||||
'```',
|
|:---:|:------------|
|
||||||
'```',
|
| 6 | Necrotic |
|
||||||
'',
|
| 7 | Poison |
|
||||||
'| d10 | Damage Type |',
|
| 8 | Psychic |
|
||||||
'|:---:|:------------|',
|
| 9 | Radiant |
|
||||||
'| 6 | Necrotic |',
|
| 10 | Thunder |
|
||||||
'| 7 | Poison |',
|
</div>
|
||||||
'| 8 | Psychic |',
|
\n`
|
||||||
'| 9 | Radiant |',
|
|
||||||
'| 10 | Thunder |',
|
|
||||||
'</div>\n\n',
|
|
||||||
].join('\n');
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -305,7 +311,7 @@ module.exports = [
|
|||||||
name : 'Ink Friendly',
|
name : 'Ink Friendly',
|
||||||
icon : 'fas fa-tint',
|
icon : 'fas fa-tint',
|
||||||
gen : dedent`
|
gen : dedent`
|
||||||
/* Ink Friendly */',
|
/* Ink Friendly */
|
||||||
.phb, .phb blockquote, .phb hr+blockquote {
|
.phb, .phb blockquote, .phb hr+blockquote {
|
||||||
background : white;
|
background : white;
|
||||||
box-shadow : 0px 0px 3px;
|
box-shadow : 0px 0px 3px;
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ const Homebrew = createClass({
|
|||||||
<Route path='/print/:id' component={(routeProps)=><PrintPage brew={this.props.brew} query={queryString.parse(routeProps.location.search)} />}/>
|
<Route path='/print/:id' component={(routeProps)=><PrintPage brew={this.props.brew} query={queryString.parse(routeProps.location.search)} />}/>
|
||||||
<Route path='/print' exact component={(routeProps)=><PrintPage query={queryString.parse(routeProps.location.search)} />}/>
|
<Route path='/print' exact component={(routeProps)=><PrintPage query={queryString.parse(routeProps.location.search)} />}/>
|
||||||
<Route path='/changelog' exact component={()=><SharePage brew={this.props.brew} />}/>
|
<Route path='/changelog' exact component={()=><SharePage brew={this.props.brew} />}/>
|
||||||
|
<Route path='/faq' exact component={()=><SharePage brew={this.props.brew} />}/>
|
||||||
<Route path='/v3_preview' exact component={()=><HomePage brew={this.props.brew} />}/>
|
<Route path='/v3_preview' exact component={()=><HomePage brew={this.props.brew} />}/>
|
||||||
<Route path='/' component={()=><HomePage brew={this.props.brew} />}/>
|
<Route path='/' component={()=><HomePage brew={this.props.brew} />}/>
|
||||||
</Switch>
|
</Switch>
|
||||||
|
|||||||
@@ -196,11 +196,14 @@ const EditPage = createClass({
|
|||||||
|
|
||||||
const transfer = this.state.saveGoogle == _.isNil(this.state.brew.googleId);
|
const transfer = this.state.saveGoogle == _.isNil(this.state.brew.googleId);
|
||||||
|
|
||||||
|
const brew = this.state.brew;
|
||||||
|
brew.pageCount = ((brew.renderer=='legacy' ? brew.text.match(/\\page/g) : brew.text.match(/^\\page$/gm)) || []).length + 1;
|
||||||
|
|
||||||
if(this.state.saveGoogle) {
|
if(this.state.saveGoogle) {
|
||||||
if(transfer) {
|
if(transfer) {
|
||||||
const res = await request
|
const res = await request
|
||||||
.post('/api/newGoogle/')
|
.post('/api/newGoogle/')
|
||||||
.send(this.state.brew)
|
.send(brew)
|
||||||
.catch((err)=>{
|
.catch((err)=>{
|
||||||
console.log(err.status === 401
|
console.log(err.status === 401
|
||||||
? 'Not signed in!'
|
? 'Not signed in!'
|
||||||
@@ -211,7 +214,7 @@ const EditPage = createClass({
|
|||||||
if(!res) { return; }
|
if(!res) { return; }
|
||||||
|
|
||||||
console.log('Deleting Local Copy');
|
console.log('Deleting Local Copy');
|
||||||
await request.delete(`/api/${this.state.brew.editId}`)
|
await request.delete(`/api/${brew.editId}`)
|
||||||
.send()
|
.send()
|
||||||
.catch((err)=>{
|
.catch((err)=>{
|
||||||
console.log('Error deleting Local Copy');
|
console.log('Error deleting Local Copy');
|
||||||
@@ -221,8 +224,8 @@ const EditPage = createClass({
|
|||||||
history.replaceState(null, null, `/edit/${this.savedBrew.googleId}${this.savedBrew.editId}`); //update URL to match doc ID
|
history.replaceState(null, null, `/edit/${this.savedBrew.googleId}${this.savedBrew.editId}`); //update URL to match doc ID
|
||||||
} else {
|
} else {
|
||||||
const res = await request
|
const res = await request
|
||||||
.put(`/api/updateGoogle/${this.state.brew.editId}`)
|
.put(`/api/updateGoogle/${brew.editId}`)
|
||||||
.send(this.state.brew)
|
.send(brew)
|
||||||
.catch((err)=>{
|
.catch((err)=>{
|
||||||
console.log(err.status === 401
|
console.log(err.status === 401
|
||||||
? 'Not signed in!'
|
? 'Not signed in!'
|
||||||
@@ -236,14 +239,14 @@ const EditPage = createClass({
|
|||||||
} else {
|
} else {
|
||||||
if(transfer) {
|
if(transfer) {
|
||||||
const res = await request.post('/api')
|
const res = await request.post('/api')
|
||||||
.send(this.state.brew)
|
.send(brew)
|
||||||
.catch((err)=>{
|
.catch((err)=>{
|
||||||
console.log('Error creating Local Copy');
|
console.log('Error creating Local Copy');
|
||||||
this.setState({ errors: err });
|
this.setState({ errors: err });
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
|
|
||||||
await request.get(`/api/removeGoogle/${this.state.brew.googleId}${this.state.brew.editId}`)
|
await request.get(`/api/removeGoogle/${brew.googleId}${brew.editId}`)
|
||||||
.send()
|
.send()
|
||||||
.catch((err)=>{
|
.catch((err)=>{
|
||||||
console.log('Error Deleting Google Brew');
|
console.log('Error Deleting Google Brew');
|
||||||
@@ -253,8 +256,8 @@ const EditPage = createClass({
|
|||||||
history.replaceState(null, null, `/edit/${this.savedBrew.editId}`); //update URL to match doc ID
|
history.replaceState(null, null, `/edit/${this.savedBrew.editId}`); //update URL to match doc ID
|
||||||
} else {
|
} else {
|
||||||
const res = await request
|
const res = await request
|
||||||
.put(`/api/update/${this.state.brew.editId}`)
|
.put(`/api/update/${brew.editId}`)
|
||||||
.send(this.state.brew)
|
.send(brew)
|
||||||
.catch((err)=>{
|
.catch((err)=>{
|
||||||
console.log('Error Updating Local Brew');
|
console.log('Error Updating Local Brew');
|
||||||
this.setState({ errors: err });
|
this.setState({ errors: err });
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Welcome traveler from an antique land. Please sit and tell us of what you have s
|
|||||||
### Homebrew D&D made easy
|
### Homebrew D&D made easy
|
||||||
The Homebrewery makes the creation and sharing of authentic looking Fifth-Edition homebrews easy. It uses [Markdown](https://help.github.com/articles/markdown-basics/) with a little CSS magic to make your brews come to life.
|
The Homebrewery makes the creation and sharing of authentic looking Fifth-Edition homebrews easy. It uses [Markdown](https://help.github.com/articles/markdown-basics/) with a little CSS magic to make your brews come to life.
|
||||||
|
|
||||||
**Try it! **Simply edit the text on the left and watch it *update live* on the right.
|
**Try it!** Simply edit the text on the left and watch it *update live* on the right.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -36,8 +36,10 @@ This tool will **always** be free, never have ads, and I will never offer any "p
|
|||||||
```
|
```
|
||||||
```
|
```
|
||||||
|
|
||||||
## Big things coming in v3.0.0
|
## V3.0.0 Released!
|
||||||
With the next major release of Homebrewery, v3.0.0, this tool *will no longer support raw HTML input for brew code*. All brews made previous to the release of v3.0.0 will still render normally.
|
With the latest major update to *The Homebrewery* we've implemented an extended Markdown-like syntax for block and span elements, plus a few other changes, eliminating the need for HTML tags like **div** and **span** in most cases. No raw HTML tags should be needed in a brew, and going forward, raw HTML will no longer receive debugging support (*but can still be used if you insist*).
|
||||||
|
|
||||||
|
**You can enable V3 via the <span class="fa fa-info-circle" style="text-indent:0"></span> Properties button!**
|
||||||
|
|
||||||
## New Things All The Time!
|
## New Things All The Time!
|
||||||
What's new in the latest update? Check out the full changelog [here](/changelog)
|
What's new in the latest update? Check out the full changelog [here](/changelog)
|
||||||
@@ -46,9 +48,9 @@ What's new in the latest update? Check out the full changelog [here](/changelog)
|
|||||||
Have an idea of how to make The Homebrewery better? Or did you find something that wasn't quite right? Head [here](https://www.reddit.com/r/homebrewery/submit?selftext=true&title=%5BIssue%5D%20Describe%20Your%20Issue%20Here) and let me know!.
|
Have an idea of how to make The Homebrewery better? Or did you find something that wasn't quite right? Head [here](https://www.reddit.com/r/homebrewery/submit?selftext=true&title=%5BIssue%5D%20Describe%20Your%20Issue%20Here) and let me know!.
|
||||||
|
|
||||||
### Legal Junk
|
### Legal Junk
|
||||||
The Homebrewery is licensed using the [MIT License](https://github.com/naturalcrit/homebrewery/blob/master/license). Which means you are free to use The Homebrewery is any way that you want, except for claiming that you made it yourself.
|
The Homebrewery is licensed using the [MIT License](https://github.com/naturalcrit/homebrewery/blob/master/license). This means you are free to use The Homebrewery codebase any way that you want, except for claiming that you made it yourself.
|
||||||
|
|
||||||
If you wish to sell or in some way gain profit for what's created on this site, it's your responsibility to ensure you have the proper licenses/rights for any images or resources used.
|
If you wish to sell or in some way gain profit for what you make on this site, it's your responsibility to ensure you have the proper licenses/rights for any images or resources used.
|
||||||
|
|
||||||
### More Resources
|
### More Resources
|
||||||
If you are looking for more 5e Homebrew resources check out [r/UnearthedArcana](https://www.reddit.com/r/UnearthedArcana/) and their list of useful resources [here](https://www.reddit.com/r/UnearthedArcana/comments/3uwxx9/resources_open_to_the_community/).
|
If you are looking for more 5e Homebrew resources check out [r/UnearthedArcana](https://www.reddit.com/r/UnearthedArcana/) and their list of useful resources [here](https://www.reddit.com/r/UnearthedArcana/comments/3uwxx9/resources_open_to_the_community/).
|
||||||
|
|||||||
@@ -4,10 +4,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.page {
|
.page {
|
||||||
padding-bottom : 1.6cm;
|
padding-bottom : 1.1cm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
# The Homebrewery *V3*
|
# The Homebrewery *V3*
|
||||||
@@ -25,26 +23,31 @@ Any changes you make while on the *edit url* will be automatically saved to the
|
|||||||
|
|
||||||
Anyone with the *share url* will be able to access a read-only version of your homebrew.
|
Anyone with the *share url* will be able to access a read-only version of your homebrew.
|
||||||
|
|
||||||
### PDF Creation
|
{{note
|
||||||
|
##### PDF Creation
|
||||||
PDF Printing works best in Google Chrome. If you are having quality/consistency issues, try using Chrome to print instead.
|
PDF Printing works best in Google Chrome. If you are having quality/consistency issues, try using Chrome to print instead.
|
||||||
|
|
||||||
After clicking the "Print" item in the navbar a new page will open and a print dialog will pop-up.
|
After clicking the "Print" item in the navbar a new page will open and a print dialog will pop-up.
|
||||||
* Set the **Destination** to "Save as PDF"
|
* Set the **Destination** to "Save as PDF"
|
||||||
* Set **Paper Size** to "Letter"
|
* Set **Paper Size** to "Letter"
|
||||||
* If you are printing on A4 paper, make sure to have the {{far,fa-file}} **A4 Pagesize** snippet in your brew
|
* If you are printing on A4 paper, make sure to have the **PRINT → {{far,fa-file}} A4 Pagesize** snippet in your brew
|
||||||
* In **Options** make sure "Background Images" is selected.
|
* In **Options** make sure "Background Images" is selected.
|
||||||
* Hit print and enjoy! You're done!
|
* Hit print and enjoy! You're done!
|
||||||
|
|
||||||
If you want to save ink or have a monochrome printer, add the {{fas,fa-tint}} **Ink Friendly** snippet to your brew before you print
|
If you want to save ink or have a monochrome printer, add the **PRINT → {{fas,fa-tint}} Ink Friendly** snippet to your brew before you print
|
||||||
|
}}
|
||||||
|
|
||||||
|
<img src='https://i.imgur.com/hMna6G0.png' style='position:absolute;bottom:50px;left:120px;width:180px' />
|
||||||
|
|
||||||
|
<div class='pageNumber'>1</div>
|
||||||
|
<div class='footnote'>PART 1 | FANCINESS</div>
|
||||||
|
|
||||||
\column
|
\column
|
||||||
|
|
||||||
## New in V3.0.0
|
## New in V3.0.0
|
||||||
With the latest major update to *The Homebrewery* we've implemented an extended Markdown-like syntax for block and span elements, plus a few other changes, eliminating the need for HTML tags like `div` and `span` in most cases. No raw HTML tags should be needed in a brew, and going forward, raw HTML will no longer receive debugging support (*but can still be used if you insist*).
|
With the latest major update to *The Homebrewery* we've implemented an extended Markdown-like syntax for block and span elements, plus a few other changes, eliminating the need for HTML tags like `div` and `span` in most cases. No raw HTML tags should be needed in a brew, and going forward, raw HTML will no longer receive debugging support (*but can still be used if you insist*).
|
||||||
|
|
||||||
All brews made prior to the release of v3.0.0 will still render normally, and you may switch between the "legacy" brew renderer and the newer "V3" renderer via the {{fa,fa-info-circle}} **Properties** button on your brew. Much of the syntax and styling has changed in V3, so code in one version may be broken in the other.
|
Much of the syntax and styling has changed in V3. Code in one version may be broken in the other, and updating an older brew to V3 will require more than just a copy and paste. *However*, all brews made prior to the release of v3.0.0 will still render normally, and you may switch between the "Legacy" brew renderer and the newer "V3" renderer via the {{fa,fa-info-circle}} **Properties** button on your brew at any time.
|
||||||
|
|
||||||
Scroll down to the next page for a brief summary of the changes and new features available in V3!
|
Scroll down to the next page for a brief summary of the changes and new features available in V3!
|
||||||
|
|
||||||
@@ -61,29 +64,18 @@ Need help getting started or just the right look for your brew? Head to [r/Homeb
|
|||||||
|
|
||||||
Have an idea to make The Homebrewery better? Or did you find something that wasn't quite right? Check out the [GitHub Repo](https://github.com/naturalcrit/homebrewery/) to report technical issues.
|
Have an idea to make The Homebrewery better? Or did you find something that wasn't quite right? Check out the [GitHub Repo](https://github.com/naturalcrit/homebrewery/) to report technical issues.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Legal Junk
|
### Legal Junk
|
||||||
The Homebrewery is licensed using the [MIT License](https://github.com/naturalcrit/homebrewery/blob/master/license). Which means you are free to use The Homebrewery codebase any way that you want, except for claiming that you made it yourself.
|
The Homebrewery is licensed using the [MIT License](https://github.com/naturalcrit/homebrewery/blob/master/license). Which means you are free to use The Homebrewery codebase any way that you want, except for claiming that you made it yourself.
|
||||||
|
|
||||||
If you wish to sell or in some way gain profit for what's created on this site, it's your responsibility to ensure you have the proper licenses/rights for any images or resources used.
|
If you wish to sell or in some way gain profit for what's created on this site, it's your responsibility to ensure you have the proper licenses/rights for any images or resources used.
|
||||||
|
|
||||||
#### Crediting Me
|
#### Crediting Me
|
||||||
If you'd like to credit The Homebrewery in your brew, I'd be flattered! Just reference that you made it with The Homebrewery.
|
If you'd like to credit me in your brew, I'd be flattered! Just reference that you made it with The Homebrewery.
|
||||||
|
|
||||||
### More Resources
|
### More Resources
|
||||||
If you are looking for more 5e Homebrew resources check out [r/UnearthedArcana](https://www.reddit.com/r/UnearthedArcana/) and their list of useful resources [here](https://www.reddit.com/r/UnearthedArcana/comments/3uwxx9/resources_open_to_the_community/).
|
If you are looking for more 5e Homebrew resources check out [r/UnearthedArcana](https://www.reddit.com/r/UnearthedArcana/) and their list of useful resources [here](https://www.reddit.com/r/UnearthedArcana/comments/3uwxx9/resources_open_to_the_community/).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<img src='https://i.imgur.com/hMna6G0.png' style='position:absolute;bottom:50px;left:120px;width:180px' />
|
|
||||||
|
|
||||||
<div class='pageNumber'>1</div>
|
|
||||||
<div class='footnote'>PART 1 | FANCINESS</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
\page
|
\page
|
||||||
|
|
||||||
## Markdown+
|
## Markdown+
|
||||||
@@ -145,9 +137,9 @@ Row spanning is achieved by adding a `^` at the end of a cell just before the `|
|
|||||||
These can be combined to span a cell across both columns and rows. Cells must have the same colspan if they are to be rowspan'd.
|
These can be combined to span a cell across both columns and rows. Cells must have the same colspan if they are to be rowspan'd.
|
||||||
|
|
||||||
##### Example
|
##### Example
|
||||||
| | Spanned Header ||
|
| Head A | Spanned Header ||
|
||||||
| Head A | Head B | Head C |
|
| Head B | Head C | Head D |
|
||||||
|:-------|:-------|:-------|
|
|:-------|:------:|:------:|
|
||||||
| 1A | 1B | 1C |
|
| 1A | 1B | 1C |
|
||||||
| 2A ^| 2B | 2C |
|
| 2A ^| 2B | 2C |
|
||||||
| 3A ^| 3B 3C ||
|
| 3A ^| 3B 3C ||
|
||||||
@@ -155,7 +147,6 @@ These can be combined to span a cell across both columns and rows. Cells must ha
|
|||||||
| 5A ^| 5B | 5C |
|
| 5A ^| 5B | 5C |
|
||||||
| 6A | 6B ^| 6C |
|
| 6A | 6B ^| 6C |
|
||||||
|
|
||||||
|
|
||||||
## Images
|
## Images
|
||||||
Images must be hosted online somewhere, like [Imgur](https://www.imgur.com). You use the address to that image to reference it in your brew\*. Images can be included using Markdown-style images.
|
Images must be hosted online somewhere, like [Imgur](https://www.imgur.com). You use the address to that image to reference it in your brew\*. Images can be included using Markdown-style images.
|
||||||
|
|
||||||
|
|||||||
@@ -161,6 +161,8 @@ const NewPage = createClass({
|
|||||||
brew.text = brew.text.slice(index + 5);
|
brew.text = brew.text.slice(index + 5);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
brew.pageCount=((brew.renderer=='legacy' ? brew.text.match(/\\page/g) : brew.text.match(/^\\page$/gm)) || []).length + 1;
|
||||||
|
|
||||||
if(this.state.saveGoogle) {
|
if(this.state.saveGoogle) {
|
||||||
const res = await request
|
const res = await request
|
||||||
.post('/api/newGoogle/')
|
.post('/api/newGoogle/')
|
||||||
|
|||||||
@@ -35,22 +35,28 @@ const PrintPage = createClass({
|
|||||||
if(this.props.query.dialog) window.print();
|
if(this.props.query.dialog) window.print();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
renderStyle : function() {
|
||||||
|
if(!this.props.brew.style) return;
|
||||||
|
return <div style={{ display: 'none' }} dangerouslySetInnerHTML={{ __html: `<style> ${this.props.brew.style} </style>` }} />;
|
||||||
|
},
|
||||||
|
|
||||||
renderPages : function(){
|
renderPages : function(){
|
||||||
if(this.props.brew.renderer == 'legacy') {
|
if(this.props.brew.renderer == 'legacy') {
|
||||||
return _.map(this.state.brewText.split('\\page'), (page, index)=>{
|
return _.map(this.state.brewText.split('\\page'), (pageText, index)=>{
|
||||||
return <div
|
return <div
|
||||||
className='phb page'
|
className='phb page'
|
||||||
id={`p${index + 1}`}
|
id={`p${index + 1}`}
|
||||||
dangerouslySetInnerHTML={{ __html: MarkdownLegacy.render(page) }}
|
dangerouslySetInnerHTML={{ __html: MarkdownLegacy.render(pageText) }}
|
||||||
key={index} />;
|
key={index} />;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return _.map(this.state.brewText.split(/^\\page/gm), (page, index)=>{
|
return _.map(this.state.brewText.split(/^\\page$/gm), (pageText, index)=>{
|
||||||
return <div
|
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)
|
||||||
className='phb3 page'
|
return (
|
||||||
id={`p${index + 1}`}
|
<div className='page' id={`p${index + 1}`} key={index} >
|
||||||
dangerouslySetInnerHTML={{ __html: Markdown.render(page) }}
|
<div className='columnWrapper' dangerouslySetInnerHTML={{ __html: Markdown.render(pageText) }} />
|
||||||
key={index} />;
|
</div>
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,8 +67,10 @@ const PrintPage = createClass({
|
|||||||
<Meta name='robots' content='noindex, nofollow' />
|
<Meta name='robots' content='noindex, nofollow' />
|
||||||
<link href={`${this.props.brew.renderer == 'legacy' ? '/themes/5ePhbLegacy.style.css' : '/themes/5ePhb.style.css'}`} rel='stylesheet'/>
|
<link href={`${this.props.brew.renderer == 'legacy' ? '/themes/5ePhbLegacy.style.css' : '/themes/5ePhb.style.css'}`} rel='stylesheet'/>
|
||||||
{/* Apply CSS from Style tab */}
|
{/* Apply CSS from Style tab */}
|
||||||
<div style={{ display: 'none' }} dangerouslySetInnerHTML={{ __html: `<style> ${this.props.brew.style} </style>` }} />
|
{this.renderStyle()}
|
||||||
{this.renderPages()}
|
<div className='pages' ref='pages'>
|
||||||
|
{this.renderPages()}
|
||||||
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const moment = require('moment');
|
|||||||
const request = require('superagent');
|
const request = require('superagent');
|
||||||
|
|
||||||
const googleDriveIcon = require('../../../googleDrive.png');
|
const googleDriveIcon = require('../../../googleDrive.png');
|
||||||
|
const dedent = require('dedent-tabs').default;
|
||||||
|
|
||||||
const BrewItem = createClass({
|
const BrewItem = createClass({
|
||||||
getDefaultProps : function() {
|
getDefaultProps : function() {
|
||||||
@@ -104,24 +105,28 @@ const BrewItem = createClass({
|
|||||||
const dateFormatString = 'YYYY-MM-DD HH:mm:ss';
|
const dateFormatString = 'YYYY-MM-DD HH:mm:ss';
|
||||||
|
|
||||||
return <div className='brewItem'>
|
return <div className='brewItem'>
|
||||||
<h2>{brew.title}</h2>
|
<div className='text'>
|
||||||
<p className='description'>{brew.description}</p>
|
<h2>{brew.title}</h2>
|
||||||
|
<p className='description'>{brew.description}</p>
|
||||||
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<div className='info'>
|
<div className='info'>
|
||||||
<span title={`Authors:\n${brew.authors.join('\n')}`}>
|
<span title={`Authors:\n${brew.authors.join('\n')}`}>
|
||||||
<i className='fas fa-user'/> {brew.authors.join(', ')}
|
<i className='fas fa-user'/> {brew.authors.join(', ')}
|
||||||
</span>
|
</span>
|
||||||
|
<br />
|
||||||
<span title={`Last viewed: ${moment(brew.lastViewed).local().format(dateFormatString)}`}>
|
<span title={`Last viewed: ${moment(brew.lastViewed).local().format(dateFormatString)}`}>
|
||||||
<i className='fas fa-eye'/> {brew.views}
|
<i className='fas fa-eye'/> {brew.views}
|
||||||
</span>
|
</span>
|
||||||
<span
|
{brew.pageCount &&
|
||||||
title={
|
<span title={`Page count: ${brew.pageCount}`}>
|
||||||
`Created: ${brew.createdAt ? moment(brew.createdAt).local().format(dateFormatString) : 'UNKNOWN'}\n` +
|
<i className='far fa-file' /> {brew.pageCount}
|
||||||
`Last updated: ${brew.updatedAt ? moment(brew.updatedAt).local().format(dateFormatString) : 'UNKNOWN'}`
|
</span>
|
||||||
}>
|
}
|
||||||
<i className='fas fa-sync-alt' />
|
<span title={dedent`
|
||||||
{moment(brew.updatedAt).fromNow()}
|
Created: ${moment(brew.createdAt).local().format(dateFormatString)}
|
||||||
|
Last updated: ${moment(brew.updatedAt).local().format(dateFormatString)}`}>
|
||||||
|
<i className='fas fa-sync-alt' /> {moment(brew.updatedAt).fromNow()}
|
||||||
</span>
|
</span>
|
||||||
{this.renderGoogleDriveIcon()}
|
{this.renderGoogleDriveIcon()}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,25 +10,28 @@
|
|||||||
min-height : 105px;
|
min-height : 105px;
|
||||||
margin-right : 15px;
|
margin-right : 15px;
|
||||||
margin-bottom : 15px;
|
margin-bottom : 15px;
|
||||||
padding : 5px 15px 5px 8px;
|
padding : 5px 15px 2px 8px;
|
||||||
padding-right : 15px;
|
padding-right : 15px;
|
||||||
border : 1px solid #c9ad6a;
|
border : 1px solid #c9ad6a;
|
||||||
border-radius : 5px;
|
border-radius : 5px;
|
||||||
-webkit-column-break-inside : avoid;
|
-webkit-column-break-inside : avoid;
|
||||||
page-break-inside : avoid;
|
page-break-inside : avoid;
|
||||||
break-inside : avoid;
|
break-inside : avoid;
|
||||||
h4{
|
.text {
|
||||||
margin-bottom : 5px;
|
min-height : 54px;
|
||||||
font-size : 2.2em;
|
h4{
|
||||||
|
margin-bottom : 5px;
|
||||||
|
font-size : 2.2em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.info{
|
.info{
|
||||||
position: absolute;
|
position: initial;
|
||||||
bottom: 0px;
|
bottom: 2px;
|
||||||
margin-bottom: 4px;
|
|
||||||
font-family : ScalySans;
|
font-family : ScalySans;
|
||||||
font-size : 1.2em;
|
font-size : 1.2em;
|
||||||
&>span{
|
&>span{
|
||||||
margin-right : 12px;
|
margin-right : 12px;
|
||||||
|
line-height : 1.5em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:hover{
|
&:hover{
|
||||||
|
|||||||
@@ -31,8 +31,9 @@ const UserPage = createClass({
|
|||||||
},
|
},
|
||||||
getInitialState : function() {
|
getInitialState : function() {
|
||||||
return {
|
return {
|
||||||
sortType : 'alpha',
|
sortType : 'alpha',
|
||||||
sortDir : 'asc'
|
sortDir : 'asc',
|
||||||
|
filterString : ''
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getUsernameWithS : function() {
|
getUsernameWithS : function() {
|
||||||
@@ -44,7 +45,7 @@ const UserPage = createClass({
|
|||||||
renderBrews : function(brews){
|
renderBrews : function(brews){
|
||||||
if(!brews || !brews.length) return <div className='noBrews'>No Brews.</div>;
|
if(!brews || !brews.length) return <div className='noBrews'>No Brews.</div>;
|
||||||
|
|
||||||
const sortedBrews = this.sortBrews(brews, this.state.sortType);
|
const sortedBrews = this.sortBrews(brews);
|
||||||
|
|
||||||
return _.map(sortedBrews, (brew, idx)=>{
|
return _.map(sortedBrews, (brew, idx)=>{
|
||||||
return <BrewItem brew={brew} key={idx}/>;
|
return <BrewItem brew={brew} key={idx}/>;
|
||||||
@@ -52,6 +53,7 @@ const UserPage = createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
sortBrewOrder : function(brew){
|
sortBrewOrder : function(brew){
|
||||||
|
if(!brew.title){brew.title = 'No Title';}
|
||||||
const mapping = {
|
const mapping = {
|
||||||
'alpha' : _.deburr(brew.title.toLowerCase()),
|
'alpha' : _.deburr(brew.title.toLowerCase()),
|
||||||
'created' : moment(brew.createdAt).format(),
|
'created' : moment(brew.createdAt).format(),
|
||||||
@@ -90,6 +92,26 @@ const UserPage = createClass({
|
|||||||
</td>;
|
</td>;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleFilterTextChange : function(e){
|
||||||
|
this.setState({
|
||||||
|
filterString : e.target.value
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
|
||||||
|
renderFilterOption : function(){
|
||||||
|
return <td>
|
||||||
|
<label>
|
||||||
|
<i className='fas fa-search'></i>
|
||||||
|
<input
|
||||||
|
type='search'
|
||||||
|
placeholder='search title/description'
|
||||||
|
onChange={this.handleFilterTextChange}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</td>;
|
||||||
|
},
|
||||||
|
|
||||||
renderSortOptions : function(){
|
renderSortOptions : function(){
|
||||||
return <div className='sort-container'>
|
return <div className='sort-container'>
|
||||||
<table>
|
<table>
|
||||||
@@ -114,6 +136,7 @@ const UserPage = createClass({
|
|||||||
{`${(this.state.sortDir == 'asc' ? '\u25B2 ASC' : '\u25BC DESC')}`}
|
{`${(this.state.sortDir == 'asc' ? '\u25B2 ASC' : '\u25BC DESC')}`}
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
|
{this.renderFilterOption()}
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -121,7 +144,12 @@ const UserPage = createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
getSortedBrews : function(){
|
getSortedBrews : function(){
|
||||||
return _.groupBy(this.props.brews, (brew)=>{
|
const testString = _.deburr(this.state.filterString).toLowerCase();
|
||||||
|
const brewCollection = this.state.filterString ? _.filter(this.props.brews, (brew)=>{
|
||||||
|
return (_.deburr(brew.title).toLowerCase().includes(testString)) ||
|
||||||
|
(_.deburr(brew.description).toLowerCase().includes(testString));
|
||||||
|
}) : this.props.brews;
|
||||||
|
return _.groupBy(brewCollection, (brew)=>{
|
||||||
return (brew.published ? 'published' : 'private');
|
return (brew.published ? 'published' : 'private');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -34,8 +34,9 @@
|
|||||||
font-family : 'Open Sans', sans-serif;
|
font-family : 'Open Sans', sans-serif;
|
||||||
position : fixed;
|
position : fixed;
|
||||||
top : 35px;
|
top : 35px;
|
||||||
|
left : calc(50vw - 408px);
|
||||||
border : 2px solid #58180D;
|
border : 2px solid #58180D;
|
||||||
width : 675px;
|
width : 800px;
|
||||||
background-color : #EEE5CE;
|
background-color : #EEE5CE;
|
||||||
padding : 2px;
|
padding : 2px;
|
||||||
text-align : center;
|
text-align : center;
|
||||||
@@ -52,6 +53,9 @@
|
|||||||
vertical-align : middle;
|
vertical-align : middle;
|
||||||
tbody tr{
|
tbody tr{
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
|
i{
|
||||||
|
padding-right : 5px
|
||||||
|
}
|
||||||
button{
|
button{
|
||||||
background-color : transparent;
|
background-color : transparent;
|
||||||
color : #58180D;
|
color : #58180D;
|
||||||
|
|||||||
243
faq.md
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
# FAQ
|
||||||
|
|
||||||
|
**Last Edit:** 26.11.2020
|
||||||
|
|
||||||
|
## Website Issues
|
||||||
|
**Q:** The site is down for me! Anyone else?
|
||||||
|
**A:** You can check https://downforeveryoneorjustme.com/homebrewery.naturalcrit.com to see if the homebrewery is up.
|
||||||
|
|
||||||
|
**Q:** How do I log out?
|
||||||
|
**A:** Go to http://www.naturalcrit.com/login, there you can click "logout".
|
||||||
|
|
||||||
|
**Q:** Is there a way to reset or restore my password?
|
||||||
|
**A:** Currently no. This is, however, a feature that is being worked on. No ETA right now.
|
||||||
|
|
||||||
|
**Q:** I can't access my profile page, what gives?
|
||||||
|
**A:** Most likely you used your e-mail address as your username, which is currently not supported. Please create a new account, avoiding special characters (like @, #, or the like).
|
||||||
|
|
||||||
|
**Q:** The preview window is suddenly gone, I can only see the editor side of the homebrewery (or the other way around)
|
||||||
|
**A:** Press CTRL+SHIFT+i (or right-click and select "Inspect") while in the homebrewery.
|
||||||
|
|
||||||
|
Expand `body` -> `main` -> `div class="homebrew"` -> `div class="editPage page"` -> `div class="content"` -> `div class="splitPane"`.
|
||||||
|
|
||||||
|
There you will find 3 divs: `<div class="pane" [...]>`, `<div class="divider" [...]>`, and `<div class="pane" [...]>`. The first (or second, depending on which side of the homebrewery went missing) `<div class="pane">` has a style tag, that looks similar to this: `<div class="pane" data-reactid="36" style="flex: 0 0 auto; width: 925px;">`.
|
||||||
|
|
||||||
|
Change whatever stands behind `width:` to something smaller than your display width. Here's a screenshot of how it looks expanded: [imgur](https://i.imgur.com/QdqPNIg.png).
|
||||||
|
|
||||||
|
**Q:** I worked on a brew for $x hours, and when I returned the next day, all changes were gone?
|
||||||
|
**A:** This happens when you did not close the tab but closed the browser, or used the back button of your browser to return to your brew! If you return to your brew under these circumstances, the version of your brew you saved before is still loaded in the cache, so you need to refresh or reopen the page for your recent changes to be in said cache. If you start working on your brew without refreshing, all changes you made in the meantime are gone. Additionally, pay extra attention to the next question below!
|
||||||
|
|
||||||
|
**Q:** Is there a way to restore a previous version of my brew?
|
||||||
|
**A:** Currently, no. This would take too much of a toll on the amount of storage the homebrewery requires. This may be solved in the future.
|
||||||
|
|
||||||
|
**Q:** The code and/or preview window of my brew are just blue, nothing else. Also, the version in the top displays 0.0.0.
|
||||||
|
**A:** You have an error in the HTML you used in your brew. That's why the page can't render properly anymore. Click the Share button in the top right, then click the Source button in the top right, get your brew's code, create a new brew, paste the code in there, fix the HTML error, and you're done. At this point, you can also delete the old brew, it is not fixable.
|
||||||
|
|
||||||
|
**Q:** I have important brews, but I can't access them anymore because [...]
|
||||||
|
**A:** Most important thing to remember: Save early, save often. Also, check out the "Back Up Your Stuff!" section below for more information.
|
||||||
|
|
||||||
|
## Text Issues
|
||||||
|
**Q:** How do I resize text globally/locally?
|
||||||
|
**A:** [Globally](https://old.reddit.com/r/homebrewery/comments/8bivc7/question_how_do_i_resize_text_globally/dx8et7c/) |
|
||||||
|
[Locally](https://old.reddit.com/r/homebrewery/comments/9pvj0q/font_size_change/)
|
||||||
|
|
||||||
|
**Q:** How do I use different fonts in my brews?
|
||||||
|
**A:** The best way, I would say, is to transform the font you want to use into the base64 format, using a website such as [fontsquirrel.com](https://www.fontsquirrel.com/tools/webfont-generator). Once there, click "Expert..." and go all the way down to "CSS" and mark "Base64 encode" and "Yes, the fonts I'm uploading are legally eligible for web embedding." (make sure that they, infact, are!). Go back to the top and click "Upload font". Select the font file you want to use. Once the font is transformed, click "Download your kit" at the bottom. In the resulting .zip file, you will find a file named "stylesheet.css". Open it and copy all of its contents.
|
||||||
|
|
||||||
|
Go to your homebrew and either add the copied information to your `<style>` section, or create a new section via `<style></style>` and paste the copied information there. You can then use `font-family: fontname`, where *fontname* is the part after `font-family: ` in the `@font-face` segment, to add that font to your brew.
|
||||||
|
|
||||||
|
***Example:*** You want to have a different font for all elements with the `testFontClass` class. This is how you would go about that:
|
||||||
|
|
||||||
|
1. Upload your font to [fontsquirrel.com](https://www.fontsquirrel.com/tools/webfont-generator) and have it base64 encoded.
|
||||||
|
|
||||||
|
2. In the resulting .zip file, look for the .css file, open it, and copy its contents, which will look something like this (Your `url()` parts will be much longer, I removed most of it for the sake of readability):
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'testFont';
|
||||||
|
src: url(data:application/font-woff2;charset=utf-8;base64,d09GMgABAA[...]+wEAAA=) format('woff2'),
|
||||||
|
url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAHTcABI[...]+wAAAADYwmAT) format('woff');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
3. In your homebrew, either add a `<style></style>` section at the top or, if you already have one, add the copied `@font-face{ [...] }` to it.
|
||||||
|
|
||||||
|
4. In that same `<style>` section, add a new class that uses the new font:
|
||||||
|
|
||||||
|
.phb .testFontClass {
|
||||||
|
font-family: testFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
5. Now everytime you do something like `<p class="testFontClass">This is in a different font.</p>`, your newly added font will be used.
|
||||||
|
|
||||||
|
If you think that the base64 encoded font takes up a bit too much space in your brew, see the question below.
|
||||||
|
|
||||||
|
**Q:** I heavily customized the style of my brews, and I have a lot of brews in which I want to use my custom style, without having to copy it over everytime I change a little detail about it.
|
||||||
|
**A:** Create a new file on your computer, and name it something like `MyHomebrewStyle.css`. Put all the style information you use into this file (do not add the `<style></style>` tags to this file!). Upload said file to a place that is accessible to the homebrewery. Go to your brew, remove everything within your `<style></style>` tags, and add this: `@import "https://my.website.com/MyHomebrewStyle.css";`
|
||||||
|
|
||||||
|
Be aware that, should you change something in that css file, your homebrew will have to be reloaded for these changes to take effect.
|
||||||
|
|
||||||
|
**Q:** How do I use different colors in my brews?
|
||||||
|
**A:** [Described here](https://old.reddit.com/r/homebrewery/comments/9kesk1/changing_text_colour_to_white/)
|
||||||
|
|
||||||
|
**Q:** How do I get a line break without indentation?
|
||||||
|
**A:** [Described here](https://old.reddit.com/r/homebrewery/comments/8hmr50/getting_line_breaks_without_getting_a_new/)
|
||||||
|
|
||||||
|
**Q:** How do I fix line indentations in monster statblocks?
|
||||||
|
**A:** [Described here](https://old.reddit.com/r/homebrewery/comments/ag46i1/indentation_problem/)
|
||||||
|
|
||||||
|
**Q:** When I write more text than fits into the two columns on the page, the text overflows into a third column and goes off-page. Why isn't a new page generated for the text?
|
||||||
|
**A:** Auto-generating a new page via code lies between tricky and impossible. Use `\page` to create a new page manually. If you have an idea about how to implement auto-new-page-ing, head over to [GitHub](https://github.com/naturalcrit/homebrewery) and let us know.
|
||||||
|
|
||||||
|
**Q:** Typing `#### Adhesion` in the formatting doesn't show the titling at all in the completed page?
|
||||||
|
**A:** Whitelist homebrewery.naturalcrit.com in your ad-blocking software.
|
||||||
|
|
||||||
|
## Paper Size
|
||||||
|
**Q:** I have white borders on the bottom/sides of the print preview.
|
||||||
|
**A:** The homebrewery paper size and your print paper size do not match.
|
||||||
|
|
||||||
|
The default homebrewery paper size is “Letter.”
|
||||||
|
|
||||||
|
If you are in the US (and you did not add the A4 snippet), in the "Print to PDF" window, click "More settings" and change "Paper size" to "Letter".
|
||||||
|
|
||||||
|
If you are anywhere else, your default "Paper size" setting is most likely "A4" and you need to change it to "Letter" (as described above). You can also add the A4 snippet to the top of your brew to make it A4-sized.
|
||||||
|
|
||||||
|
## Get PDF
|
||||||
|
**Q:** Whenever I click on the "Get PDF" button, instead of getting a download, it opens Print Preview in another tab.
|
||||||
|
**A:** Yes, this is by design. In the print preview, select "Save as PDF" as the Destination, and then click "Save". There will be a normal download dialog where you can save your brew as a PDF.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# PSAs
|
||||||
|
|
||||||
|
## Back Up Your Stuff!
|
||||||
|
|
||||||
|
By that I mean, when you brew, occasionally hit CTRL + A, CTRL + C, open a texteditor (on your local machine), CTRL + V your brew in there, and save that file.
|
||||||
|
|
||||||
|
You can go as crazy as you want to be with that. Create one file per brew, that's fine. Create one file per brew per day you edit it, that's even better. Create one file per brew per day you edit it, save it in two or more separate (remote) locations? That's even more better (I do it that way ;) ).
|
||||||
|
|
||||||
|
Whatever method you prefer, just do it.
|
||||||
|
|
||||||
|
Also, see the "Backing Up Brews with a Bookmarklet", "Backing Up Brews with Linux" section, and the comments below.
|
||||||
|
|
||||||
|
## Brewmasters
|
||||||
|
|
||||||
|
|
||||||
|
We recently started the "Brewmasters" program, where we give out a special flair to users that have proven that they know what they are talking about when it comes to using the [Homebrewery](https://homebrewery.naturalcrit.com).
|
||||||
|
|
||||||
|
The first member to earn this special flair is u/VexbaneAramori, who is a pillar of this community.
|
||||||
|
|
||||||
|
Brewmasters can nominate other active users to become Brewmasters via ModMail as well.
|
||||||
|
|
||||||
|
Thanks to all who help to make this community more helpful and welcoming. :)
|
||||||
|
|
||||||
|
**18.05.2020 - Update:** We're happy to announce that u/Jintonix has joined the ranks of our Brewmasters. Welcome!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Miscellaneous
|
||||||
|
|
||||||
|
## Backing Up Brews with a Bookmarklet
|
||||||
|
|
||||||
|
This solution was provided by u/garumoo in the [comments](https://www.reddit.com/r/homebrewery/comments/adh6lh/faqs_psas_announcements/edrvz8o/) of the old [PSA](https://www.reddit.com/r/homebrewery/comments/adh6lh/faqs_psas_announcements/).
|
||||||
|
|
||||||
|
> Here is a handy bookmarklet for saving your brew
|
||||||
|
>
|
||||||
|
> Just create a new bookmark, put it onto your browser button bar, and edit it, changing the URL to:
|
||||||
|
|
||||||
|
javascript:(function() {var nav=document.getElementsByClassName('navContent')[0];var share=nav.querySelector('.navItem[icon="fa-share-alt"');var code=nav.querySelector('.navItem[icon="fa-code"');if(share||code){let brewtitle=document.getElementsByClassName('brewTitle')[0].innerText;let date=new Date();let dd=date.getDate();let mm=date.getMonth()+1;let yyyy=date.getFullYear();let hour=date.getHours();let mins=date.getMinutes();dd=dd<10?'0'+dd:dd;mm=mm<10?'0'+mm:mm;hour=hour<10?'0'+hour:hour;mins=mins<10?'0'+mins:mins;let dateString=`${yyyy}-${mm}-${dd}-${hour}${mins}`;let filename=brewtitle+'-'+dateString+'.md';var sourceuri=share?share.href.replace('share','source'):code.href;fetch(sourceuri).then((response)=>{if(response.ok){return response.text()}}).then((payload)=>{var div=document.createElement('div');div.innerHTML=payload;var brewtext=div.innerText;delete div;let data_uri='data:text/markdown; charset=UTF-8,'+encodeURIComponent(brewtext);var link=document.createElement("a");link.download=filename;link.href=data_uri;document.body.appendChild(link);link.click();document.body.removeChild(link);delete link})}})();
|
||||||
|
|
||||||
|
> Then, while viewing either the edit or the share versions, just click the bookmarklet. It should then download as a text file named as Brewtitle-yyyy-mm-dd-hhmm.md
|
||||||
|
>
|
||||||
|
> The code doesn't sanitise the brewtitle so if you have a funky brewtitle and things blow up that's on you.
|
||||||
|
|
||||||
|
## Backing Up Brews with Linux
|
||||||
|
|
||||||
|
This following script was written by myself, u/Thurse. For an easier to use script, check out u/-Hydrargyros-'s [comment](https://www.reddit.com/r/homebrewery/comments/adh6lh/faqs_psas_announcements/ee9xtsw/) on the old [PSA](https://www.reddit.com/r/homebrewery/comments/adh6lh/faqs_psas_announcements/).
|
||||||
|
|
||||||
|
Hello everyone,
|
||||||
|
as of now, I'm pretty sure everyone has read our [PSA on Backing Up Your Stuff](https://old.reddit.com/r/homebrewery/comments/a0ubx1/psa_back_up_your_stuff/), as you should... :)
|
||||||
|
|
||||||
|
In the PSA thread, u/sonaplayer offered a way to automatically back up your stuff via Google Docs. Although a good method, it can't handle larger brews, so it wasn't for me. I actually corresponded with u/sonaplayer on the topic, and said at one point "maybe someday I will write something in bash...". Well, "someday" was during the christmas holidays, so I present to you:
|
||||||
|
|
||||||
|
A bash script to backup your brews!
|
||||||
|
|
||||||
|
### How does this work?
|
||||||
|
|
||||||
|
1. Go to https://pastebin.com/hkx0NXid and click "download".
|
||||||
|
1a. You can actually look at the source code there to see how it works.
|
||||||
|
2. Save the file as `backupBrews.sh` (this should be the default name already).
|
||||||
|
2a. If it isn't already on a Linux system, transfer the file to one. Or use "[git bash for Windows](https://gitforwindows.org/)" or whatever tickles your fancy.
|
||||||
|
3. Make sure you put it to a place where you have sufficient permissions to read, write, and create folders.
|
||||||
|
4. The script should run on any Linux, I tested it on Raspbian and with "git bash for Windows".
|
||||||
|
5. The simplest way to use this is `./backupBrews.sh -b BrewId` where the `BrewId` is the last part of the SHARE link: https://homebrewery.naturalcrit.com/share/*HereIsTheBrewId*. You don't need the whole link, just the `BrewId` part! Also, don't use the EDIT id, because that won't work.
|
||||||
|
5a. There will be several checks, if they pass, your brew will be downloaded and "cleaned up". What does that mean? When you get the source of your brew, all the `<` will be replaced with `<` and all the `>` will be replaced with `>`. The clean up process turns all the `<` and `>` back into `<` and `>`, so that you can theoretically take the text from the .md file and paste it into the homebrewery, ready to go. **Be aware:** Clean up can take quite a while. My Raspberry Pi 3 B+ needs about 10 minutes to clean up my largest brew at ~1,000,000 characters.
|
||||||
|
5b. A folder will be created in the current location of the script, named as follows: `./backup/BrewId/`
|
||||||
|
5c. Inside that folder, a file named BrewId_YYYYMMDD_HHMMSS.md will be created.
|
||||||
|
6. That's it. For advanced usage, see `--help` or the info below.
|
||||||
|
|
||||||
|
### Advanced Usage
|
||||||
|
|
||||||
|
Apparently, you are not content with the tool's basic function. That's cool, I wasn't either. :)
|
||||||
|
|
||||||
|
There are some more options you can use, described in detail below.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### Mandatory Options
|
||||||
|
|
||||||
|
* `-b BrewId`
|
||||||
|
|
||||||
|
At least one `-b BrewId` is mandatory, else the program will exit. You can do however many brews at once as you like. Just make sure to use `-b BrewId`, and all's good.
|
||||||
|
|
||||||
|
***Example.*** `./backupBrews.sh -b BrewId1 -b BrewId2 -b BrewId3`
|
||||||
|
|
||||||
|
Instead of using the BrewId as the name for the folder and the file, you can give your brew a (short) name. You should avoid spaces and special characters. If you must, you can use quotes to have spaces in the name. BrewName and BrewId have to be separated via `::`.
|
||||||
|
|
||||||
|
***Example.*** `./backupBrews.sh -b BrewName1::BrewId1`
|
||||||
|
|
||||||
|
You can of course combine these options:
|
||||||
|
|
||||||
|
***Example.*** `./backupBrews.sh -b BrewName1::BrewId1 -b BrewId2 -b "Dont use spaces"::BrewId3`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### Optional options
|
||||||
|
|
||||||
|
* `--help`
|
||||||
|
|
||||||
|
Show the help. This is the only option you can use without the `-b` option.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
* `-s`
|
||||||
|
|
||||||
|
The tool is verbose by default. The `-s` option turns off all output. You are still able to get an exit status via `echo $?`.
|
||||||
|
|
||||||
|
***Example.*** `./backupBrews.sh -s -b BrewId`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
* `-d dateformat`
|
||||||
|
|
||||||
|
This changes the date format at the end of the backup file. Standard is `%Y%m%d_%H%M%S`. You can enter whatever is accepted by `date`. See `date --help` for more information. The example below gives you the current unix timestamp, so your filename would look something like this: `BrewId_1546297200.md`
|
||||||
|
|
||||||
|
***Example.*** `./backupBrews.sh -d %s -b BrewId`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
* `-l location`
|
||||||
|
|
||||||
|
This changes the savelocation of your backups. The example below puts the brew folders into a folder called "backup" in the home of the current user, like so: `~/backup/BrewId/BrewId_20190101_000000.md`. Be aware that this script will only create a folder for the brew, not folders above that. To use the example, if the folder `~/backup/` doesn't exist, this tool will not create that folder and simply exit.
|
||||||
|
|
||||||
|
***Example.*** `./backupBrews.sh -l "~/backup/" -b BrewId`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
You can of course combine all of the options mentioned above:
|
||||||
|
|
||||||
|
***Example.*** `./backupBrews.sh -s -d %s -l "~/backup/" -b BrewName1::BrewId1 -b BrewId2 -b "Dont use spaces"::BrewId3`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
If you have any questions, feel free to ask.
|
||||||
1589
package-lock.json
generated
20
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": "2.13.3",
|
"version": "3.0.1",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "14.15.x"
|
"node": "14.15.x"
|
||||||
},
|
},
|
||||||
@@ -40,28 +40,28 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.15.0",
|
"@babel/core": "^7.15.5",
|
||||||
"@babel/plugin-transform-runtime": "^7.15.0",
|
"@babel/plugin-transform-runtime": "^7.15.0",
|
||||||
"@babel/preset-env": "^7.15.0",
|
"@babel/preset-env": "^7.15.6",
|
||||||
"@babel/preset-react": "^7.14.5",
|
"@babel/preset-react": "^7.14.5",
|
||||||
"body-parser": "^1.19.0",
|
"body-parser": "^1.19.0",
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
"codemirror": "^5.62.2",
|
"codemirror": "^5.63.0",
|
||||||
"cookie-parser": "^1.4.5",
|
"cookie-parser": "^1.4.5",
|
||||||
"create-react-class": "^15.7.0",
|
"create-react-class": "^15.7.0",
|
||||||
"dedent-tabs": "^0.9.0",
|
"dedent-tabs": "^0.10.1",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"express-async-handler": "^1.1.4",
|
"express-async-handler": "^1.1.4",
|
||||||
"express-static-gzip": "2.1.1",
|
"express-static-gzip": "2.1.1",
|
||||||
"fs-extra": "10.0.0",
|
"fs-extra": "10.0.0",
|
||||||
"googleapis": "84.0.0",
|
"googleapis": "87.0.0",
|
||||||
"jwt-simple": "^0.5.6",
|
"jwt-simple": "^0.5.6",
|
||||||
"less": "^3.13.1",
|
"less": "^3.13.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"marked": "2.1.3",
|
"marked": "3.0.4",
|
||||||
"markedLegacy": "npm:marked@^0.3.19",
|
"markedLegacy": "npm:marked@^0.3.19",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
"mongoose": "^5.13.7",
|
"mongoose": "^6.0.7",
|
||||||
"nanoid": "3.1.25",
|
"nanoid": "3.1.25",
|
||||||
"nconf": "^0.11.3",
|
"nconf": "^0.11.3",
|
||||||
"prop-types": "15.7.2",
|
"prop-types": "15.7.2",
|
||||||
@@ -69,14 +69,14 @@
|
|||||||
"react": "^16.14.0",
|
"react": "^16.14.0",
|
||||||
"react-dom": "^16.14.0",
|
"react-dom": "^16.14.0",
|
||||||
"react-frame-component": "4.1.3",
|
"react-frame-component": "4.1.3",
|
||||||
"react-router-dom": "5.2.0",
|
"react-router-dom": "5.3.0",
|
||||||
"sanitize-filename": "1.6.3",
|
"sanitize-filename": "1.6.3",
|
||||||
"superagent": "^6.1.0",
|
"superagent": "^6.1.0",
|
||||||
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
|
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^7.32.0",
|
||||||
"eslint-plugin-react": "^7.24.0",
|
"eslint-plugin-react": "^7.26.0",
|
||||||
"pico-check": "^2.1.3"
|
"pico-check": "^2.1.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
29
server.js
@@ -72,10 +72,11 @@ const config = require('nconf')
|
|||||||
//DB
|
//DB
|
||||||
const mongoose = require('mongoose');
|
const mongoose = require('mongoose');
|
||||||
mongoose.connect(config.get('mongodb_uri') || config.get('mongolab_uri') || 'mongodb://localhost/naturalcrit',
|
mongoose.connect(config.get('mongodb_uri') || config.get('mongolab_uri') || 'mongodb://localhost/naturalcrit',
|
||||||
{ retryWrites: false, useNewUrlParser: true, useCreateIndex: true, useUnifiedTopology: true });
|
{ retryWrites: false });
|
||||||
mongoose.connection.on('error', ()=>{
|
mongoose.connection.on('error', (err)=>{
|
||||||
console.log('Error : Could not connect to a Mongo Database.');
|
console.log('Error : Could not connect to a Mongo Database.');
|
||||||
console.log(' If you are running locally, make sure mongodb.exe is running.');
|
console.log(' If you are running locally, make sure mongodb.exe is running.');
|
||||||
|
console.log(err);
|
||||||
throw 'Can not connect to Mongo';
|
throw 'Can not connect to Mongo';
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -103,6 +104,7 @@ const HomebrewModel = require('./server/homebrew.model.js').model;
|
|||||||
const welcomeText = require('fs').readFileSync('./client/homebrew/pages/homePage/welcome_msg.md', 'utf8');
|
const welcomeText = require('fs').readFileSync('./client/homebrew/pages/homePage/welcome_msg.md', 'utf8');
|
||||||
const welcomeTextV3 = require('fs').readFileSync('./client/homebrew/pages/homePage/welcome_msg_v3.md', 'utf8');
|
const welcomeTextV3 = require('fs').readFileSync('./client/homebrew/pages/homePage/welcome_msg_v3.md', 'utf8');
|
||||||
const changelogText = require('fs').readFileSync('./changelog.md', 'utf8');
|
const changelogText = require('fs').readFileSync('./changelog.md', 'utf8');
|
||||||
|
const faqText = require('fs').readFileSync('./faq.md', 'utf8');
|
||||||
|
|
||||||
String.prototype.replaceAll = function(s, r){return this.split(s).join(r);};
|
String.prototype.replaceAll = function(s, r){return this.split(s).join(r);};
|
||||||
|
|
||||||
@@ -134,9 +136,23 @@ app.get('/v3_preview', async (req, res, next)=>{
|
|||||||
//Changelog page
|
//Changelog page
|
||||||
app.get('/changelog', async (req, res, next)=>{
|
app.get('/changelog', async (req, res, next)=>{
|
||||||
const brew = {
|
const brew = {
|
||||||
title : 'Changelog',
|
title : 'Changelog',
|
||||||
text : changelogText
|
text : changelogText,
|
||||||
|
renderer : 'V3'
|
||||||
};
|
};
|
||||||
|
splitTextAndStyle(brew);
|
||||||
|
req.brew = brew;
|
||||||
|
return next();
|
||||||
|
});
|
||||||
|
|
||||||
|
//FAQ page
|
||||||
|
app.get('/faq', async (req, res, next)=>{
|
||||||
|
const brew = {
|
||||||
|
title : 'FAQ',
|
||||||
|
text : faqText,
|
||||||
|
renderer : 'V3'
|
||||||
|
};
|
||||||
|
splitTextAndStyle(brew);
|
||||||
req.brew = brew;
|
req.brew = brew;
|
||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
@@ -280,5 +296,6 @@ app.use((err, req, res, next)=>{
|
|||||||
//^=====--------------------------------------=====^//
|
//^=====--------------------------------------=====^//
|
||||||
|
|
||||||
const PORT = process.env.PORT || config.get('web_port') || 8000;
|
const PORT = process.env.PORT || config.get('web_port') || 8000;
|
||||||
app.listen(PORT);
|
app.listen(PORT, ()=>{
|
||||||
console.log(`server on port:${PORT}`);
|
console.log(`server on port:${PORT}`);
|
||||||
|
});
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ GoogleActions = {
|
|||||||
if(!account || !account.googleId){ // If not signed into Google
|
if(!account || !account.googleId){ // If not signed into Google
|
||||||
const err = new Error('Not Signed In');
|
const err = new Error('Not Signed In');
|
||||||
err.status = 401;
|
err.status = 401;
|
||||||
throw err;
|
throw (err);
|
||||||
}
|
}
|
||||||
|
|
||||||
const oAuth2Client = new google.auth.OAuth2(
|
const oAuth2Client = new google.auth.OAuth2(
|
||||||
@@ -60,6 +60,7 @@ GoogleActions = {
|
|||||||
.catch((err)=>{
|
.catch((err)=>{
|
||||||
console.log('Error searching Google Drive Folders');
|
console.log('Error searching Google Drive Folders');
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw (err);
|
||||||
});
|
});
|
||||||
|
|
||||||
let folderId;
|
let folderId;
|
||||||
@@ -69,8 +70,9 @@ GoogleActions = {
|
|||||||
resource : fileMetadata
|
resource : fileMetadata
|
||||||
})
|
})
|
||||||
.catch((err)=>{
|
.catch((err)=>{
|
||||||
console.log('Error creating google app folder');
|
console.log('Error creating Google Drive folder');
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw (err);
|
||||||
});
|
});
|
||||||
|
|
||||||
folderId = obj.data.id;
|
folderId = obj.data.id;
|
||||||
@@ -99,7 +101,9 @@ GoogleActions = {
|
|||||||
q : 'mimeType != \'application/vnd.google-apps.folder\' and trashed = false'
|
q : 'mimeType != \'application/vnd.google-apps.folder\' and trashed = false'
|
||||||
})
|
})
|
||||||
.catch((err)=>{
|
.catch((err)=>{
|
||||||
return console.error(`Error Listing Google Brews: ${err}`);
|
console.log(`Error Listing Google Brews`);
|
||||||
|
console.error(err);
|
||||||
|
throw (err);
|
||||||
//TODO: Should break out here, but continues on for some reason.
|
//TODO: Should break out here, but continues on for some reason.
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -109,24 +113,23 @@ GoogleActions = {
|
|||||||
|
|
||||||
const brews = obj.data.files.map((file)=>{
|
const brews = obj.data.files.map((file)=>{
|
||||||
return {
|
return {
|
||||||
text : '',
|
text : '',
|
||||||
shareId : file.properties.shareId,
|
shareId : file.properties.shareId,
|
||||||
editId : file.properties.editId,
|
editId : file.properties.editId,
|
||||||
createdAt : file.createdTime,
|
createdAt : file.createdTime,
|
||||||
updatedAt : file.modifiedTime,
|
updatedAt : file.modifiedTime,
|
||||||
gDrive : true,
|
gDrive : true,
|
||||||
googleId : file.id,
|
googleId : file.id,
|
||||||
|
pageCount : file.properties.pageCount,
|
||||||
title : file.properties.title,
|
title : file.properties.title,
|
||||||
description : file.description,
|
description : file.description,
|
||||||
views : file.properties.views,
|
views : file.properties.views,
|
||||||
tags : '',
|
tags : '',
|
||||||
published : file.properties.published ? file.properties.published == 'true' : false,
|
published : file.properties.published ? file.properties.published == 'true' : false,
|
||||||
authors : [req.account.username], //TODO: properly save and load authors to google drive
|
authors : [req.account.username], //TODO: properly save and load authors to google drive
|
||||||
systems : []
|
systems : []
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return brews;
|
return brews;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -136,7 +139,7 @@ GoogleActions = {
|
|||||||
const result = await drive.files.get({ fileId: id })
|
const result = await drive.files.get({ fileId: id })
|
||||||
.catch((err)=>{
|
.catch((err)=>{
|
||||||
console.log('error checking file exists...');
|
console.log('error checking file exists...');
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -151,19 +154,23 @@ GoogleActions = {
|
|||||||
if(await GoogleActions.existsGoogleBrew(auth, brew.googleId) == true) {
|
if(await GoogleActions.existsGoogleBrew(auth, brew.googleId) == true) {
|
||||||
await drive.files.update({
|
await drive.files.update({
|
||||||
fileId : brew.googleId,
|
fileId : brew.googleId,
|
||||||
resource : { name : `${brew.title}.txt`,
|
resource : {
|
||||||
description : `${brew.description}`,
|
name : `${brew.title}.txt`,
|
||||||
properties : { title : brew.title,
|
description : `${brew.description}`,
|
||||||
published : brew.published,
|
properties : {
|
||||||
lastViewed : brew.lastViewed,
|
title : brew.title,
|
||||||
views : brew.views,
|
published : brew.published,
|
||||||
version : brew.version,
|
version : brew.version,
|
||||||
renderer : brew.renderer,
|
renderer : brew.renderer,
|
||||||
tags : brew.tags,
|
tags : brew.tags,
|
||||||
systems : brew.systems.join() }
|
pageCount : brew.pageCount,
|
||||||
},
|
systems : brew.systems.join()
|
||||||
media : { mimeType : 'text/plain',
|
}
|
||||||
body : brew.text }
|
},
|
||||||
|
media : {
|
||||||
|
mimeType : 'text/plain',
|
||||||
|
body : brew.text
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch((err)=>{
|
.catch((err)=>{
|
||||||
console.log('Error saving to google');
|
console.log('Error saving to google');
|
||||||
@@ -191,11 +198,12 @@ GoogleActions = {
|
|||||||
'description' : `${brew.description}`,
|
'description' : `${brew.description}`,
|
||||||
'parents' : [folderId],
|
'parents' : [folderId],
|
||||||
'properties' : { //AppProperties is not accessible
|
'properties' : { //AppProperties is not accessible
|
||||||
'shareId' : nanoid(12),
|
'shareId' : nanoid(12),
|
||||||
'editId' : nanoid(12),
|
'editId' : nanoid(12),
|
||||||
'title' : brew.title,
|
'title' : brew.title,
|
||||||
'views' : '0',
|
'views' : '0',
|
||||||
'renderer' : brew.renderer || 'legacy'
|
'pageCount' : brew.pageCount,
|
||||||
|
'renderer' : brew.renderer || 'legacy'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -230,6 +238,7 @@ GoogleActions = {
|
|||||||
updatedAt : new Date(),
|
updatedAt : new Date(),
|
||||||
gDrive : true,
|
gDrive : true,
|
||||||
googleId : obj.data.id,
|
googleId : obj.data.id,
|
||||||
|
pageCount : fileMetadata.properties.pageCount,
|
||||||
|
|
||||||
title : brew.title,
|
title : brew.title,
|
||||||
description : brew.description,
|
description : brew.description,
|
||||||
@@ -301,6 +310,7 @@ GoogleActions = {
|
|||||||
createdAt : obj.data.createdTime,
|
createdAt : obj.data.createdTime,
|
||||||
updatedAt : obj.data.modifiedTime,
|
updatedAt : obj.data.modifiedTime,
|
||||||
lastViewed : obj.data.properties.lastViewed,
|
lastViewed : obj.data.properties.lastViewed,
|
||||||
|
pageCount : obj.data.properties.pageCount,
|
||||||
views : parseInt(obj.data.properties.views) || 0, //brews with no view parameter will return undefined
|
views : parseInt(obj.data.properties.views) || 0, //brews with no view parameter will return undefined
|
||||||
version : parseInt(obj.data.properties.version) || 0,
|
version : parseInt(obj.data.properties.version) || 0,
|
||||||
renderer : obj.data.properties.renderer ? obj.data.properties.renderer : 'legacy',
|
renderer : obj.data.properties.renderer ? obj.data.properties.renderer : 'legacy',
|
||||||
@@ -361,8 +371,13 @@ GoogleActions = {
|
|||||||
|
|
||||||
await drive.files.update({
|
await drive.files.update({
|
||||||
fileId : brew.googleId,
|
fileId : brew.googleId,
|
||||||
resource : { properties : { views : brew.views + 1,
|
resource : {
|
||||||
lastViewed : new Date() } }
|
modifiedTime : brew.updatedAt,
|
||||||
|
properties : {
|
||||||
|
views : brew.views + 1,
|
||||||
|
lastViewed : new Date()
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch((err)=>{
|
.catch((err)=>{
|
||||||
console.log('Error updating Google views');
|
console.log('Error updating Google views');
|
||||||
|
|||||||
@@ -19,6 +19,15 @@ const getGoodBrewTitle = (text)=>{
|
|||||||
.slice(0, MAX_TITLE_LENGTH);
|
.slice(0, MAX_TITLE_LENGTH);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const excludePropsFromUpdate = (brew)=>{
|
||||||
|
// Remove undesired properties
|
||||||
|
const propsToExclude = ['views', 'lastViewed'];
|
||||||
|
for (const prop of propsToExclude) {
|
||||||
|
delete brew[prop];
|
||||||
|
};
|
||||||
|
return brew;
|
||||||
|
};
|
||||||
|
|
||||||
const mergeBrewText = (text, style)=>{
|
const mergeBrewText = (text, style)=>{
|
||||||
if(typeof style !== 'undefined') {
|
if(typeof style !== 'undefined') {
|
||||||
text = `\`\`\`css\n` +
|
text = `\`\`\`css\n` +
|
||||||
@@ -64,7 +73,8 @@ const newBrew = (req, res)=>{
|
|||||||
const updateBrew = (req, res)=>{
|
const updateBrew = (req, res)=>{
|
||||||
HomebrewModel.get({ editId: req.params.id })
|
HomebrewModel.get({ editId: req.params.id })
|
||||||
.then((brew)=>{
|
.then((brew)=>{
|
||||||
brew = _.merge(brew, req.body);
|
const updateBrew = excludePropsFromUpdate(req.body);
|
||||||
|
brew = _.merge(brew, updateBrew);
|
||||||
brew.text = mergeBrewText(brew.text, brew.style);
|
brew.text = mergeBrewText(brew.text, brew.style);
|
||||||
|
|
||||||
// Compress brew text to binary before saving
|
// Compress brew text to binary before saving
|
||||||
@@ -154,7 +164,7 @@ const updateGoogleBrew = async (req, res, next)=>{
|
|||||||
|
|
||||||
try { oAuth2Client = GoogleActions.authCheck(req.account, res); } catch (err) { return res.status(err.status).send(err.message); }
|
try { oAuth2Client = GoogleActions.authCheck(req.account, res); } catch (err) { return res.status(err.status).send(err.message); }
|
||||||
|
|
||||||
const brew = req.body;
|
const brew = excludePropsFromUpdate(req.body);
|
||||||
brew.text = mergeBrewText(brew.text, brew.style);
|
brew.text = mergeBrewText(brew.text, brew.style);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -4,11 +4,12 @@ const _ = require('lodash');
|
|||||||
const zlib = require('zlib');
|
const zlib = require('zlib');
|
||||||
|
|
||||||
const HomebrewSchema = mongoose.Schema({
|
const HomebrewSchema = mongoose.Schema({
|
||||||
shareId : { type: String, default: ()=>{return nanoid(12);}, index: { unique: true } },
|
shareId : { type: String, default: ()=>{return nanoid(12);}, index: { unique: true } },
|
||||||
editId : { type: String, default: ()=>{return nanoid(12);}, index: { unique: true } },
|
editId : { type: String, default: ()=>{return nanoid(12);}, index: { unique: true } },
|
||||||
title : { type: String, default: '' },
|
title : { type: String, default: '' },
|
||||||
text : { type: String, default: '' },
|
text : { type: String, default: '' },
|
||||||
textBin : { type: Buffer },
|
textBin : { type: Buffer },
|
||||||
|
pageCount : { type: Number, default: 1 },
|
||||||
|
|
||||||
description : { type: String, default: '' },
|
description : { type: String, default: '' },
|
||||||
tags : { type: String, default: '' },
|
tags : { type: String, default: '' },
|
||||||
|
|||||||
@@ -65,13 +65,13 @@ const mustacheSpans = {
|
|||||||
raw : raw, // Text to consume from the source
|
raw : raw, // Text to consume from the source
|
||||||
text : text, // Additional custom properties
|
text : text, // Additional custom properties
|
||||||
tags : tags,
|
tags : tags,
|
||||||
tokens : this.inlineTokens(text) // inlineTokens to process **bold**, *italics*, etc.
|
tokens : this.lexer.inlineTokens(text) // inlineTokens to process **bold**, *italics*, etc.
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
renderer(token) {
|
renderer(token) {
|
||||||
return `<span class="inline-block${token.tags}>${this.parseInline(token.tokens)}</span>`; // parseInline to turn child tokens into HTML
|
return `<span class="inline-block${token.tags}>${this.parser.parseInline(token.tokens)}</span>`; // parseInline to turn child tokens into HTML
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -114,13 +114,13 @@ const mustacheDivs = {
|
|||||||
raw : raw, // Text to consume from the source
|
raw : raw, // Text to consume from the source
|
||||||
text : text, // Additional custom properties
|
text : text, // Additional custom properties
|
||||||
tags : tags,
|
tags : tags,
|
||||||
tokens : this.inline(this.blockTokens(text))
|
tokens : this.lexer.blockTokens(text)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
renderer(token) {
|
renderer(token) {
|
||||||
return `<div class="block${token.tags}>${this.parse(token.tokens)}</div>`; // parseInline to turn child tokens into HTML
|
return `<div class="block${token.tags}>${this.parser.parse(token.tokens)}</div>`; // parseInline to turn child tokens into HTML
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -149,7 +149,7 @@ const mustacheInjectInline = {
|
|||||||
},
|
},
|
||||||
renderer(token) {
|
renderer(token) {
|
||||||
token.type = token.originalType;
|
token.type = token.originalType;
|
||||||
const text = this.parseInline([token]);
|
const text = this.parser.parseInline([token]);
|
||||||
const openingTag = /(<[^\s<>]+)([^\n<>]*>.*)/s.exec(text);
|
const openingTag = /(<[^\s<>]+)([^\n<>]*>.*)/s.exec(text);
|
||||||
if(openingTag) {
|
if(openingTag) {
|
||||||
return `${openingTag[1]} class="${token.tags}${openingTag[2]}`;
|
return `${openingTag[1]} class="${token.tags}${openingTag[2]}`;
|
||||||
@@ -174,15 +174,18 @@ const mustacheInjectBlock = {
|
|||||||
lastToken.originalType = 'mustacheInjectBlock';
|
lastToken.originalType = 'mustacheInjectBlock';
|
||||||
lastToken.tags = ` ${processStyleTags(match[1])}`;
|
lastToken.tags = ` ${processStyleTags(match[1])}`;
|
||||||
return {
|
return {
|
||||||
type : 'text', // 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
|
||||||
text : ''
|
text : ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
renderer(token) {
|
renderer(token) {
|
||||||
|
if(!token.originalType){
|
||||||
|
return;
|
||||||
|
}
|
||||||
token.type = token.originalType;
|
token.type = token.originalType;
|
||||||
const text = this.parse([token]);
|
const text = this.parser.parse([token]);
|
||||||
const openingTag = /(<[^\s<>]+)([^\n<>]*>.*)/s.exec(text);
|
const openingTag = /(<[^\s<>]+)([^\n<>]*>.*)/s.exec(text);
|
||||||
if(openingTag) {
|
if(openingTag) {
|
||||||
return `${openingTag[1]} class="${token.tags}${openingTag[2]}`;
|
return `${openingTag[1]} class="${token.tags}${openingTag[2]}`;
|
||||||
@@ -205,14 +208,14 @@ const definitionLists = {
|
|||||||
level : 'block',
|
level : 'block',
|
||||||
start(src) { return src.match(/^.*?::.*/m)?.index; }, // Hint to Marked.js to stop and check for a match
|
start(src) { return src.match(/^.*?::.*/m)?.index; }, // Hint to Marked.js to stop and check for a match
|
||||||
tokenizer(src, tokens) {
|
tokenizer(src, tokens) {
|
||||||
const regex = /^([^\n]*?)::([^\n]*)/ym;
|
const regex = /^([^\n]*?)::([^\n]*)(?:\n|$)/ym;
|
||||||
let match;
|
let match;
|
||||||
let endIndex = 0;
|
let endIndex = 0;
|
||||||
const definitions = [];
|
const definitions = [];
|
||||||
while (match = regex.exec(src)) {
|
while (match = regex.exec(src)) {
|
||||||
definitions.push({
|
definitions.push({
|
||||||
dt : this.inlineTokens(match[1].trim()),
|
dt : this.lexer.inlineTokens(match[1].trim()),
|
||||||
dd : this.inlineTokens(match[2].trim())
|
dd : this.lexer.inlineTokens(match[2].trim())
|
||||||
});
|
});
|
||||||
endIndex = regex.lastIndex;
|
endIndex = regex.lastIndex;
|
||||||
}
|
}
|
||||||
@@ -225,12 +228,10 @@ const definitionLists = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
renderer(token) {
|
renderer(token) {
|
||||||
return `<dl>
|
return `<dl>${token.definitions.reduce((html, def)=>{
|
||||||
${token.definitions.reduce((html, def)=>{
|
return `${html}<dt>${this.parser.parseInline(def.dt)}</dt>`
|
||||||
return `${html}<dt>${this.parseInline(def.dt)}</dt>`
|
+ `<dd>${this.parser.parseInline(def.dd)}</dd>\n`;
|
||||||
+ `<dd>${this.parseInline(def.dd)}</dd>\n`;
|
}, '')}</dl>`;
|
||||||
}, '')}
|
|
||||||
</dl>`;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -302,7 +303,7 @@ const spanTable = {
|
|||||||
row = item.header[j];
|
row = item.header[j];
|
||||||
for (k = 0; k < row.length; k++) {
|
for (k = 0; k < row.length; k++) {
|
||||||
row[k].tokens = [];
|
row[k].tokens = [];
|
||||||
this.inlineTokens(row[k].text, row[k].tokens);
|
this.lexer.inlineTokens(row[k].text, row[k].tokens);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,7 +313,7 @@ const spanTable = {
|
|||||||
row = item.rows[j];
|
row = item.rows[j];
|
||||||
for (k = 0; k < row.length; k++) {
|
for (k = 0; k < row.length; k++) {
|
||||||
row[k].tokens = [];
|
row[k].tokens = [];
|
||||||
this.inlineTokens(row[k].text, row[k].tokens);
|
this.lexer.inlineTokens(row[k].text, row[k].tokens);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
@@ -329,7 +330,7 @@ const spanTable = {
|
|||||||
output += `<tr>`;
|
output += `<tr>`;
|
||||||
for (j = 0; j < row.length; j++) {
|
for (j = 0; j < row.length; j++) {
|
||||||
cell = row[j];
|
cell = row[j];
|
||||||
text = this.parseInline(cell.tokens);
|
text = this.parser.parseInline(cell.tokens);
|
||||||
output += getTableCell(text, cell, 'th', token.align[col]);
|
output += getTableCell(text, cell, 'th', token.align[col]);
|
||||||
col += cell.colspan;
|
col += cell.colspan;
|
||||||
}
|
}
|
||||||
@@ -344,7 +345,7 @@ const spanTable = {
|
|||||||
output += `<tr>`;
|
output += `<tr>`;
|
||||||
for (j = 0; j < row.length; j++) {
|
for (j = 0; j < row.length; j++) {
|
||||||
cell = row[j];
|
cell = row[j];
|
||||||
text = this.parseInline(cell.tokens);
|
text = this.parser.parseInline(cell.tokens);
|
||||||
output += getTableCell(text, cell, 'td', token.align[col]);
|
output += getTableCell(text, cell, 'td', token.align[col]);
|
||||||
col += cell.colspan;
|
col += cell.colspan;
|
||||||
}
|
}
|
||||||
@@ -508,9 +509,15 @@ const sanatizeScriptTags = (content)=>{
|
|||||||
const tagTypes = ['div', 'span', 'a'];
|
const tagTypes = ['div', 'span', 'a'];
|
||||||
const tagRegex = new RegExp(`(${
|
const tagRegex = new RegExp(`(${
|
||||||
_.map(tagTypes, (type)=>{
|
_.map(tagTypes, (type)=>{
|
||||||
return `\\<${type}|\\</${type}>`;
|
return `\\<${type}\\b|\\</${type}>`;
|
||||||
}).join('|')})`, 'g');
|
}).join('|')})`, 'g');
|
||||||
|
|
||||||
|
// Special "void" tags that can be self-closed but don't need to be.
|
||||||
|
const voidTags = new Set([
|
||||||
|
'area', 'base', 'br', 'col', 'command', 'hr', 'img',
|
||||||
|
'input', 'keygen', 'link', 'meta', 'param', 'source'
|
||||||
|
]);
|
||||||
|
|
||||||
const processStyleTags = (string)=>{
|
const processStyleTags = (string)=>{
|
||||||
//split tags up. quotes can only occur right after colons.
|
//split tags up. quotes can only occur right after colons.
|
||||||
//TODO: can we simplify to just split on commas?
|
//TODO: can we simplify to just split on commas?
|
||||||
@@ -527,7 +534,7 @@ const processStyleTags = (string)=>{
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
marked : Markdown,
|
marked : Markdown,
|
||||||
render : (rawBrewText)=>{
|
render : (rawBrewText)=>{
|
||||||
rawBrewText = rawBrewText.replace(/^\\column$/gm, `<div class='columnSplit'></div>`)
|
rawBrewText = rawBrewText.replace(/^\\column$/gm, `\n<div class='columnSplit'></div>\n`)
|
||||||
.replace(/^(:+)$/gm, (match)=>`${`<div class='blank'></div>`.repeat(match.length)}\n`);
|
.replace(/^(:+)$/gm, (match)=>`${`<div class='blank'></div>`.repeat(match.length)}\n`);
|
||||||
return Markdown(
|
return Markdown(
|
||||||
sanatizeScriptTags(rawBrewText),
|
sanatizeScriptTags(rawBrewText),
|
||||||
@@ -551,6 +558,13 @@ module.exports = {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if(match === `</${type}>`){
|
if(match === `</${type}>`){
|
||||||
|
// Closing tag: Check we expect it to be closed.
|
||||||
|
// The accumulator may contain a sequence of voidable opening tags,
|
||||||
|
// over which we skip before checking validity of the close.
|
||||||
|
while (acc.length && voidTags.has(_.last(acc).type) && _.last(acc).type != type) {
|
||||||
|
acc.pop();
|
||||||
|
}
|
||||||
|
// Now check that what remains in the accumulator is valid.
|
||||||
if(!acc.length){
|
if(!acc.length){
|
||||||
errors.push({
|
errors.push({
|
||||||
line : lineNumber,
|
line : lineNumber,
|
||||||
|
|||||||
@@ -99,9 +99,15 @@ const sanatizeScriptTags = (content)=>{
|
|||||||
const tagTypes = ['div', 'span', 'a'];
|
const tagTypes = ['div', 'span', 'a'];
|
||||||
const tagRegex = new RegExp(`(${
|
const tagRegex = new RegExp(`(${
|
||||||
_.map(tagTypes, (type)=>{
|
_.map(tagTypes, (type)=>{
|
||||||
return `\\<${type}|\\</${type}>`;
|
return `\\<${type}\\b|\\</${type}>`;
|
||||||
}).join('|')})`, 'g');
|
}).join('|')})`, 'g');
|
||||||
|
|
||||||
|
// Special "void" tags that can be self-closed but don't need to be.
|
||||||
|
const voidTags = new Set([
|
||||||
|
'area', 'base', 'br', 'col', 'command', 'hr', 'img',
|
||||||
|
'input', 'keygen', 'link', 'meta', 'param', 'source'
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
marked : Markdown,
|
marked : Markdown,
|
||||||
@@ -128,6 +134,13 @@ module.exports = {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if(match === `</${type}>`){
|
if(match === `</${type}>`){
|
||||||
|
// Closing tag: Check we expect it to be closed.
|
||||||
|
// The accumulator may contain a sequence of voidable opening tags,
|
||||||
|
// over which we skip before checking validity of the close.
|
||||||
|
while (acc.length && voidTags.has(_.last(acc).type) && _.last(acc).type != type) {
|
||||||
|
acc.pop();
|
||||||
|
}
|
||||||
|
// Now check that what remains in the accumulator is valid.
|
||||||
if(!acc.length){
|
if(!acc.length){
|
||||||
errors.push({
|
errors.push({
|
||||||
line : lineNumber,
|
line : lineNumber,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
@headerText : #58180D; // Dark maroon
|
@headerText : #58180D; // Dark maroon
|
||||||
@monsterStatBackground : #EEDBAB; // Light orange parchment
|
@monsterStatBackground : #EEDBAB; // Light orange parchment
|
||||||
@captionText : #766649; // Brown
|
@captionText : #766649; // Brown
|
||||||
|
@watercolorStain : #BBAD82; // Light brown
|
||||||
@page { margin: 0; }
|
@page { margin: 0; }
|
||||||
body {
|
body {
|
||||||
counter-reset : phb-page-numbers;
|
counter-reset : phb-page-numbers;
|
||||||
@@ -18,7 +19,7 @@ body {
|
|||||||
}
|
}
|
||||||
.useSansSerif(){
|
.useSansSerif(){
|
||||||
font-family : ScalySansRemake;
|
font-family : ScalySansRemake;
|
||||||
font-size : 0.325cm;
|
font-size : 0.318cm;
|
||||||
line-height : 1.2em;
|
line-height : 1.2em;
|
||||||
p,dl,ul,ol {
|
p,dl,ul,ol {
|
||||||
line-height : 1.2em;
|
line-height : 1.2em;
|
||||||
@@ -33,10 +34,13 @@ body {
|
|||||||
font-weight : 800;
|
font-weight : 800;
|
||||||
letter-spacing : -0.02em;
|
letter-spacing : -0.02em;
|
||||||
}
|
}
|
||||||
|
h5 + * {
|
||||||
|
margin-top : 0.1cm;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.useColumns(@multiplier : 1){
|
.useColumns(@multiplier : 1, @fillMode: balance){
|
||||||
column-count : 2;
|
column-count : 2;
|
||||||
column-fill : auto;
|
column-fill : @fillMode;
|
||||||
column-gap : 0.9cm;
|
column-gap : 0.9cm;
|
||||||
column-width : 8cm * @multiplier;
|
column-width : 8cm * @multiplier;
|
||||||
-webkit-column-count : 2;
|
-webkit-column-count : 2;
|
||||||
@@ -46,6 +50,12 @@ body {
|
|||||||
-webkit-column-gap : 0.9cm;
|
-webkit-column-gap : 0.9cm;
|
||||||
-moz-column-gap : 0.9cm;
|
-moz-column-gap : 0.9cm;
|
||||||
}
|
}
|
||||||
|
.columnWrapper{
|
||||||
|
max-height : 100%;
|
||||||
|
column-span : all;
|
||||||
|
columns : inherit;
|
||||||
|
column-gap : inherit;
|
||||||
|
}
|
||||||
.page{
|
.page{
|
||||||
.useColumns();
|
.useColumns();
|
||||||
counter-increment : phb-page-numbers;
|
counter-increment : phb-page-numbers;
|
||||||
@@ -55,9 +65,9 @@ body {
|
|||||||
overflow : hidden;
|
overflow : hidden;
|
||||||
height : 279.4mm;
|
height : 279.4mm;
|
||||||
width : 215.9mm;
|
width : 215.9mm;
|
||||||
padding : 1.4cm 1.9cm 1.7cm;
|
|
||||||
background-color : @background;
|
background-color : @background;
|
||||||
background-image : @backgroundImage;
|
background-image : @backgroundImage;
|
||||||
|
padding : 1.4cm 1.9cm 1.7cm;
|
||||||
font-family : BookInsanityRemake;
|
font-family : BookInsanityRemake;
|
||||||
font-size : 0.34cm;
|
font-size : 0.34cm;
|
||||||
text-rendering : optimizeLegibility;
|
text-rendering : optimizeLegibility;
|
||||||
@@ -68,10 +78,13 @@ body {
|
|||||||
// *****************************/
|
// *****************************/
|
||||||
p{
|
p{
|
||||||
overflow-wrap : break-word; //TODO: MAKE ALL MARGINS TOP-ONLY. USE * + * STYLE SELECTORS
|
overflow-wrap : break-word; //TODO: MAKE ALL MARGINS TOP-ONLY. USE * + * STYLE SELECTORS
|
||||||
margin-bottom : 0.8em;
|
display : block;
|
||||||
line-height : 1.3em;
|
line-height : 1.3em;
|
||||||
|
&+* {
|
||||||
|
margin-top : 0.325cm;
|
||||||
|
}
|
||||||
&+p{
|
&+p{
|
||||||
margin-top : -0.8em;
|
margin-top : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ul{
|
ul{
|
||||||
@@ -121,53 +134,55 @@ body {
|
|||||||
color : @headerText;
|
color : @headerText;
|
||||||
}
|
}
|
||||||
h1{
|
h1{
|
||||||
margin-bottom : 0.18cm;
|
margin-bottom : 0.18cm; //Margin-bottom only because this is WIDE
|
||||||
column-span : all;
|
column-span : all;
|
||||||
font-size : 0.89cm;
|
font-size : 0.89cm;
|
||||||
-webkit-column-span : all;
|
-webkit-column-span : all;
|
||||||
-moz-column-span : all;
|
-moz-column-span : all;
|
||||||
&+p::first-letter{
|
&+p::first-letter{
|
||||||
float : left;
|
float : left;
|
||||||
font-family : SolberaImitationRemake;
|
font-family : SolberaImitationRemake;
|
||||||
line-height : 0.8em;
|
line-height : 1em;
|
||||||
font-size: 3.5cm;
|
font-size : 3.5cm;
|
||||||
padding-left: 40px;
|
padding-left : 40px; //Allow background color to extend into margins
|
||||||
margin-left: -40px;
|
margin-left : -40px;
|
||||||
padding-top:10px;
|
margin-top : -0.3cm;
|
||||||
margin-top:-8px;
|
padding-bottom : 2px;
|
||||||
padding-bottom:10px;
|
margin-bottom : -20px;
|
||||||
margin-bottom:-20px;
|
background-image : linear-gradient(-45deg, #322814, #998250, #322814);
|
||||||
background-image: linear-gradient(-45deg, #322814, #998250, #322814);
|
background-clip : text;
|
||||||
background-clip: text;
|
-webkit-background-clip : text;
|
||||||
-webkit-background-clip: text;
|
color : rgba(0, 0, 0, 0);
|
||||||
color: rgba(0, 0, 0, 0);
|
|
||||||
}
|
}
|
||||||
&+p::first-line{
|
&+p::first-line{
|
||||||
font-variant : small-caps;
|
font-variant : small-caps;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
h2{
|
h2{
|
||||||
margin-top : 0px;
|
//margin-top : 0px; //Font is misaligned. Shift up slightly
|
||||||
margin-bottom : 0.05cm;
|
//margin-bottom : 0.05cm;
|
||||||
font-size : 0.75cm;
|
font-size : 0.75cm;
|
||||||
}
|
}
|
||||||
h3{
|
h3{
|
||||||
margin-top : -0.1cm;
|
//margin-top : -0.1cm; //Font is misaligned. Shift up slightly
|
||||||
margin-bottom : 0.1cm;
|
//margin-bottom : 0.1cm;
|
||||||
font-size : 0.575cm;
|
font-size : 0.575cm;
|
||||||
border-bottom : 2px solid @headerUnderline;
|
border-bottom : 2px solid @headerUnderline;
|
||||||
}
|
}
|
||||||
h4{
|
h4{
|
||||||
margin-top : -0.02cm;
|
//margin-top : -0.02cm; //Font is misaligned. Shift up slightly
|
||||||
margin-bottom : 0.02cm;
|
//margin-bottom : 0.02cm;
|
||||||
font-size : 0.458cm;
|
font-size : 0.458cm;
|
||||||
}
|
}
|
||||||
h5{
|
h5{
|
||||||
margin-top : -0.02cm;
|
//margin-top : -0.02cm; //Font is misaligned. Shift up slightly
|
||||||
margin-bottom : 0.02cm;
|
//margin-bottom : 0.02cm;
|
||||||
font-family : ScalySansSmallCapsRemake;
|
font-family : ScalySansSmallCapsRemake;
|
||||||
font-size : 0.423cm;
|
font-size : 0.423cm;
|
||||||
font-weight : 900;
|
font-weight : 900;
|
||||||
|
& + * {
|
||||||
|
margin-top : 0.2cm;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//*****************************
|
//*****************************
|
||||||
// * TABLE
|
// * TABLE
|
||||||
@@ -175,7 +190,9 @@ body {
|
|||||||
table{
|
table{
|
||||||
.useSansSerif();
|
.useSansSerif();
|
||||||
width : 100%;
|
width : 100%;
|
||||||
margin-bottom : 1em;
|
& + * {
|
||||||
|
margin-top : 0.325cm;
|
||||||
|
}
|
||||||
thead{
|
thead{
|
||||||
display: table-row-group;
|
display: table-row-group;
|
||||||
font-weight : 800;
|
font-weight : 800;
|
||||||
@@ -199,29 +216,23 @@ body {
|
|||||||
// * NOTE
|
// * NOTE
|
||||||
// *****************************/
|
// *****************************/
|
||||||
.note{
|
.note{
|
||||||
&::before{
|
|
||||||
content : "";
|
|
||||||
box-sizing : border-box;
|
|
||||||
border-style : solid;
|
|
||||||
border-width : 11px;
|
|
||||||
border-image : @noteBorderImage 12;
|
|
||||||
border-image-outset : 9px 0px;
|
|
||||||
box-shadow : 1px 4px 14px #888;
|
|
||||||
position : absolute;
|
|
||||||
width : 100%;
|
|
||||||
height : 100%;
|
|
||||||
top : 0;
|
|
||||||
left : 0;
|
|
||||||
}
|
|
||||||
.useSansSerif();
|
.useSansSerif();
|
||||||
position : relative;
|
|
||||||
margin-top : 1.3em;
|
|
||||||
margin-left : -0.1em;
|
|
||||||
margin-right : -0.1em;
|
|
||||||
background-color : @noteGreen;
|
background-color : @noteGreen;
|
||||||
padding : 0.5em 0.6em;
|
border-style : solid;
|
||||||
|
border-width : 1px;
|
||||||
|
border-image : @noteBorderImage 12 stretch;
|
||||||
|
border-image-outset : 9px 0px;
|
||||||
|
border-image-width : 11px;
|
||||||
|
padding : 0.13cm 0.16cm;
|
||||||
|
filter : drop-shadow(1px 4px 6px #888);
|
||||||
|
.page :where(&) {
|
||||||
|
margin-top : 9px; //Prevent top border getting cut off on colbreak
|
||||||
|
}
|
||||||
& + * {
|
& + * {
|
||||||
margin-top : 1.3em;
|
margin-top : 0.45cm;
|
||||||
|
}
|
||||||
|
h5 {
|
||||||
|
font-size : 0.375cm;
|
||||||
}
|
}
|
||||||
p{
|
p{
|
||||||
display : block;
|
display : block;
|
||||||
@@ -231,7 +242,7 @@ body {
|
|||||||
padding-top : .8em;
|
padding-top : .8em;
|
||||||
}
|
}
|
||||||
:last-child {
|
:last-child {
|
||||||
margin-bottom : 0em;
|
margin-bottom : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//************************************
|
//************************************
|
||||||
@@ -239,18 +250,21 @@ body {
|
|||||||
// ************************************/
|
// ************************************/
|
||||||
.descriptive{
|
.descriptive{
|
||||||
.useSansSerif();
|
.useSansSerif();
|
||||||
display : block-inline;
|
|
||||||
margin-top : 1.4em;
|
|
||||||
background-color : #faf7ea;
|
background-color : #faf7ea;
|
||||||
font-family : ScalySansRemake;
|
|
||||||
border-style : solid;
|
border-style : solid;
|
||||||
border-width : 7px;
|
border-width : 7px;
|
||||||
border-image : @descriptiveBoxImage 12 stretch;
|
border-image : @descriptiveBoxImage 12 stretch;
|
||||||
border-image-outset : 4px;
|
border-image-outset : 4px;
|
||||||
box-shadow : 0px 0px 6px #faf7ea;
|
|
||||||
padding : 0.1em;
|
padding : 0.1em;
|
||||||
|
filter : drop-shadow(0 0 3px #faf7ea);
|
||||||
|
.page :where(&) {
|
||||||
|
margin-top : 4px; //Prevent top border getting cut off on colbreak
|
||||||
|
}
|
||||||
& + * {
|
& + * {
|
||||||
margin-top : 1.4em;
|
margin-top : 0.45cm;
|
||||||
|
}
|
||||||
|
h5 {
|
||||||
|
font-size : 0.375cm;
|
||||||
}
|
}
|
||||||
p{
|
p{
|
||||||
display : block;
|
display : block;
|
||||||
@@ -261,14 +275,17 @@ body {
|
|||||||
padding-top : .8em;
|
padding-top : .8em;
|
||||||
}
|
}
|
||||||
:last-child {
|
:last-child {
|
||||||
margin-bottom : 0em;
|
margin-bottom : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//*****************************
|
//*****************************
|
||||||
// * ARTIST CREDIT BLOCK
|
// * Images Snippets
|
||||||
// *****************************/
|
// *****************************/
|
||||||
|
|
||||||
|
/* Arist Credit */
|
||||||
.artist {
|
.artist {
|
||||||
position : absolute;
|
position : absolute;
|
||||||
|
width : auto;
|
||||||
text-align : center;
|
text-align : center;
|
||||||
font-family : WalterTurncoat;
|
font-family : WalterTurncoat;
|
||||||
font-size : 0.27cm;
|
font-size : 0.27cm;
|
||||||
@@ -291,6 +308,58 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Watermark */
|
||||||
|
.watermark {
|
||||||
|
display : grid !important;
|
||||||
|
place-items : center;
|
||||||
|
justify-content : center;
|
||||||
|
position : absolute;
|
||||||
|
top : 0;
|
||||||
|
left : 0;
|
||||||
|
width : 100%;
|
||||||
|
height : 100%;
|
||||||
|
font-size : 120px;
|
||||||
|
text-transform : uppercase;
|
||||||
|
color : black;
|
||||||
|
mix-blend-mode : overlay;
|
||||||
|
opacity : 30%;
|
||||||
|
transform : rotate(-45deg);
|
||||||
|
z-index : 500;
|
||||||
|
p {
|
||||||
|
margin-bottom : none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Watercolor */
|
||||||
|
[class*="watercolor"] {
|
||||||
|
position : absolute;
|
||||||
|
width : 2000px; /* dimensions need to be real big so the user can set */
|
||||||
|
height : 2000px; /* height or width and the image will maintain aspect ratio */
|
||||||
|
-webkit-mask-image : var(--wc);
|
||||||
|
-webkit-mask-size : contain;
|
||||||
|
-webkit-mask-repeat : no-repeat;
|
||||||
|
mask-image : var(--wc);
|
||||||
|
mask-size : contain;
|
||||||
|
mask-repeat : no-repeat;
|
||||||
|
background-size : cover;
|
||||||
|
background-color : @watercolorStain; /*default color*/
|
||||||
|
--wc : @watercolor1; /*default image*/
|
||||||
|
z-index : -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.watercolor1 { --wc : @watercolor1; }
|
||||||
|
.watercolor2 { --wc : @watercolor2; }
|
||||||
|
.watercolor3 { --wc : @watercolor3; }
|
||||||
|
.watercolor4 { --wc : @watercolor4; }
|
||||||
|
.watercolor5 { --wc : @watercolor5; }
|
||||||
|
.watercolor6 { --wc : @watercolor6; }
|
||||||
|
.watercolor7 { --wc : @watercolor7; }
|
||||||
|
.watercolor8 { --wc : @watercolor8; }
|
||||||
|
.watercolor9 { --wc : @watercolor9; }
|
||||||
|
.watercolor10 { --wc : @watercolor10; }
|
||||||
|
.watercolor11 { --wc : @watercolor11; }
|
||||||
|
.watercolor12 { --wc : @watercolor12; }
|
||||||
|
|
||||||
//*****************************
|
//*****************************
|
||||||
// * MONSTER STAT BLOCK
|
// * MONSTER STAT BLOCK
|
||||||
// *****************************/
|
// *****************************/
|
||||||
@@ -305,26 +374,16 @@ body {
|
|||||||
border-image-outset : 0px 2px;
|
border-image-outset : 0px 2px;
|
||||||
background-blend-mode : overlay;
|
background-blend-mode : overlay;
|
||||||
background-attachment : fixed;
|
background-attachment : fixed;
|
||||||
box-shadow : 1px 4px 14px #888;
|
filter : drop-shadow(1px 4px 6px #888);
|
||||||
padding : 4px 2px;
|
padding : 4px 2px;
|
||||||
margin : 0px -6px 1em;
|
margin-left : -0.16cm;
|
||||||
|
margin-right : -0.16cm;
|
||||||
|
width : calc(100% + 0.32cm);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-webkit-transform : translateZ(0); //Prevents shadows from breaking across columns, but breaks internal columns...
|
|
||||||
position : relative;
|
position : relative;
|
||||||
padding : 0px;
|
padding : 0px;
|
||||||
margin-bottom : 1em;
|
margin-bottom : 0.325cm;
|
||||||
|
|
||||||
p{
|
|
||||||
margin-bottom : 0.3cm;
|
|
||||||
}
|
|
||||||
p+p {
|
|
||||||
margin-top : 0; //May not be needed
|
|
||||||
text-indent : 0;
|
|
||||||
}
|
|
||||||
p:last-of-type {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Headers
|
//Headers
|
||||||
h2{
|
h2{
|
||||||
@@ -341,7 +400,7 @@ body {
|
|||||||
font-weight : 800;
|
font-weight : 800;
|
||||||
font-variant : small-caps;
|
font-variant : small-caps;
|
||||||
border-bottom : 2px solid @headerText;
|
border-bottom : 2px solid @headerText;
|
||||||
margin-top : 0.05cm;
|
// margin-top : 0.05cm; //Font is misaligned. Shift up slightly
|
||||||
padding-bottom : 0.05cm;
|
padding-bottom : 0.05cm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,20 +414,28 @@ body {
|
|||||||
border : none;
|
border : none;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Attribute Lists
|
//Attribute Lists - All text between HRs is red
|
||||||
dl {
|
hr ~ :is(dl,p) {
|
||||||
color : @headerText;
|
color : @headerText;
|
||||||
}
|
}
|
||||||
|
hr:last-of-type {
|
||||||
|
& ~ :is(dl,p) {
|
||||||
|
color : inherit; // After the HRs, reset text to black
|
||||||
|
}
|
||||||
|
& + * {
|
||||||
|
margin-top : 0.325cm; // Space after last HR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Monster Ability table
|
// Monster Ability table
|
||||||
hr + table:first-of-type{
|
hr + table:first-of-type{
|
||||||
margin : 0;
|
margin : 0;
|
||||||
column-span : 1;
|
column-span : none;
|
||||||
color : @headerText;
|
color : @headerText;
|
||||||
background-color : transparent;
|
background-color : transparent;
|
||||||
border-style : none;
|
border-style : none;
|
||||||
border-image : none;
|
border-image : none;
|
||||||
-webkit-column-span : 1;
|
-webkit-column-span : none;
|
||||||
tr {
|
tr {
|
||||||
background-color : transparent;
|
background-color : transparent;
|
||||||
}
|
}
|
||||||
@@ -376,11 +443,15 @@ body {
|
|||||||
padding: 0px;
|
padding: 0px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:last-child {
|
||||||
|
margin-bottom : 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Full Width
|
//Full Width
|
||||||
.monster.wide{
|
.monster.wide{
|
||||||
.useColumns(0.96);
|
.useColumns(0.96, @fillMode: balance);
|
||||||
}
|
}
|
||||||
|
|
||||||
//*****************************
|
//*****************************
|
||||||
@@ -447,14 +518,20 @@ body {
|
|||||||
|
|
||||||
pre code{
|
pre code{
|
||||||
width : 100%;
|
width : 100%;
|
||||||
display : block;
|
display : inline-block;
|
||||||
border : 4px solid;
|
border-style : solid;
|
||||||
|
border-width : 1px;
|
||||||
border-image : @codeBorderImage 26 stretch;
|
border-image : @codeBorderImage 26 stretch;
|
||||||
border-image-width : 10px;
|
border-image-width : 10px;
|
||||||
border-image-outset : 2px;
|
border-image-outset : 2px;
|
||||||
border-radius : 12px;
|
border-radius : 12px;
|
||||||
|
margin-bottom : 2px;
|
||||||
|
padding : 0.15cm;
|
||||||
|
.page :where(&) {
|
||||||
|
margin-top : 2px; //Prevent top border getting cut off on colbreak
|
||||||
|
}
|
||||||
& + * {
|
& + * {
|
||||||
margin-top : 1em;
|
margin-top : 0.325cm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//*****************************
|
//*****************************
|
||||||
@@ -464,13 +541,6 @@ body {
|
|||||||
visibility : hidden;
|
visibility : hidden;
|
||||||
margin : 0px;
|
margin : 0px;
|
||||||
}
|
}
|
||||||
//Modified unorder list, used in spells
|
|
||||||
hr+ul{
|
|
||||||
margin-bottom : 0.5em;
|
|
||||||
padding-left : 1em;
|
|
||||||
text-indent : -1em;
|
|
||||||
list-style-type : none;
|
|
||||||
}
|
|
||||||
.columnSplit {
|
.columnSplit {
|
||||||
visibility : hidden;
|
visibility : hidden;
|
||||||
-webkit-column-break-after : always;
|
-webkit-column-break-after : always;
|
||||||
@@ -485,10 +555,6 @@ body {
|
|||||||
page-break-inside : avoid;
|
page-break-inside : avoid;
|
||||||
break-inside : avoid;
|
break-inside : avoid;
|
||||||
}
|
}
|
||||||
//Better spacing for spell blocks
|
|
||||||
h4+p+hr+ul{
|
|
||||||
margin-top : -0.5em
|
|
||||||
}
|
|
||||||
//Text indent right after table
|
//Text indent right after table
|
||||||
table+p{
|
table+p{
|
||||||
text-indent : 1em;
|
text-indent : 1em;
|
||||||
@@ -509,10 +575,7 @@ body {
|
|||||||
// *****************************/
|
// *****************************/
|
||||||
.page .spellList{
|
.page .spellList{
|
||||||
.useSansSerif();
|
.useSansSerif();
|
||||||
column-count : 4;
|
column-count : 2;
|
||||||
column-span : all;
|
|
||||||
-webkit-column-span : all;
|
|
||||||
-moz-column-span : all;
|
|
||||||
ul+h5{
|
ul+h5{
|
||||||
margin-top : 15px;
|
margin-top : 15px;
|
||||||
}
|
}
|
||||||
@@ -529,32 +592,57 @@ body {
|
|||||||
page-break-inside : auto;
|
page-break-inside : auto;
|
||||||
break-inside : auto;
|
break-inside : auto;
|
||||||
}
|
}
|
||||||
|
&.wide{
|
||||||
|
column-count : 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//*****************************
|
|
||||||
// * WIDE
|
|
||||||
// *****************************/
|
|
||||||
.page .wide{
|
|
||||||
column-span : all;
|
|
||||||
-webkit-column-span : all;
|
|
||||||
-moz-column-span : all;
|
|
||||||
}
|
|
||||||
//*****************************
|
//*****************************
|
||||||
// * CLASS TABLE
|
// * CLASS TABLE
|
||||||
// *****************************/
|
// *****************************/
|
||||||
.page .classTable{
|
.page .classTable{
|
||||||
margin-top : 25px;
|
th[colspan]:not([rowspan]) {
|
||||||
margin-bottom : 40px;
|
white-space : nowrap;
|
||||||
border-collapse : separate;
|
}
|
||||||
background-color : white;
|
&.frame {
|
||||||
border : initial;
|
margin-top : 0.66cm;
|
||||||
border-style : solid;
|
margin-bottom : 1.05cm;
|
||||||
border-image-outset : 25px 17px;
|
margin-left : -0.1cm;
|
||||||
border-image-repeat : stretch;
|
margin-right : -0.1cm;
|
||||||
border-image-slice : 150 200 150 200;
|
width : calc(100% + 0.2cm);
|
||||||
border-image-source : @frameBorderImage;
|
border-collapse : separate;
|
||||||
border-image-width : 47px;
|
background-color : white;
|
||||||
h5{
|
border : initial;
|
||||||
margin-bottom : 10px;
|
border-style : solid;
|
||||||
|
border-image-outset : 0.55cm 0.3cm;
|
||||||
|
border-image-repeat : stretch;
|
||||||
|
border-image-slice : 200;
|
||||||
|
border-image-source : @frameBorderImage;
|
||||||
|
border-image-width : 47px;
|
||||||
|
}
|
||||||
|
&.decoration {
|
||||||
|
transform-style : preserve-3d;
|
||||||
|
}
|
||||||
|
&.decoration::before {
|
||||||
|
content :'';
|
||||||
|
position : absolute;
|
||||||
|
background-image : @classTableDecoration;
|
||||||
|
background-size : contain;
|
||||||
|
background-repeat : space;
|
||||||
|
width : 7.75cm;
|
||||||
|
height : calc(100% + 3.3cm);
|
||||||
|
top : 50%;
|
||||||
|
left : 50%;
|
||||||
|
transform : translateY(-50%) translateX(-50%) translateZ(-1px);
|
||||||
|
filter : drop-shadow(0px 0px 1px #C8C5C080)
|
||||||
|
}
|
||||||
|
&.decoration.wide::before {
|
||||||
|
width : calc(100% + 3.3cm);
|
||||||
|
height : 7.75cm;
|
||||||
|
top : calc(50% + 0.4cm);
|
||||||
|
}
|
||||||
|
h5 + table{
|
||||||
|
margin-top : 0.2cm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//*****************************
|
//*****************************
|
||||||
@@ -626,7 +714,7 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.wide{
|
&.wide{
|
||||||
.useColumns(0.96);
|
.useColumns(0.96, @fillMode: balance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -635,16 +723,16 @@ body {
|
|||||||
// *****************************/
|
// *****************************/
|
||||||
.page {
|
.page {
|
||||||
.block {
|
.block {
|
||||||
break-inside : avoid;
|
break-inside : avoid;
|
||||||
-webkit-transform : translateZ(0); //Prevents shadows from breaking across columns
|
display : inline-block;
|
||||||
|
.page :where(&) {
|
||||||
|
width : 100%;
|
||||||
|
}
|
||||||
|
//-webkit-transform : translateZ(0); //Prevents shadows from breaking across columns
|
||||||
}
|
}
|
||||||
.inline-block {
|
.inline-block {
|
||||||
display : inline-block;
|
display : inline-block;
|
||||||
text-indent : initial;
|
text-indent : initial;
|
||||||
line-height : 1.3em;
|
|
||||||
}
|
|
||||||
div {
|
|
||||||
column-gap : 0.5cm; //Default spacing if a div uses multicolumns
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -655,20 +743,21 @@ body {
|
|||||||
dl {
|
dl {
|
||||||
line-height : 1.3em;
|
line-height : 1.3em;
|
||||||
padding-left : 1em;
|
padding-left : 1em;
|
||||||
text-indent : -1em;
|
white-space : pre-line;
|
||||||
|
& + * {
|
||||||
|
margin-top : 0.28cm;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
dl + * {
|
dl + * {
|
||||||
margin-top : 0.28cm;
|
margin-top : 0.17cm;
|
||||||
}
|
|
||||||
dl + p {
|
|
||||||
margin-top : 0.5em;
|
|
||||||
}
|
}
|
||||||
p + dl {
|
p + dl {
|
||||||
margin-top: -0.5em;
|
margin-top: 0.17cm;
|
||||||
}
|
}
|
||||||
dt {
|
dt {
|
||||||
display : inline;
|
display : inline;
|
||||||
margin-right : 5px;
|
margin-right : 5px;
|
||||||
|
margin-left : -1em;
|
||||||
}
|
}
|
||||||
dd {
|
dd {
|
||||||
display : inline;
|
display : inline;
|
||||||
@@ -682,9 +771,21 @@ body {
|
|||||||
// *****************************/
|
// *****************************/
|
||||||
.page {
|
.page {
|
||||||
.blank {
|
.blank {
|
||||||
height: 0.75em;
|
height : 1em;
|
||||||
}
|
margin-top : 0;
|
||||||
p + .blank {
|
}
|
||||||
margin-top: -1em;
|
}
|
||||||
|
|
||||||
|
//*****************************
|
||||||
|
// * WIDE
|
||||||
|
// *****************************/
|
||||||
|
.page .wide{
|
||||||
|
column-span : all;
|
||||||
|
-webkit-column-span : all;
|
||||||
|
-moz-column-span : all;
|
||||||
|
display : block;
|
||||||
|
margin-bottom : 0.34cm;
|
||||||
|
&+* {
|
||||||
|
margin-top : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -231,11 +231,9 @@ body {
|
|||||||
// Monster Ability table
|
// Monster Ability table
|
||||||
hr+table{
|
hr+table{
|
||||||
margin : 0;
|
margin : 0;
|
||||||
column-span : 1;
|
|
||||||
background-color : transparent;
|
background-color : transparent;
|
||||||
border-style : none;
|
border-style : none;
|
||||||
border-image : none;
|
border-image : none;
|
||||||
-webkit-column-span : 1;
|
|
||||||
tbody{
|
tbody{
|
||||||
tr:nth-child(odd), tr:nth-child(even){
|
tr:nth-child(odd), tr:nth-child(even){
|
||||||
background-color : transparent;
|
background-color : transparent;
|
||||||
@@ -416,7 +414,6 @@ body {
|
|||||||
// * DESCRIPTIVE TEXT BOX
|
// * DESCRIPTIVE TEXT BOX
|
||||||
// ************************************/
|
// ************************************/
|
||||||
.phb .descriptive{
|
.phb .descriptive{
|
||||||
display : block-inline;
|
|
||||||
margin-bottom : 1em;
|
margin-bottom : 1em;
|
||||||
background-color : #faf7ea;
|
background-color : #faf7ea;
|
||||||
font-family : ScalySans;
|
font-family : ScalySans;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// PHB
|
||||||
@footerAccentImage : data-uri('./themes/assets/footerAccent.png');
|
@footerAccentImage : data-uri('./themes/assets/footerAccent.png');
|
||||||
@frameBorderImage : data-uri('./themes/assets/frameBorder.png');
|
@frameBorderImage : data-uri('./themes/assets/frameBorder.png');
|
||||||
@backgroundImage : data-uri('./themes/assets/parchmentBackground.jpg');
|
@backgroundImage : data-uri('./themes/assets/parchmentBackground.jpg');
|
||||||
@@ -8,3 +9,18 @@
|
|||||||
@monsterBlockBackground : data-uri('./themes/assets/parchmentBackgroundGrayscale.jpg');
|
@monsterBlockBackground : data-uri('./themes/assets/parchmentBackgroundGrayscale.jpg');
|
||||||
@monsterBorderImage : data-uri('./themes/assets/monsterBorderFancy.png');
|
@monsterBorderImage : data-uri('./themes/assets/monsterBorderFancy.png');
|
||||||
@codeBorderImage : data-uri('./themes/assets/codeBorder.png');
|
@codeBorderImage : data-uri('./themes/assets/codeBorder.png');
|
||||||
|
@classTableDecoration : data-uri('./themes/assets/classTableDecoration.png');
|
||||||
|
|
||||||
|
// Watercolor Images
|
||||||
|
@watercolor1 : data-uri('./themes/assets/watercolor/watercolor1.png');
|
||||||
|
@watercolor2 : data-uri('./themes/assets/watercolor/watercolor2.png');
|
||||||
|
@watercolor3 : data-uri('./themes/assets/watercolor/watercolor3.png');
|
||||||
|
@watercolor4 : data-uri('./themes/assets/watercolor/watercolor4.png');
|
||||||
|
@watercolor5 : data-uri('./themes/assets/watercolor/watercolor5.png');
|
||||||
|
@watercolor6 : data-uri('./themes/assets/watercolor/watercolor6.png');
|
||||||
|
@watercolor7 : data-uri('./themes/assets/watercolor/watercolor7.png');
|
||||||
|
@watercolor8 : data-uri('./themes/assets/watercolor/watercolor8.png');
|
||||||
|
@watercolor9 : data-uri('./themes/assets/watercolor/watercolor9.png');
|
||||||
|
@watercolor10 : data-uri('./themes/assets/watercolor/watercolor10.png');
|
||||||
|
@watercolor11 : data-uri('./themes/assets/watercolor/watercolor11.png');
|
||||||
|
@watercolor12 : data-uri('./themes/assets/watercolor/watercolor12.png');
|
||||||
|
|||||||
BIN
themes/assets/classTableDecoration.png
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
themes/assets/watercolor/watercolor1.png
Normal file
|
After Width: | Height: | Size: 161 KiB |
BIN
themes/assets/watercolor/watercolor10.png
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
themes/assets/watercolor/watercolor11.png
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
themes/assets/watercolor/watercolor12.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
themes/assets/watercolor/watercolor2.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
themes/assets/watercolor/watercolor3.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
themes/assets/watercolor/watercolor4.png
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
themes/assets/watercolor/watercolor5.png
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
themes/assets/watercolor/watercolor6.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
themes/assets/watercolor/watercolor7.png
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
themes/assets/watercolor/watercolor8.png
Normal file
|
After Width: | Height: | Size: 71 KiB |
BIN
themes/assets/watercolor/watercolor9.png
Normal file
|
After Width: | Height: | Size: 73 KiB |