Compare commits
82 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4f46f34f51 | ||
![]() |
7213f44192 | ||
![]() |
6d4ab9423e | ||
![]() |
6d188edef3 | ||
![]() |
ba63c28e01 | ||
![]() |
5c73ec1c9d | ||
![]() |
b98b515564 | ||
![]() |
8c89c6b5fa | ||
![]() |
a30d0db4e4 | ||
![]() |
cdcd9c19e9 | ||
![]() |
b95bb89066 | ||
![]() |
52f7a2eed2 | ||
![]() |
5c7e0adabb | ||
![]() |
bd9e0ee283 | ||
![]() |
b5b24a46f8 | ||
![]() |
05683d77fd | ||
![]() |
a38f787eda | ||
![]() |
7f20f8b300 | ||
![]() |
37f915e6d6 | ||
![]() |
60900b2295 | ||
![]() |
865e5cf34d | ||
![]() |
36cd5a021e | ||
![]() |
17f669f2d2 | ||
![]() |
f0a80e3beb | ||
![]() |
4bf53c5174 | ||
![]() |
b3bd386195 | ||
![]() |
bafce8cad4 | ||
![]() |
a71bdd25e3 | ||
![]() |
f5baea755a | ||
![]() |
8d4aae4997 | ||
![]() |
789ef7fcc2 | ||
![]() |
73cb8bf415 | ||
![]() |
28b8f9a00d | ||
![]() |
df8123698f | ||
![]() |
1c0dc989e9 | ||
![]() |
45ca486e9d | ||
![]() |
0d83a3374b | ||
![]() |
95a5a3b181 | ||
![]() |
a66a6c068f | ||
![]() |
628fc4aeec | ||
![]() |
36581c4665 | ||
![]() |
603dc59bfa | ||
![]() |
94642bac3a | ||
![]() |
2c3cd548ac | ||
![]() |
93901c03eb | ||
![]() |
e1b6f258e0 | ||
![]() |
4e1cd5714c | ||
![]() |
5ef1c284d0 | ||
![]() |
4a0adb7984 | ||
![]() |
84efa5f654 | ||
![]() |
2234c2304a | ||
![]() |
16f5ee9de7 | ||
![]() |
96f3dda172 | ||
![]() |
c9da3b2033 | ||
![]() |
b49a04869a | ||
![]() |
a8fe015e16 | ||
![]() |
2d8253b493 | ||
![]() |
640cadac63 | ||
![]() |
86b2ad9a72 | ||
![]() |
18f5e653fc | ||
![]() |
7b50b77267 | ||
![]() |
b2a43cc946 | ||
![]() |
90a6824e37 | ||
![]() |
89ca44069b | ||
![]() |
2fba3427cc | ||
![]() |
16ca3af64b | ||
![]() |
5a9ae69368 | ||
![]() |
4ad1414be7 | ||
![]() |
894532668e | ||
![]() |
e0b37bbf33 | ||
![]() |
513af3a56b | ||
![]() |
b7ba325a60 | ||
![]() |
531d24f2e6 | ||
![]() |
d6c6426aed | ||
![]() |
892fa05c42 | ||
![]() |
99507b0884 | ||
![]() |
bb646d64c0 | ||
![]() |
25e6af91c8 | ||
![]() |
85492f8a6e | ||
![]() |
56f1f8eaaa | ||
![]() |
fec38cfbb2 | ||
![]() |
b679575e0f |
BIN
.DS_Store
vendored
5
.babelrc
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"presets": [["es2015", {"modules": false}], "stage-2"],
|
||||
"plugins": ["transform-runtime"],
|
||||
"comments": false
|
||||
}
|
9
.editorconfig
Normal file
|
@ -0,0 +1,9 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
4
.eslintignore
Normal file
|
@ -0,0 +1,4 @@
|
|||
build/*.js
|
||||
config/*.js
|
||||
dist/*.js
|
||||
src/tmp/*.js
|
31
.eslintrc.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
module.exports = {
|
||||
root: true,
|
||||
parserOptions: {
|
||||
sourceType: 'module'
|
||||
},
|
||||
env: {
|
||||
browser: true
|
||||
},
|
||||
globals: {
|
||||
'cordova': true,
|
||||
'DEV': true,
|
||||
'PROD': true,
|
||||
'__THEME': true
|
||||
},
|
||||
// https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
|
||||
extends: 'standard',
|
||||
// required to lint *.vue files
|
||||
plugins: [
|
||||
'html'
|
||||
],
|
||||
// add your custom rules here
|
||||
'rules': {
|
||||
// allow paren-less arrow functions
|
||||
'arrow-parens': 0,
|
||||
'one-var': 0,
|
||||
'import/first': 0,
|
||||
// allow debugger during development
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
|
||||
'brace-style': [2, 'stroustrup', { 'allowSingleLine': true }]
|
||||
}
|
||||
}
|
51
.gitignore
vendored
|
@ -1,37 +1,14 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules
|
||||
jspm_packages
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
.DS_Store
|
||||
src/tmp/
|
||||
node_modules/
|
||||
dist/
|
||||
src/statics/spells.json
|
||||
npm-debug.log
|
||||
npm-debug.log.*
|
||||
selenium-debug.log
|
||||
test/unit/coverage
|
||||
test/e2e/reports
|
||||
cordova/platforms
|
||||
cordova/plugins
|
||||
thumbs.db
|
||||
!.gitkeep
|
||||
|
|
35
.stylintrc
Normal file
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"blocks": "never",
|
||||
"brackets": "never",
|
||||
"colons": "never",
|
||||
"colors": "always",
|
||||
"commaSpace": "always",
|
||||
"commentSpace": "always",
|
||||
"cssLiteral": "never",
|
||||
"depthLimit": false,
|
||||
"duplicates": true,
|
||||
"efficient": "always",
|
||||
"extendPref": false,
|
||||
"globalDupe": true,
|
||||
"indentPref": 2,
|
||||
"leadingZero": "never",
|
||||
"maxErrors": false,
|
||||
"maxWarnings": false,
|
||||
"mixed": false,
|
||||
"namingConvention": false,
|
||||
"namingConventionStrict": false,
|
||||
"none": "never",
|
||||
"noImportant": false,
|
||||
"parenSpace": "never",
|
||||
"placeholder": false,
|
||||
"prefixVarsWithDollar": "always",
|
||||
"quotePref": "single",
|
||||
"semicolons": "never",
|
||||
"sortOrder": false,
|
||||
"stackedProperties": "never",
|
||||
"trailingWhitespace": "never",
|
||||
"universal": "never",
|
||||
"valid": true,
|
||||
"zeroUnits": "never",
|
||||
"zIndexNormalize": false
|
||||
}
|
24
LICENSE
Normal file
|
@ -0,0 +1,24 @@
|
|||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <https://unlicense.org>
|
45
README.md
|
@ -1,18 +1,39 @@
|
|||
# My Spells
|
||||
...is a user friendly mobile responsive app designed to do one thing well: _View Spells_.
|
||||
|
||||
[Check it out on github.io](https://sharpshark28.github.io/my_spells/)!
|
||||
My Spells is an open source web-based application to elegantly view spells and save them to your local spellbook.
|
||||
|
||||
## Systems Supported
|
||||
* Dungeons & Dragons 5e
|
||||
* Hackmaster 4e (WIP)
|
||||
[](https://play.google.com/store/apps/details?id=io.cordova.myspells)
|
||||
|
||||
### Will you support _X_ system?
|
||||
Anyone who wishes to write up spells for a system in json format matching the same syntax used by the existing systems in this repo is welcome to add their system of choice.
|
||||
## License
|
||||
|
||||
## For Developers
|
||||
1. Clone/Fork Repo
|
||||
2. `npm install`
|
||||
3. `npm run develop`
|
||||
Open Game License v1.0a Copyright 2000, Wizards of the Coast, Inc.
|
||||
|
||||
You may wish to run a local http server such as [http-server](https://github.com/indexzero/http-server).
|
||||
App contains content from the SRD and is restricted and covered by the OGL. You can find the OGL 1.0a at [ogl.html](./ogl.html) in this app's repo, or [online here](http://www.opengamingfoundation.org/ogl.html). When using said data, please make sure to conform appropriately with the proper licenses and whatnot.
|
||||
|
||||
## Credit
|
||||
|
||||
* ephe's [grimoire](https://github.com/ephe/grimoire/) spell list converted json by vorpalhex and cleaned up to meet OGL license standards [labeled under srd_spells](https://github.com/vorpalhex/srd_spells)
|
||||
* Built on [Vue.js](https://vuejs.org/) and the [Quasar Framework](http://quasar-framework.org/)
|
||||
* Logo magic wand icon by David from the Noun Project
|
||||
|
||||
## Build Setup
|
||||
|
||||
``` bash
|
||||
# install dependencies
|
||||
$ npm install
|
||||
|
||||
# serve with hot reload at localhost:8080
|
||||
$ npm run dev_web
|
||||
|
||||
# build for production with minification
|
||||
$ npm run build_web # or build_app
|
||||
|
||||
# build cordova (android, iOS potentially in future) release
|
||||
$ npm run build_app_cordova
|
||||
# sign apk with android studio or jarsigner
|
||||
# install on device
|
||||
$ adp install cordova/platforms/android/build/apk/<BUILT-FILE.apk>
|
||||
|
||||
# lint code
|
||||
$ npm run lint
|
||||
```
|
||||
|
|
BIN
assets/.DS_Store
vendored
231
assets/app.css
|
@ -1,231 +0,0 @@
|
|||
body {
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
[data-action=print],
|
||||
.printonly {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mdl-mini-footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
padding: .5em 1em .75em 1em
|
||||
}
|
||||
|
||||
.do-nothing {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.mdl-layout-title i {
|
||||
position: relative;
|
||||
bottom: -.125em;
|
||||
}
|
||||
|
||||
#empty {
|
||||
padding-bottom: 100%;
|
||||
text-align: center;
|
||||
background: url('wand.svg') no-repeat top center;
|
||||
}
|
||||
|
||||
.mdl-layout__header .mdl-button .mdl-badge[data-badge] {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.mdl-layout__header .mdl-button .mdl-badge[data-badge]::after {
|
||||
left: -1em;
|
||||
right: auto;
|
||||
}
|
||||
|
||||
.mdl-navigation .mdl-textfield__label i {
|
||||
vertical-align: top;
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
.mdl-navigation .mdl-textfield__input {
|
||||
box-sizing: border-box;
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
.mdl-navigation .mdl-textfield__label {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
padding: 0 1em;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.left {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.page-content {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.page-content .mdl-grid {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.page-content .mdl-cell {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
[data-template=spell-details] {
|
||||
transition: margin-top 500ms ease-out;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
|
||||
#description {
|
||||
margin: 0;
|
||||
max-height: 13em;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#description br:last-of-type {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#description p:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#copy {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#details {
|
||||
columns: 2;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
#details strong {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.mdl-layout__header [data-action-details=""] {
|
||||
display: none;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
height: 4rem;
|
||||
width: 4rem;
|
||||
}
|
||||
|
||||
.mdl-layout__header [data-action-details=""] i {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
left: 1rem;
|
||||
}
|
||||
|
||||
[data-template=spell-details] [data-action-details=""] {
|
||||
position: absolute;
|
||||
top: .5rem;
|
||||
right: .5rem;
|
||||
}
|
||||
|
||||
@media (max-width: 840px) {
|
||||
.hide-phone {
|
||||
display: none;
|
||||
}
|
||||
|
||||
[data-template=spell-details] {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
#spell-list-container,
|
||||
[data-template=spell-details] {
|
||||
transition: left 250ms;
|
||||
}
|
||||
|
||||
#spell-list-container {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
body.details #spell-list-container {
|
||||
left: -95%;
|
||||
}
|
||||
|
||||
body.details #spell-list-container::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: black;
|
||||
opacity: .25;
|
||||
}
|
||||
|
||||
[data-template=spell-details] {
|
||||
position: fixed;
|
||||
width: 95%;
|
||||
left: 100%;
|
||||
overflow: auto;
|
||||
max-height: calc(100% - 56px)
|
||||
}
|
||||
|
||||
body.details [data-template=spell-details] {
|
||||
left: 5%;
|
||||
}
|
||||
|
||||
body.details .mdl-layout__header [data-action-details=""] {
|
||||
display: block;
|
||||
}
|
||||
|
||||
body.details .mdl-layout__header .mdl-layout__drawer-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body.details [data-template=spell-details] [data-action-details=""] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
[data-action-details] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
[data-action-sort],
|
||||
[data-template=class-list] label,
|
||||
.classes,
|
||||
.spell-level,
|
||||
.spell-name,
|
||||
.spell-school {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
[data-action-sort] {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
[data-action-sort]:hover {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
[data-action-sort] i.material-icons.mdl-list__item-icon {
|
||||
position: relative;
|
||||
bottom: -.25em;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
#share-url {
|
||||
padding-left: 2em;
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
@media print {
|
||||
body {
|
||||
background: white;
|
||||
font-size: 11pt;
|
||||
box-sizing: border-box;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
body > .printonly {
|
||||
display: block;
|
||||
}
|
||||
|
||||
body > :not(.printonly) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
th {
|
||||
white-space: nowrap;
|
||||
padding: 1em 1em 1em 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.spell-description p {
|
||||
font-size: 8pt;
|
||||
line-height: 10pt;
|
||||
margin: .75em 0;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.spell-description br {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#details {
|
||||
font-size: 8pt;
|
||||
margin: 0;
|
||||
columns: 3;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
}
|
123
assets/wand.svg
|
@ -1,123 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1"
|
||||
id="svg7404" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="232 -592.3 824.9 1155"
|
||||
style="enable-background:new 232 -592.3 824.9 1155;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#EDF9F7;}
|
||||
.st1{fill:#7BCBBF;}
|
||||
.st2{fill:#9BD8D0;}
|
||||
.st3{fill:#CBE9E4;}
|
||||
.st4{fill:#6EC3BB;}
|
||||
.st5{fill:#FFFFFF;}
|
||||
.st6{fill:#EED7B2;}
|
||||
.st7{fill:#DAC4BF;}
|
||||
.st8{fill:#CCDBB9;}
|
||||
.st9{fill:#DBEFBE;}
|
||||
.st10{fill:#D4E6BC;}
|
||||
.st11{fill:#F9FBF5;}
|
||||
.st12{fill:#D6C2BE;}
|
||||
.st13{fill:#E0E4DD;}
|
||||
.st14{fill:#B3D3C8;}
|
||||
.st15{fill:#9FCABF;}
|
||||
.st16{fill:#D3DBD9;}
|
||||
.st17{fill:#A6C9C4;}
|
||||
.st18{fill:#BCD1CD;}
|
||||
.st19{fill:#92C0BB;}
|
||||
.st20{fill:#DFEAE9;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M544.6-229L544.6-229L544.6-229 M501.7-241.2L501.7-241.2l-19.1,22.8l31.1,13c0.1-1.1,0.4-2.1,1.1-2.9
|
||||
c1-1.2,2.4-1.8,4-1.8c1.4,0,2.9,0.5,4.1,1.5c0.9,0.7,1.5,1.6,1.9,2.6l19.4-23.3L501.7-241.2"/>
|
||||
<polyline class="st1" points="474.8,-209.1 447.4,-176.2 466.8,-136.4 489.6,-163.7 465.5,-197.8 474.9,-209.1 474.8,-209.1 "/>
|
||||
<path class="st2" d="M544.5-229.4l-0.2,0.2l-19.4,23.3c0.7,1.8,0.5,3.9-0.7,5.4c-0.3,0.4-0.7,0.7-1.1,0.9l21.1,32.6l19.3-23.1
|
||||
L544.6-229l0,0L544.5-229.4"/>
|
||||
<polyline class="st3" points="489.9,-163.8 489.7,-163.6 489.6,-163.7 466.8,-136.4 466.7,-136.2 508.6,-124.3 508.6,-124.3
|
||||
527,-146.3 489.9,-163.8 "/>
|
||||
<path class="st2" d="M482.6-218.4l-7.8,9.3l-9.4,11.3l24.2,34.1l0.1,0.1l0.2-0.2l-0.2-0.1l29.3-35c-1-0.2-2-0.7-2.9-1.4
|
||||
c-1.6-1.3-2.4-3.3-2.3-5.1L482.6-218.4L482.6-218.4"/>
|
||||
<path class="st4" d="M523.1-199.6c-0.8,0.6-1.9,0.8-2.9,0.8c-0.4,0-0.8,0-1.2-0.1l-29.3,35l0.2,0.1l37.1,17.5l8.2-9.7l9.1-10.9
|
||||
L523.1-199.6"/>
|
||||
<path class="st5" d="M518.9-210c-1.5,0-3,0.6-4,1.8c-0.7,0.8-1.1,1.9-1.1,2.9c-0.1,1.8,0.7,3.7,2.3,5.1c0.9,0.7,1.9,1.2,2.9,1.4
|
||||
c0.4,0.1,0.8,0.1,1.2,0.1c1,0,2.1-0.3,2.9-0.8c0.4-0.3,0.7-0.6,1.1-0.9c1.2-1.5,1.4-3.5,0.7-5.4c-0.4-1-1-1.9-1.9-2.6
|
||||
C521.7-209.5,520.3-210,518.9-210"/>
|
||||
<path class="st6" d="M874.4,91.9c-2,9.3-4.7,18-7.1,25.7l133.5,111.7l-2.3,2.7l0,0l13.2-15.9L874.4,91.9 M577.3-176.6l2.2,53.4
|
||||
L624-86.1c4.1-1.9,9-2.9,14.2-2.9c3.2,0,6.5,0.4,9.6,1.2c13,3.4,19.8,12.9,15,21.2c-0.3,0.5-0.6,1-1,1.5c-0.7,2.4-1.5,5.5-2.1,8.9
|
||||
L839.8,94.6c0-0.9,0-1.9-0.1-2.8l0,0c0,0,0,0,0,0c0.3-13.5,2-27.5-1.3-32.3L577.3-176.6"/>
|
||||
<path class="st7" d="M867.3,117.6c-2.8,8.9-5.1,16.4-5.1,21.9c-0.1,3.7,0.4,6.8,1.2,9.5L987.6,245l10.9-13.1l2.3-2.7L867.3,117.6
|
||||
M659.7-56.2c-3,16.4-2.7,42.8,21.9,63.4c2.2,1.8,4.6,3.4,7,4.5l67.1,52.1l0,0c-0.5,0.2-1,0.4-1.5,0.7l87.3,67.6
|
||||
c-0.9-10.2-1.3-22.6-1.7-37.4L659.7-56.2 M579.6-123.3l0.1,2.5l-55.1,7.4L614-44.1c-0.6-5.7-0.7-10.8-0.7-15
|
||||
c0-8.5,0.7-13.6,0.7-13.6s0-0.1,0.1-0.3c-0.1-2,0.4-4,1.5-6c1.7-3,4.7-5.4,8.4-7.1L579.6-123.3"/>
|
||||
<path class="st8" d="M839.8,91.7L839.8,91.7c0,1,0,1.9,0.1,2.8c0.4,14.8,0.8,27.2,1.7,37.4c1.9,21.5,6,33.3,17.1,36.7
|
||||
c3.4,1.1,6.4,1.5,9,1.5c4.4,0,7.6-1.2,9.9-2.6c-2.3,1.4-5.5,2.6-9.9,2.6c-2.6,0-5.6-0.4-9-1.5C841.9,163.6,841,139.4,839.8,91.7
|
||||
M806.6-3.9c-10.8,0-21.9,2-32.8,4.7l23.9,21.6c1,0,2.1-0.1,3.1-0.1c21.4,0,38,9.1,49.3,22.5c12.8,15.3,3.1,56.1,3.9,79
|
||||
c0.9,22.4-5.4,36.8,27.2,40.6c0.4-0.5,0.6-0.8,0.6-0.8s-14.1-0.8-18.4-14.8c-0.8-2.7-1.3-5.8-1.2-9.5c0.1-5.4,2.4-13,5.1-21.9
|
||||
c2.4-7.7,5.1-16.4,7.1-25.7c5.4-25.7,5-55.8-24.9-80.8C836.3,0,821.7-3.9,806.6-3.9 M613.2-59.1c0,4.2,0.2,9.3,0.7,15
|
||||
c2.5,25.9,12.6,64.3,47.8,93.6c20.4,17,39.5,23,56.7,23c13.2,0,25.2-3.5,35.8-8.1c0.5-0.2,1-0.4,1.5-0.7l0,0
|
||||
c-10.9,4.9-23.5,8.7-37.2,8.7c-17.2,0-36.3-5.9-56.7-23C618.9,13.7,613.2-35.6,613.2-59.1 M661.9-65.1c-4.1,5.4-12.5,8.6-21.6,8.6
|
||||
c-1.7,0-3.4-0.1-5.1-0.3c-0.8,25.1,5.1,61.8,29.9,82.4c10.6,8.8,25.2,11.8,40.9,11.8c4.8,0,9.7-0.3,14.7-0.8l35,27.1l-67.1-52.1
|
||||
c-2.3-1.1-4.7-2.6-7-4.5c-24.6-20.5-24.9-46.9-21.9-63.4C660.3-59.7,661.1-62.7,661.9-65.1"/>
|
||||
<path class="st9" d="M800.8,22.4c-1,0-2.1,0-3.1,0.1c0,0-0.1,0-0.1,0l40,36c0.3,0.3,0.6,0.6,0.8,0.9c3.3,4.9,1.6,18.9,1.3,32.3l0,0
|
||||
c1.2,47.7,2.2,71.8,18.9,77c3.4,1.1,6.4,1.5,9,1.5c4.4,0,7.6-1.2,9.9-2.6c1.8-1.1,3-2.3,3.7-3.1c0,0,0,0,0,0
|
||||
c-32.6-3.8-26.3-18.2-27.2-40.6c-0.8-22.9,8.9-63.7-3.9-79C838.8,31.5,822.2,22.4,800.8,22.4 M614.1-73c-0.1,0.2-0.1,0.3-0.1,0.3
|
||||
s-0.7,5.1-0.7,13.6c0,23.6,5.7,72.8,48.5,108.6c20.4,17,39.5,23,56.7,23c13.8,0,26.3-3.8,37.2-8.7l0,0l-35-27.1
|
||||
c-4.9,0.5-9.9,0.8-14.7,0.8c-15.7,0-30.3-3.1-40.9-11.8c-24.8-20.7-30.8-57.4-29.9-82.4c-1.5-0.2-3-0.5-4.5-0.9
|
||||
C620.6-60.3,614.3-66.5,614.1-73"/>
|
||||
<path class="st10" d="M638.2-59.6c-2,0-4.1-0.7-5.9-2.2c-3.7-3.1-4.4-8.2-1.7-11.4c1.4-1.7,3.5-2.5,5.7-2.5c2,0,4.1,0.7,5.9,2.2
|
||||
c3.7,3.1,4.4,8.2,1.7,11.4C642.5-60.5,640.4-59.6,638.2-59.6 M638.2-89c-5.2,0-10.1,1-14.2,2.9c-3.7,1.7-6.7,4.2-8.4,7.1
|
||||
c-1.1,2-1.6,4-1.5,6c0.3,6.5,6.6,12.7,16.5,15.3c1.5,0.4,3,0.7,4.5,0.9c1.7,0.2,3.4,0.3,5.1,0.3c9.1,0,17.5-3.2,21.6-8.6
|
||||
c0.4-0.5,0.7-1,1-1.5c4.7-8.3-2-17.8-15-21.2C644.6-88.6,641.4-89,638.2-89"/>
|
||||
<path class="st11" d="M636.3-75.8c-2.2,0-4.3,0.9-5.7,2.5c-2.7,3.3-2,8.4,1.7,11.4c1.8,1.5,3.9,2.2,5.9,2.2c2.2,0,4.3-0.9,5.7-2.5
|
||||
c2.7-3.3,2-8.4-1.7-11.4C640.5-75.1,638.4-75.8,636.3-75.8"/>
|
||||
<polyline class="st12" points="577.3,-178.5 549.7,-145.7 522.2,-113.1 524.5,-113.4 579.7,-120.8 579.6,-123.3 577.3,-176.6
|
||||
577.3,-178.5 "/>
|
||||
<polyline class="st13" points="563.6,-190 563.5,-190 564.1,-188.9 537.9,-157.6 550.6,-147 577.1,-178.7 563.6,-190 "/>
|
||||
<polyline class="st14" points="563.5,-190 544.2,-166.9 544.4,-166.7 537.2,-158.2 537.9,-157.6 564.1,-188.9 563.5,-190 "/>
|
||||
<polyline class="st15" points="544.2,-166.9 535.1,-156 537,-158.3 537.2,-158.2 544.4,-166.7 544.2,-166.9 "/>
|
||||
<polyline class="st16" points="537.9,-157.6 536.7,-156.1 536.7,-156.1 509.7,-124 508.6,-124.3 522.1,-113 550.6,-147
|
||||
537.9,-157.6 "/>
|
||||
<polyline class="st17" points="537.2,-158.2 536.6,-157.4 537.3,-156.8 536.7,-156.1 536.7,-156.1 537.9,-157.6 537.2,-158.2 "/>
|
||||
<polyline class="st18" points="536.6,-157.4 527.2,-146.2 527,-146.3 508.6,-124.3 508.6,-124.3 509.7,-124 536.7,-156.1
|
||||
537.3,-156.8 536.6,-157.4 "/>
|
||||
<polyline class="st19" points="537,-158.3 535.1,-156 527,-146.3 527.2,-146.2 536.6,-157.4 537.2,-158.2 537,-158.3 "/>
|
||||
<polygon class="st20" points="362.8,-106.5 366.8,-137.1 394.1,-151.2 366.3,-164.3 361.4,-194.7 340.3,-172.4 309.9,-177.1
|
||||
324.6,-150 310.7,-122.6 341,-128.3 "/>
|
||||
<polygon class="st20" points="394.7,-386.8 409.4,-403.2 431.2,-400.3 420.2,-419.4 429.7,-439.2 408.2,-434.6 392.3,-449.7
|
||||
390,-427.9 370.7,-417.4 390.7,-408.5 "/>
|
||||
<polygon class="st20" points="457,20.4 461.6,-14.7 493.1,-30.9 461.1,-46.1 455.4,-81.1 431,-55.3 396,-60.7 413,-29.6 397,2
|
||||
431.8,-4.5 "/>
|
||||
<polygon class="st20" points="634.6,-418.3 636.7,-434.1 650.9,-441.4 636.5,-448.2 633.9,-463.9 623,-452.4 607.2,-454.8
|
||||
614.9,-440.8 607.7,-426.6 623.3,-429.5 "/>
|
||||
<polygon class="st20" points="803.5,-10.6 800.3,-33.9 817.8,-49.6 794.6,-53.9 785,-75.3 773.8,-54.7 750.5,-52.1 766.7,-35.1
|
||||
761.9,-12.1 783.1,-22.3 "/>
|
||||
<polygon class="st20" points="608.2,41.7 610.5,23.5 626.9,15.1 610.3,7.2 607.4,-10.9 594.7,2.5 576.6,-0.4 585.4,15.8
|
||||
577.1,32.1 595.1,28.8 "/>
|
||||
<polygon class="st20" points="267.8,88.3 269.8,72.5 284,65.2 269.6,58.4 267,42.6 256.1,54.2 240.4,51.8 248,65.8 240.8,80
|
||||
256.5,77.1 "/>
|
||||
<polygon class="st20" points="489.7,348 497.5,334.2 513.4,332.8 502.6,321 506.2,305.5 491.7,312.1 478,303.9 479.8,319.7
|
||||
467.8,330.2 483.4,333.4 "/>
|
||||
<polygon class="st20" points="989.4,-441.9 997.3,-455.7 1013.1,-457.1 1002.4,-468.9 1005.9,-484.4 991.4,-477.8 977.8,-486
|
||||
979.6,-470.2 967.5,-459.7 983.2,-456.5 "/>
|
||||
<polygon class="st20" points="934.4,137.9 939.1,126.4 951.4,123.8 941.9,115.7 943.1,103.3 932.5,109.8 921.1,104.8 924,116.9
|
||||
915.7,126.2 928.2,127.1 "/>
|
||||
<polygon class="st20" points="326.5,108.6 324.9,96.3 334.1,87.9 321.8,85.6 316.8,74.3 310.8,85.2 298.5,86.6 307.1,95.6
|
||||
304.5,107.8 315.7,102.4 "/>
|
||||
<polygon class="st20" points="530.6,104.7 532,93.7 541.9,88.7 531.9,83.9 530.1,73 522.5,81 511.6,79.3 516.9,89 511.9,98.9
|
||||
522.7,96.9 "/>
|
||||
<polygon class="st20" points="742.1,-272 745.1,-282.7 755.5,-286.3 746.3,-292.4 746.1,-303.5 737.4,-296.6 726.8,-299.8
|
||||
730.7,-289.5 724.3,-280.4 735.4,-280.9 "/>
|
||||
<polygon class="st20" points="939.7,-208.2 950.1,-211.9 959.1,-205.5 958.7,-216.6 967.5,-223.3 956.9,-226.3 953.4,-236.7
|
||||
947.2,-227.6 936.1,-227.4 943,-218.7 "/>
|
||||
<polygon class="st20" points="825.7,-570.5 829.8,-574.5 835.4,-573.5 832.8,-578.6 835.5,-583.7 829.9,-582.8 825.9,-587
|
||||
825,-581.3 819.8,-578.8 824.9,-576.2 "/>
|
||||
<polygon class="st20" points="862.9,475.8 867,471.8 872.6,472.8 870,467.7 872.7,462.6 867.1,463.5 863.1,459.3 862.2,465
|
||||
857,467.5 862.1,470.1 "/>
|
||||
<polygon class="st20" points="503.3,-554 507.4,-558 513.1,-557 510.5,-562.1 513.2,-567.2 507.5,-566.3 503.6,-570.5
|
||||
502.7,-564.8 497.4,-562.3 502.6,-559.7 "/>
|
||||
<polygon class="st20" points="706.5,302 710.6,297.9 716.3,299 713.6,293.8 716.4,288.7 710.7,289.6 706.7,285.5 705.8,291.1
|
||||
700.6,293.6 705.7,296.2 "/>
|
||||
<polygon class="st20" points="328,488.5 333.8,487.9 337.6,492.2 338.7,486.5 344,484.2 339,481.4 338.4,475.7 334.2,479.6
|
||||
328.6,478.3 331,483.6 "/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 9.2 KiB |
91
build/css-utils.js
Normal file
|
@ -0,0 +1,91 @@
|
|||
var
|
||||
ExtractTextPlugin = require('extract-text-webpack-plugin'),
|
||||
autoprefixer = require('autoprefixer'),
|
||||
purify = require('purify-css'),
|
||||
glob = require('glob'),
|
||||
path = require('path'),
|
||||
fs = require('fs')
|
||||
|
||||
module.exports.postcss = [autoprefixer()]
|
||||
|
||||
module.exports.styleLoaders = function (options) {
|
||||
options = options || {}
|
||||
|
||||
function generateLoaders (loaders) {
|
||||
if (options.postcss) {
|
||||
loaders.splice(1, 0, 'postcss')
|
||||
}
|
||||
|
||||
var sourceLoader = loaders.map(function (loader) {
|
||||
var extraParamChar
|
||||
if (/\?/.test(loader)) {
|
||||
loader = loader.replace(/\?/, '-loader?')
|
||||
extraParamChar = '&'
|
||||
}
|
||||
else {
|
||||
loader = loader + '-loader'
|
||||
extraParamChar = '?'
|
||||
}
|
||||
return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '')
|
||||
}).join('!')
|
||||
|
||||
if (options.extract) {
|
||||
return ExtractTextPlugin.extract({
|
||||
use: sourceLoader,
|
||||
fallback: 'vue-style-loader'
|
||||
})
|
||||
}
|
||||
else {
|
||||
return ['vue-style-loader', sourceLoader].join('!')
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
css: generateLoaders(['css']),
|
||||
less: generateLoaders(['css', 'less']),
|
||||
sass: generateLoaders(['css', 'sass?indentedSyntax']),
|
||||
scss: generateLoaders(['css', 'sass']),
|
||||
styl: generateLoaders(['css', 'stylus']),
|
||||
stylus: generateLoaders(['css', 'stylus'])
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.styleRules = function (options) {
|
||||
var output = []
|
||||
var loaders = exports.styleLoaders(options)
|
||||
for (var extension in loaders) {
|
||||
var loader = loaders[extension]
|
||||
output.push({
|
||||
test: new RegExp('\\.' + extension + '$'),
|
||||
loader: loader
|
||||
})
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
function getSize (size) {
|
||||
return (size / 1024).toFixed(2) + 'kb'
|
||||
}
|
||||
|
||||
module.exports.purify = function(cb) {
|
||||
var css = glob.sync(path.join(__dirname, '../dist/**/*.css'))
|
||||
var js = glob.sync(path.join(__dirname, '../dist/**/*.js'))
|
||||
|
||||
Promise.all(css.map(function (file) {
|
||||
return new Promise(function (resolve) {
|
||||
console.log('\n Purifying ' + path.relative(path.join(__dirname, '../dist'), file).bold + '...')
|
||||
purify(js, [file], {minify: true}, function (purified) {
|
||||
var oldSize = fs.statSync(file).size
|
||||
fs.writeFileSync(file, purified)
|
||||
var newSize = fs.statSync(file).size
|
||||
|
||||
console.log(
|
||||
' * Reduced size by ' + ((1 - newSize / oldSize) * 100).toFixed(2) + '%, from ' +
|
||||
getSize(oldSize) + ' to ' + getSize(newSize) + '.'
|
||||
)
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}))
|
||||
.then(cb)
|
||||
}
|
13
build/env-utils.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
var
|
||||
config = require('../config'),
|
||||
theme = process.argv[2] || config.defaultTheme
|
||||
|
||||
module.exports = {
|
||||
dev: process.env.NODE_ENV === 'development',
|
||||
prod: process.env.NODE_ENV === 'production',
|
||||
|
||||
platform: {
|
||||
theme: theme,
|
||||
cordovaAssets: './cordova/platforms/' + (theme === 'mat' ? 'android' : 'ios') + '/platform_www'
|
||||
}
|
||||
}
|
9
build/hot-reload.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
/* eslint-disable */
|
||||
require('eventsource-polyfill')
|
||||
var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
|
||||
|
||||
hotClient.subscribe(function (event) {
|
||||
if (event.action === 'reload') {
|
||||
window.location.reload()
|
||||
}
|
||||
})
|
53
build/process_spells.js
Normal file
|
@ -0,0 +1,53 @@
|
|||
'use strict'
|
||||
|
||||
const args = require('yargs').argv
|
||||
|
||||
const fs = require('fs')
|
||||
const spells = require('../src/spells_original.json')
|
||||
|
||||
const hashCode = function (str) {
|
||||
let hash = 0, i, chr
|
||||
if (str.length === 0) return hash
|
||||
for (i = 0; i < str.length; i++) {
|
||||
chr = str.charCodeAt(i)
|
||||
hash = ((hash << 5) - hash) + chr
|
||||
hash |= 0
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
console.log('Processing spells...', args.web ? 'for web!' : 'for apps!')
|
||||
|
||||
let spellsWithIDs = spells.map(spell => {
|
||||
spell.id = hashCode(spell.name).toString()
|
||||
return spell
|
||||
})
|
||||
|
||||
let indexedSpells = spellsWithIDs.map(spell => {
|
||||
return {
|
||||
id: spell.id,
|
||||
name: spell.name,
|
||||
classes: spell.classes,
|
||||
level: spell.level.toLowerCase() === 'cantrip' ? 0 : parseInt(spell.level),
|
||||
link: '/spell/' + spell.id,
|
||||
}
|
||||
})
|
||||
|
||||
let dirs = ['dist', 'dist/statics', 'src/tmp']
|
||||
dirs.forEach(dir => {
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir)
|
||||
}
|
||||
})
|
||||
|
||||
fs.writeFileSync('./src/tmp/spells_index.js', `export default ${JSON.stringify(indexedSpells)};`)
|
||||
|
||||
if (args.web) {
|
||||
fs.writeFileSync('./dist/statics/spells.json', JSON.stringify(spellsWithIDs));
|
||||
fs.writeFileSync('./src/tmp/spells.js', `export default []; // Will fetch from web`)
|
||||
}
|
||||
else {
|
||||
fs.writeFileSync('./src/tmp/spells.js', `export default ${JSON.stringify(spellsWithIDs)};`)
|
||||
}
|
||||
|
||||
console.log('Processed spells')
|
50
build/script.build.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
process.env.NODE_ENV = 'production'
|
||||
|
||||
require('colors')
|
||||
|
||||
var
|
||||
shell = require('shelljs'),
|
||||
path = require('path'),
|
||||
env = require('./env-utils'),
|
||||
css = require('./css-utils'),
|
||||
config = require('../config'),
|
||||
webpack = require('webpack'),
|
||||
webpackConfig = require('./webpack.prod.conf'),
|
||||
targetPath = path.join(__dirname, '../dist')
|
||||
|
||||
console.log(' WARNING!'.bold)
|
||||
console.log(' Do NOT use VueRouter\'s "history" mode if')
|
||||
console.log(' building for Cordova or Electron.\n')
|
||||
|
||||
require('./script.clean.js')
|
||||
console.log((' Building Quasar App with "' + env.platform.theme + '" theme...\n').bold)
|
||||
|
||||
shell.mkdir('-p', targetPath)
|
||||
shell.cp('-R', 'src/statics', targetPath)
|
||||
|
||||
function finalize () {
|
||||
console.log((
|
||||
'\n Build complete with "' + env.platform.theme.bold + '" theme in ' +
|
||||
'"/dist"'.bold + ' folder.\n').cyan)
|
||||
|
||||
console.log(' Built files are meant to be served over an HTTP server.'.bold)
|
||||
console.log(' Opening index.html over file:// won\'t work.'.bold)
|
||||
}
|
||||
|
||||
webpack(webpackConfig, function (err, stats) {
|
||||
if (err) throw err
|
||||
process.stdout.write(stats.toString({
|
||||
colors: true,
|
||||
modules: false,
|
||||
children: false,
|
||||
chunks: false,
|
||||
chunkModules: false
|
||||
}) + '\n')
|
||||
|
||||
if (config.build.purifyCSS) {
|
||||
css.purify(finalize)
|
||||
}
|
||||
else {
|
||||
finalize()
|
||||
}
|
||||
})
|
6
build/script.clean.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
var
|
||||
shell = require('shelljs'),
|
||||
path = require('path')
|
||||
|
||||
shell.rm('-rf', path.resolve(__dirname, '../dist ../src/tmp'))
|
||||
console.log(' Cleaned build artifacts.\n')
|
86
build/script.dev.js
Normal file
|
@ -0,0 +1,86 @@
|
|||
process.env.NODE_ENV = 'development'
|
||||
|
||||
require('colors')
|
||||
|
||||
var
|
||||
path = require('path'),
|
||||
express = require('express'),
|
||||
webpack = require('webpack'),
|
||||
env = require('./env-utils'),
|
||||
config = require('../config'),
|
||||
opn = require('opn'),
|
||||
proxyMiddleware = require('http-proxy-middleware'),
|
||||
webpackConfig = require('./webpack.dev.conf'),
|
||||
app = express(),
|
||||
port = process.env.PORT || config.dev.port,
|
||||
uri = 'http://localhost:' + port
|
||||
|
||||
console.log(' Starting dev server with "' + (process.argv[2] || env.platform.theme).bold + '" theme...')
|
||||
console.log(' Will listen at ' + uri.bold)
|
||||
if (config.dev.openBrowser) {
|
||||
console.log(' Browser will open when build is ready.\n')
|
||||
}
|
||||
|
||||
var compiler = webpack(webpackConfig)
|
||||
|
||||
// Define HTTP proxies to your custom API backend
|
||||
// https://github.com/chimurai/http-proxy-middleware
|
||||
var proxyTable = config.dev.proxyTable
|
||||
|
||||
var devMiddleware = require('webpack-dev-middleware')(compiler, {
|
||||
publicPath: webpackConfig.output.publicPath,
|
||||
quiet: true
|
||||
})
|
||||
|
||||
var hotMiddleware = require('webpack-hot-middleware')(compiler, {
|
||||
log: function () {}
|
||||
})
|
||||
|
||||
// force page reload when html-webpack-plugin template changes
|
||||
compiler.plugin('compilation', function (compilation) {
|
||||
compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
|
||||
hotMiddleware.publish({ action: 'reload' })
|
||||
cb()
|
||||
})
|
||||
})
|
||||
|
||||
// proxy requests like API. See /config/index.js -> dev.proxyTable
|
||||
// https://github.com/chimurai/http-proxy-middleware
|
||||
Object.keys(proxyTable).forEach(function (context) {
|
||||
var options = proxyTable[context]
|
||||
if (typeof options === 'string') {
|
||||
options = { target: options }
|
||||
}
|
||||
app.use(proxyMiddleware(context, options))
|
||||
})
|
||||
|
||||
// handle fallback for HTML5 history API
|
||||
app.use(require('connect-history-api-fallback')())
|
||||
|
||||
// serve webpack bundle output
|
||||
app.use(devMiddleware)
|
||||
|
||||
// enable hot-reload and state-preserving
|
||||
// compilation error display
|
||||
app.use(hotMiddleware)
|
||||
|
||||
// serve pure static assets
|
||||
var staticsPath = path.posix.join(webpackConfig.output.publicPath, 'statics/')
|
||||
app.use(staticsPath, express.static('./src/statics'))
|
||||
|
||||
// try to serve Cordova statics for Play App
|
||||
app.use(express.static(env.platform.cordovaAssets))
|
||||
|
||||
module.exports = app.listen(port, function (err) {
|
||||
if (err) {
|
||||
console.log(err)
|
||||
return
|
||||
}
|
||||
|
||||
// open browser if set so in /config/index.js
|
||||
if (config.dev.openBrowser) {
|
||||
devMiddleware.waitUntilValid(function () {
|
||||
opn(uri)
|
||||
})
|
||||
}
|
||||
})
|
115
build/webpack.base.conf.js
Normal file
|
@ -0,0 +1,115 @@
|
|||
var
|
||||
path = require('path'),
|
||||
webpack = require('webpack'),
|
||||
config = require('../config'),
|
||||
cssUtils = require('./css-utils'),
|
||||
env = require('./env-utils'),
|
||||
merge = require('webpack-merge'),
|
||||
projectRoot = path.resolve(__dirname, '../'),
|
||||
ProgressBarPlugin = require('progress-bar-webpack-plugin'),
|
||||
useCssSourceMap =
|
||||
(env.dev && config.dev.cssSourceMap) ||
|
||||
(env.prod && config.build.productionSourceMap)
|
||||
|
||||
function resolve (dir) {
|
||||
return path.join(__dirname, '..', dir)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
app: './src/main.js'
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, '../dist'),
|
||||
publicPath: config[env.prod ? 'build' : 'dev'].publicPath,
|
||||
filename: 'js/[name].js',
|
||||
chunkFilename: 'js/[id].[chunkhash].js'
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.vue', '.json'],
|
||||
modules: [
|
||||
resolve('src'),
|
||||
resolve('node_modules')
|
||||
],
|
||||
alias: config.aliases
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{ // eslint
|
||||
enforce: 'pre',
|
||||
test: /\.(vue|js)$/,
|
||||
loader: 'eslint-loader',
|
||||
include: projectRoot,
|
||||
exclude: /node_modules/,
|
||||
options: {
|
||||
formatter: require('eslint-friendly-formatter')
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel-loader',
|
||||
include: projectRoot,
|
||||
exclude: /node_modules/
|
||||
},
|
||||
{
|
||||
test: /\.vue$/,
|
||||
loader: 'vue-loader',
|
||||
options: {
|
||||
postcss: cssUtils.postcss,
|
||||
loaders: merge({js: 'babel-loader'}, cssUtils.styleLoaders({
|
||||
sourceMap: useCssSourceMap,
|
||||
extract: env.prod
|
||||
}))
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.json$/,
|
||||
loader: 'json-loader'
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: 'img/[name].[hash:7].[ext]'
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: 'fonts/[name].[hash:7].[ext]'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
/*
|
||||
Take note!
|
||||
Uncomment if you wish to load only one Moment locale:
|
||||
|
||||
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /en/),
|
||||
*/
|
||||
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': config[env.prod ? 'build' : 'dev'].env,
|
||||
'DEV': env.dev,
|
||||
'PROD': env.prod,
|
||||
'__THEME': '"' + env.platform.theme + '"'
|
||||
}),
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
minimize: env.prod,
|
||||
options: {
|
||||
context: path.resolve(__dirname, '../src'),
|
||||
postcss: cssUtils.postcss
|
||||
}
|
||||
}),
|
||||
new ProgressBarPlugin({
|
||||
format: config.progressFormat
|
||||
})
|
||||
],
|
||||
performance: {
|
||||
hints: false
|
||||
}
|
||||
}
|
43
build/webpack.dev.conf.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
var
|
||||
config = require('../config'),
|
||||
webpack = require('webpack'),
|
||||
merge = require('webpack-merge'),
|
||||
cssUtils = require('./css-utils'),
|
||||
baseWebpackConfig = require('./webpack.base.conf'),
|
||||
HtmlWebpackPlugin = require('html-webpack-plugin'),
|
||||
FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
||||
|
||||
// add hot-reload related code to entry chunks
|
||||
Object.keys(baseWebpackConfig.entry).forEach(function (name) {
|
||||
baseWebpackConfig.entry[name] = ['./build/hot-reload'].concat(baseWebpackConfig.entry[name])
|
||||
})
|
||||
|
||||
module.exports = merge(baseWebpackConfig, {
|
||||
// eval-source-map is faster for development
|
||||
devtool: '#cheap-module-eval-source-map',
|
||||
devServer: {
|
||||
historyApiFallback: true,
|
||||
noInfo: true
|
||||
},
|
||||
module: {
|
||||
rules: cssUtils.styleRules({
|
||||
sourceMap: config.dev.cssSourceMap,
|
||||
postcss: true
|
||||
})
|
||||
},
|
||||
plugins: [
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.NoEmitOnErrorsPlugin(),
|
||||
new HtmlWebpackPlugin({
|
||||
filename: 'index.html',
|
||||
template: 'src/index.html',
|
||||
inject: true
|
||||
}),
|
||||
new FriendlyErrorsPlugin({
|
||||
clearConsole: config.dev.clearConsoleOnRebuild
|
||||
})
|
||||
],
|
||||
performance: {
|
||||
hints: false
|
||||
}
|
||||
})
|
75
build/webpack.prod.conf.js
Normal file
|
@ -0,0 +1,75 @@
|
|||
var
|
||||
path = require('path'),
|
||||
config = require('../config'),
|
||||
cssUtils = require('./css-utils'),
|
||||
webpack = require('webpack'),
|
||||
merge = require('webpack-merge'),
|
||||
baseWebpackConfig = require('./webpack.base.conf'),
|
||||
ExtractTextPlugin = require('extract-text-webpack-plugin'),
|
||||
HtmlWebpackPlugin = require('html-webpack-plugin'),
|
||||
OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
|
||||
|
||||
module.exports = merge(baseWebpackConfig, {
|
||||
module: {
|
||||
rules: cssUtils.styleRules({
|
||||
sourceMap: config.build.productionSourceMap,
|
||||
extract: true,
|
||||
postcss: true
|
||||
})
|
||||
},
|
||||
devtool: config.build.productionSourceMap ? '#source-map' : false,
|
||||
plugins: [
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
sourceMap: config.build.productionSourceMap,
|
||||
minimize: true,
|
||||
compress: {
|
||||
warnings: false
|
||||
}
|
||||
}),
|
||||
// Compress extracted CSS. We are using this plugin so that possible
|
||||
// duplicated CSS from different components can be deduped.
|
||||
new OptimizeCSSPlugin({
|
||||
cssProcessorOptions: {
|
||||
safe: true
|
||||
}
|
||||
}),
|
||||
// extract css into its own file
|
||||
new ExtractTextPlugin({
|
||||
filename: '[name].[contenthash].css'
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
filename: config.build.index,
|
||||
template: 'src/index.html',
|
||||
inject: true,
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeAttributeQuotes: true
|
||||
// more options:
|
||||
// https://github.com/kangax/html-minifier#options-quick-reference
|
||||
},
|
||||
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
|
||||
chunksSortMode: 'dependency'
|
||||
}),
|
||||
// split vendor js into its own file
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
name: 'vendor',
|
||||
minChunks: function (module, count) {
|
||||
// any required modules inside node_modules are extracted to vendor
|
||||
return (
|
||||
module.resource &&
|
||||
/\.js$/.test(module.resource) &&
|
||||
module.resource.indexOf(
|
||||
path.join(__dirname, '../node_modules')
|
||||
) === 0
|
||||
)
|
||||
}
|
||||
}),
|
||||
// extract webpack runtime and module manifest to its own file in order to
|
||||
// prevent vendor hash from being updated whenever app bundle is updated
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
name: 'manifest',
|
||||
chunks: ['vendor']
|
||||
})
|
||||
]
|
||||
})
|
6
config/dev.env.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
var merge = require('webpack-merge')
|
||||
var prodEnv = require('./prod.env')
|
||||
|
||||
module.exports = merge(prodEnv, {
|
||||
NODE_ENV: '"development"'
|
||||
})
|
64
config/index.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
var path = require('path')
|
||||
|
||||
module.exports = {
|
||||
// Webpack aliases
|
||||
aliases: {
|
||||
quasar: path.resolve(__dirname, '../node_modules/quasar-framework/'),
|
||||
src: path.resolve(__dirname, '../src'),
|
||||
assets: path.resolve(__dirname, '../src/assets'),
|
||||
components: path.resolve(__dirname, '../src/components')
|
||||
},
|
||||
|
||||
// Progress Bar Webpack plugin format
|
||||
// https://github.com/clessg/progress-bar-webpack-plugin#options
|
||||
progressFormat: ' [:bar] ' + ':percent'.bold + ' (:msg)',
|
||||
|
||||
// Default theme to build with ('ios' or 'mat')
|
||||
defaultTheme: 'mat',
|
||||
|
||||
build: {
|
||||
env: require('./prod.env'),
|
||||
index: path.resolve(__dirname, '../dist/index.html'),
|
||||
publicPath: '',
|
||||
productionSourceMap: false,
|
||||
|
||||
// Remove unused CSS
|
||||
// Disable it if it has side-effects for your specific app
|
||||
purifyCSS: true
|
||||
},
|
||||
dev: {
|
||||
env: require('./dev.env'),
|
||||
cssSourceMap: true,
|
||||
// auto open browser or not
|
||||
openBrowser: true,
|
||||
publicPath: '/',
|
||||
port: 8080,
|
||||
|
||||
// If for example you are using Quasar Play
|
||||
// to generate a QR code then on each dev (re)compilation
|
||||
// you need to avoid clearing out the console, so set this
|
||||
// to "false", otherwise you can set it to "true" to always
|
||||
// have only the messages regarding your last (re)compilation.
|
||||
clearConsoleOnRebuild: false,
|
||||
|
||||
// Proxy your API if using any.
|
||||
// Also see /build/script.dev.js and search for "proxy api requests"
|
||||
// https://github.com/chimurai/http-proxy-middleware
|
||||
proxyTable: {}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* proxyTable example:
|
||||
*
|
||||
proxyTable: {
|
||||
// proxy all requests starting with /api
|
||||
'/api': {
|
||||
target: 'https://some.address.com/api',
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
'^/api': ''
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
3
config/prod.env.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
module.exports = {
|
||||
NODE_ENV: '"production"'
|
||||
}
|
22
cordova/.idea/compiler.xml
generated
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<resourceExtensions />
|
||||
<wildcardResourcePatterns>
|
||||
<entry name="!?*.java" />
|
||||
<entry name="!?*.form" />
|
||||
<entry name="!?*.class" />
|
||||
<entry name="!?*.groovy" />
|
||||
<entry name="!?*.scala" />
|
||||
<entry name="!?*.flex" />
|
||||
<entry name="!?*.kt" />
|
||||
<entry name="!?*.clj" />
|
||||
<entry name="!?*.aj" />
|
||||
</wildcardResourcePatterns>
|
||||
<annotationProcessing>
|
||||
<profile default="true" name="Default" enabled="false">
|
||||
<processorPath useClasspath="true" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
</project>
|
3
cordova/.idea/copyright/profiles_settings.xml
generated
Normal file
|
@ -0,0 +1,3 @@
|
|||
<component name="CopyrightManager">
|
||||
<settings default="" />
|
||||
</component>
|
24
cordova/.idea/cordova.iml
generated
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="android" name="Android">
|
||||
<configuration>
|
||||
<option name="GEN_FOLDER_RELATIVE_PATH_APT" value="/../gen" />
|
||||
<option name="GEN_FOLDER_RELATIVE_PATH_AIDL" value="/../gen" />
|
||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/../../cordova/AndroidManifest.xml" />
|
||||
<option name="RES_FOLDER_RELATIVE_PATH" value="/../../cordova/res" />
|
||||
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/../../cordova/assets" />
|
||||
<option name="LIBS_FOLDER_RELATIVE_PATH" value="/../../cordova/libs" />
|
||||
<option name="PROGUARD_LOGS_FOLDER_RELATIVE_PATH" value="/../../cordova/proguard_logs" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" generated="true" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Android API 25 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
14
cordova/.idea/misc.xml
generated
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
|
||||
<OptionsSetting value="true" id="Add" />
|
||||
<OptionsSetting value="true" id="Remove" />
|
||||
<OptionsSetting value="true" id="Checkout" />
|
||||
<OptionsSetting value="true" id="Update" />
|
||||
<OptionsSetting value="true" id="Status" />
|
||||
<OptionsSetting value="true" id="Edit" />
|
||||
<ConfirmationsSetting value="0" id="Add" />
|
||||
<ConfirmationsSetting value="0" id="Remove" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_3" default="false" assert-keyword="false" jdk-15="false" />
|
||||
</project>
|
8
cordova/.idea/modules.xml
generated
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/cordova.iml" filepath="$PROJECT_DIR$/.idea/cordova.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
291
cordova/.idea/workspace.xml
generated
Normal file
|
@ -0,0 +1,291 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="c5c4ced8-75d2-4b8c-a2ac-45d7a9743afa" name="Default" comment="" />
|
||||
<ignored path="cordova.iws" />
|
||||
<ignored path=".idea/workspace.xml" />
|
||||
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||
<option name="TRACKING_ENABLED" value="true" />
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="CreatePatchCommitExecutor">
|
||||
<option name="PATCH_PATH" value="" />
|
||||
</component>
|
||||
<component name="ExecutionTargetManager" SELECTED_TARGET="default_target" />
|
||||
<component name="FavoritesManager">
|
||||
<favorites_list name="cordova" />
|
||||
</component>
|
||||
<component name="GenerateSignedApkSettings">
|
||||
<option name="KEY_STORE_PATH" value="$USER_HOME$/android/keystore/sharpshark28-keystore.jks" />
|
||||
<option name="KEY_ALIAS" value="key0" />
|
||||
</component>
|
||||
<component name="GradleLocalSettings">
|
||||
<option name="externalProjectsViewState">
|
||||
<projects_view />
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectFrameBounds">
|
||||
<option name="y" value="23" />
|
||||
<option name="width" value="1440" />
|
||||
<option name="height" value="873" />
|
||||
</component>
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
|
||||
<OptionsSetting value="true" id="Add" />
|
||||
<OptionsSetting value="true" id="Remove" />
|
||||
<OptionsSetting value="true" id="Checkout" />
|
||||
<OptionsSetting value="true" id="Update" />
|
||||
<OptionsSetting value="true" id="Status" />
|
||||
<OptionsSetting value="true" id="Edit" />
|
||||
<ConfirmationsSetting value="0" id="Add" />
|
||||
<ConfirmationsSetting value="0" id="Remove" />
|
||||
</component>
|
||||
<component name="ProjectView">
|
||||
<navigator currentView="AndroidView" proportions="" version="1">
|
||||
<flattenPackages />
|
||||
<showMembers />
|
||||
<showModules />
|
||||
<showLibraryContents />
|
||||
<hideEmptyPackages />
|
||||
<abbreviatePackageNames />
|
||||
<autoscrollToSource />
|
||||
<autoscrollFromSource />
|
||||
<sortByType />
|
||||
<manualOrder />
|
||||
<foldersAlwaysOnTop value="true" />
|
||||
</navigator>
|
||||
<panes>
|
||||
<pane id="PackagesPane" />
|
||||
<pane id="Scope" />
|
||||
<pane id="AndroidView">
|
||||
<subPane>
|
||||
<PATH>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="cordova" />
|
||||
<option name="myItemType" value="com.android.tools.idea.navigator.nodes.AndroidViewProjectNode" />
|
||||
</PATH_ELEMENT>
|
||||
</PATH>
|
||||
</subPane>
|
||||
</pane>
|
||||
<pane id="ProjectPane" />
|
||||
<pane id="Scratches" />
|
||||
</panes>
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="android.sdk.path" value="$USER_HOME$/Library/Android/sdk" />
|
||||
<property name="settings.editor.selected.configurable" value="android.sdk-updates" />
|
||||
<property name="settings.editor.splitter.proportion" value="0.2" />
|
||||
<property name="last_opened_file_path" value="$PROJECT_DIR$/platforms/android/build/outputs/apk/android-release-unsigned.apk" />
|
||||
<property name="ExportedModule" value="cordova" />
|
||||
<property name="ExportedApkPath" value="$PROJECT_DIR$/cordova.apk" />
|
||||
<property name="AndroidRunProguardForReleaseBuild" value="false" />
|
||||
<property name="project.structure.last.edited" value="Modules" />
|
||||
<property name="project.structure.proportion" value="0.0" />
|
||||
<property name="project.structure.side.proportion" value="0.0" />
|
||||
</component>
|
||||
<component name="RunManager">
|
||||
<configuration default="true" type="Application" factoryName="Application">
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<option name="MAIN_CLASS_NAME" />
|
||||
<option name="VM_PARAMETERS" />
|
||||
<option name="PROGRAM_PARAMETERS" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
<option name="ENABLE_SWING_INSPECTOR" value="false" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<module name="" />
|
||||
<envs />
|
||||
<method />
|
||||
</configuration>
|
||||
<configuration default="true" type="Remote" factoryName="Remote">
|
||||
<option name="USE_SOCKET_TRANSPORT" value="true" />
|
||||
<option name="SERVER_MODE" value="false" />
|
||||
<option name="SHMEM_ADDRESS" value="javadebug" />
|
||||
<option name="HOST" value="localhost" />
|
||||
<option name="PORT" value="5005" />
|
||||
<method />
|
||||
</configuration>
|
||||
<configuration default="true" type="TestNG" factoryName="TestNG">
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<module name="" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
<option name="SUITE_NAME" />
|
||||
<option name="PACKAGE_NAME" />
|
||||
<option name="MAIN_CLASS_NAME" />
|
||||
<option name="METHOD_NAME" />
|
||||
<option name="GROUP_NAME" />
|
||||
<option name="TEST_OBJECT" value="CLASS" />
|
||||
<option name="VM_PARAMETERS" value="-ea" />
|
||||
<option name="PARAMETERS" />
|
||||
<option name="WORKING_DIRECTORY" value="$MODULE_DIR$" />
|
||||
<option name="OUTPUT_DIRECTORY" />
|
||||
<option name="ANNOTATION_TYPE" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<option name="TEST_SEARCH_SCOPE">
|
||||
<value defaultName="singleModule" />
|
||||
</option>
|
||||
<option name="USE_DEFAULT_REPORTERS" value="false" />
|
||||
<option name="PROPERTIES_FILE" />
|
||||
<envs />
|
||||
<properties />
|
||||
<listeners />
|
||||
<method />
|
||||
</configuration>
|
||||
<configuration name="<template>" type="Applet" default="true" selected="false">
|
||||
<option name="MAIN_CLASS_NAME" />
|
||||
<option name="HTML_FILE_NAME" />
|
||||
<option name="HTML_USED" value="false" />
|
||||
<option name="WIDTH" value="400" />
|
||||
<option name="HEIGHT" value="300" />
|
||||
<option name="POLICY_FILE" value="$APPLICATION_HOME_DIR$/bin/appletviewer.policy" />
|
||||
<option name="VM_PARAMETERS" />
|
||||
</configuration>
|
||||
<configuration name="<template>" type="JUnit" default="true" selected="false">
|
||||
<option name="MAIN_CLASS_NAME" />
|
||||
<option name="VM_PARAMETERS" value="-ea" />
|
||||
<option name="PARAMETERS" />
|
||||
<option name="WORKING_DIRECTORY" value="$MODULE_DIR$" />
|
||||
</configuration>
|
||||
<configuration name="<template>" type="#org.jetbrains.idea.devkit.run.PluginConfigurationType" default="true" selected="false">
|
||||
<option name="VM_PARAMETERS" value="-Xmx512m -Xms256m -XX:MaxPermSize=250m -ea" />
|
||||
</configuration>
|
||||
</component>
|
||||
<component name="ShelveChangesManager" show_recycled="false">
|
||||
<option name="remove_strategy" value="false" />
|
||||
</component>
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="c5c4ced8-75d2-4b8c-a2ac-45d7a9743afa" name="Default" comment="" />
|
||||
<created>1502571896668</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1502571896668</updated>
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="ToolWindowManager">
|
||||
<frame x="0" y="23" width="1440" height="873" extended-state="6" />
|
||||
<editor active="false" />
|
||||
<layout>
|
||||
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Image Layers" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Build Variants" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" />
|
||||
<window_info id="Capture Analysis" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" />
|
||||
<window_info id="Android Monitor" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Captures" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.24964234" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Capture Tool" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.24892704" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
|
||||
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.24964234" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Theme Preview" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" />
|
||||
<window_info id="Android Model" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" />
|
||||
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
|
||||
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||
</layout>
|
||||
</component>
|
||||
<component name="Vcs.Log.UiProperties">
|
||||
<option name="RECENTLY_FILTERED_USER_GROUPS">
|
||||
<collection />
|
||||
</option>
|
||||
<option name="RECENTLY_FILTERED_BRANCH_GROUPS">
|
||||
<collection />
|
||||
</option>
|
||||
</component>
|
||||
<component name="VcsContentAnnotationSettings">
|
||||
<option name="myLimit" value="2678400000" />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager />
|
||||
<watches-manager />
|
||||
</component>
|
||||
<component name="masterDetails">
|
||||
<states>
|
||||
<state key="ArtifactsStructureConfigurable.UI">
|
||||
<settings>
|
||||
<artifact-editor />
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
<state key="FacetStructureConfigurable.UI">
|
||||
<settings>
|
||||
<last-edited>Android</last-edited>
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
<state key="GlobalLibrariesConfigurable.UI">
|
||||
<settings>
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
<state key="JdkListConfigurable.UI">
|
||||
<settings>
|
||||
<last-edited>1.8</last-edited>
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
<state key="ModuleStructureConfigurable.UI">
|
||||
<settings>
|
||||
<last-edited>Android|cordova</last-edited>
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
<state key="ProjectLibrariesConfigurable.UI">
|
||||
<settings>
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
</states>
|
||||
</component>
|
||||
</project>
|
2
cordova/.npmignore
Normal file
|
@ -0,0 +1,2 @@
|
|||
# OS X
|
||||
.DS_Store
|
31
cordova/config.xml
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<widget id="io.cordova.myspells" version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
|
||||
<name>My Spells DnD5e</name>
|
||||
<description>
|
||||
My Spells is an open source web-based application to elegantly view spells and save them to your local spellbook.
|
||||
</description>
|
||||
<author email="joe@wroten.me" href="https://www.wroten.me/">
|
||||
Joe Wroten
|
||||
</author>
|
||||
<content src="index.html" />
|
||||
<access origin="*" />
|
||||
<allow-intent href="http://*/*" />
|
||||
<allow-intent href="https://*/*" />
|
||||
<allow-intent href="tel:*" />
|
||||
<allow-intent href="sms:*" />
|
||||
<allow-intent href="mailto:*" />
|
||||
<allow-intent href="geo:*" />
|
||||
<platform name="android">
|
||||
<allow-intent href="market:*" />
|
||||
</platform>
|
||||
<platform name="android">
|
||||
<icon density="ldpi" src="res/android/ldpi.png" />
|
||||
<icon density="mdpi" src="res/android/mdpi.png" />
|
||||
<icon density="hdpi" src="res/android/hdpi.png" />
|
||||
<icon density="xhdpi" src="res/android/xhdpi.png" />
|
||||
<icon density="xxhdpi" src="res/android/xxhdpi.png" />
|
||||
<icon density="xxxhdpi" src="res/android/xxxhdpi.png" />
|
||||
</platform>
|
||||
<engine name="android" spec="^6.2.3" />
|
||||
<plugin name="cordova-plugin-whitelist" spec="^1.3.2" />
|
||||
</widget>
|
23
cordova/hooks/README.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
<!--
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
-->
|
||||
# Cordova Hooks
|
||||
|
||||
Cordova Hooks represent special scripts which could be added by application and plugin developers or even by your own build system to customize cordova commands. See Hooks Guide for more details: http://cordova.apache.org/docs/en/edge/guide_appdev_hooks_index.md.html#Hooks%20Guide.
|
24
cordova/package.json
Normal file
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "my_spells_app",
|
||||
"displayName": "My Spells - Cordova",
|
||||
"version": "1.0.0",
|
||||
"description": "My Spells is an open source web-based application to elegantly view spells and save them to your local spellbook.",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "Joe Wroten <joe@wroten.me>",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"cordova-android": "^6.2.3",
|
||||
"cordova-plugin-whitelist": "^1.3.2"
|
||||
},
|
||||
"cordova": {
|
||||
"plugins": {
|
||||
"cordova-plugin-whitelist": {}
|
||||
},
|
||||
"platforms": [
|
||||
"android"
|
||||
]
|
||||
}
|
||||
}
|
29
cordova/res/README.md
Normal file
|
@ -0,0 +1,29 @@
|
|||
<!--
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
-->
|
||||
|
||||
Note that these image resources are not copied into a project when a project
|
||||
is created with the CLI. Although there are default image resources in a
|
||||
newly-created project, those come from the platform-specific project template,
|
||||
which can generally be found in the platform's `template` directory. Until
|
||||
icon and splashscreen support is added to the CLI, these image resources
|
||||
aren't used directly.
|
||||
|
||||
See https://issues.apache.org/jira/browse/CB-5145
|
BIN
cordova/res/android/hdpi.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
cordova/res/android/ldpi.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
cordova/res/android/mdpi.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
cordova/res/android/xhdpi.png
Normal file
After Width: | Height: | Size: 7.1 KiB |
BIN
cordova/res/android/xxhdpi.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
cordova/res/android/xxxhdpi.png
Normal file
After Width: | Height: | Size: 13 KiB |
1
cordova/www
Symbolic link
|
@ -0,0 +1 @@
|
|||
../dist
|
418
dist/app.js
vendored
|
@ -1,418 +0,0 @@
|
|||
/**
|
||||
* Misc helper functions
|
||||
*/
|
||||
Object.values = x => Object.keys(x).reduce((y, z) => y.push(x[z]) && y, []);
|
||||
const debounce = (func, wait, immediate) => {
|
||||
let timeout;
|
||||
return function () {
|
||||
let context = this,
|
||||
args = arguments;
|
||||
let later = function () {
|
||||
timeout = null;
|
||||
if (!immediate) func.apply(context, args);
|
||||
};
|
||||
let callNow = immediate && !timeout;
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
if (callNow) func.apply(context, args);
|
||||
};
|
||||
};
|
||||
const el = id => $(`[data-template=${ id }]`)[0] || console.error('Unable to render to', id);
|
||||
const clone = obj => JSON.parse(JSON.stringify(obj));
|
||||
const basicDetails = ['level', 'range', 'duration', 'casting_time', 'saving_throw', 'aoe', 'source'];
|
||||
|
||||
/**
|
||||
* Global store and view holders
|
||||
*/
|
||||
let view = {};
|
||||
let store = {
|
||||
systems: {
|
||||
data: [{
|
||||
friendly: 'Dungeons & Dragons 5e',
|
||||
value: 'dnd5e'
|
||||
}, {
|
||||
friendly: 'HackMaster 4e (WIP)',
|
||||
value: 'hackmaster4e'
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* See Matching System Friendly and Value
|
||||
*/
|
||||
const matchingSystemProp = (system, requested) => store.systems.data.find(d => d[requested === 'value' ? 'friendly' : 'value'] === system)[requested];
|
||||
|
||||
/**
|
||||
* Init Local Storage
|
||||
*/
|
||||
const localStorageDefault = (key, val) => {
|
||||
if (localStorage.getItem(key) === null) localStorage.setItem(key, val);
|
||||
};
|
||||
let defaults = {
|
||||
tableSortName: 'name',
|
||||
tableSortRev: false,
|
||||
system: 'dnd5e',
|
||||
classes: [],
|
||||
search: ''
|
||||
};
|
||||
for (let cur in defaults) localStorageDefault(cur, defaults[cur]);
|
||||
|
||||
if (window.location.hash) {
|
||||
let urlSystem = window.location.hash.substr(1).split('/')[0];
|
||||
localStorage.setItem('system', store.systems.data.find(d => d.value === urlSystem).value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render Table Sort
|
||||
*/
|
||||
store.tableSort = {
|
||||
data: ['name', 'school', 'level'],
|
||||
current: localStorage.getItem('tableSortName'),
|
||||
rev: localStorage.getItem('tableSortRev') !== 'false'
|
||||
};
|
||||
view.table_sort = Monkberry.render(table_sort, el('table-sort'));
|
||||
view.table_sort.update(store.tableSort);
|
||||
|
||||
/**
|
||||
* Render Systems
|
||||
*/
|
||||
store.systems.current = matchingSystemProp(localStorage.getItem('system'), 'friendly');
|
||||
view.systems_list = Monkberry.render(system_list, el('system-list'));
|
||||
view.systems_list.update(store.systems);
|
||||
|
||||
/**
|
||||
* Render Spell List
|
||||
*/
|
||||
view.spell_list = Monkberry.render(spell_list, el('spell-list'));
|
||||
view.spell_list.update({ data: false });
|
||||
|
||||
/**
|
||||
* Render Spell Print List
|
||||
*/
|
||||
view.spell_list_print = Monkberry.render(spell_list_print, el('spell-list-print'));
|
||||
view.spell_list_print.update({});
|
||||
|
||||
/**
|
||||
* Render Spell Details
|
||||
*/
|
||||
view.spell_details = Monkberry.render(spell_details, el('spell-details'));
|
||||
view.spell_details.update({ data: {} });
|
||||
|
||||
/**
|
||||
* Render Class List
|
||||
*/
|
||||
store.classes = {
|
||||
data: [],
|
||||
current: localStorage.getItem('classes') ? localStorage.getItem('classes').split(',') : []
|
||||
};
|
||||
view.class_list = Monkberry.render(class_list, el('class-list'));
|
||||
view.class_list.update({ data: false });
|
||||
|
||||
/**
|
||||
* Render Search
|
||||
*/
|
||||
store.search = localStorage.getItem('search');
|
||||
view.search_field = Monkberry.render(search_field, el('search-field'));
|
||||
view.search_field.update({ data: store.search });
|
||||
|
||||
/**
|
||||
* Discover Classes
|
||||
*/
|
||||
const discoverClasses = spells => {
|
||||
let classes = [];
|
||||
spells.forEach(spell => {
|
||||
if (!spell.classes) return;
|
||||
spell.classes.forEach(current => {
|
||||
if (!classes.includes(current)) classes.push(current);
|
||||
});
|
||||
});
|
||||
return classes.sort((a, b) => a > b);
|
||||
};
|
||||
|
||||
/**
|
||||
* Emphasis on important string bits
|
||||
* @param {string} string
|
||||
*/
|
||||
const emphasis = (str = '') => {
|
||||
let keywords = ['constitution', 'con', 'intelligence', 'int', 'wisdom', 'wis', 'strength', 'str', 'dexterity', 'dex', 'charisma', 'cha', 'comeliness', 'com', 'saving throw', 'ability check', 'skill check'];
|
||||
keywords.forEach(word => {
|
||||
let r = new RegExp(` ${ word } `, 'gi');
|
||||
str = str.replace(r, o => ` _${ o.trim() }_ `);
|
||||
});
|
||||
|
||||
str = str.replace(/[\s()<>]+\d+d*\d*(th)*[\s()<>]+/gi, o => ` **${ o.trim() }** `);
|
||||
return str;
|
||||
};
|
||||
|
||||
/**
|
||||
* Description Prettifier
|
||||
*/
|
||||
const descriptionPrettifier = description => {
|
||||
let md = new Remarkable();
|
||||
description = Array.isArray(description) ? description.join('\n') : description;
|
||||
description = emphasis(description);
|
||||
description = md.render(description);
|
||||
description = description.replace(/\n/g, '<br>');
|
||||
|
||||
return description;
|
||||
};
|
||||
|
||||
/**
|
||||
* Init Spells
|
||||
*/
|
||||
const initSpells = s => s.map((spell, i) => {
|
||||
spell.selected = false;
|
||||
spell.ranking = 0;
|
||||
spell.level = parseInt(spell.level) ? spell.level : 0;
|
||||
return spell;
|
||||
});
|
||||
|
||||
/**
|
||||
* Sort Spells
|
||||
*/
|
||||
const sortSpells = (s, sortBy, reverse) => s.sort((a, b) => {
|
||||
let hasFilters = store.classes.current.length || store.search.length;
|
||||
let by = sortBy || hasFilters ? 'ranking' : store.tableSort.current;
|
||||
let rev = reverse || hasFilters ? false : store.tableSort.rev;
|
||||
if (by) {
|
||||
if (a[by] < b[by]) return rev ? 1 : -1;
|
||||
if (a[by] > b[by]) return rev ? -1 : 1;
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Search Spells
|
||||
* @param {Array} spells
|
||||
* @param {String} ex 'acid spray'
|
||||
* @return {Array} filtered spells
|
||||
*/
|
||||
const searchSpells = (spells, search) => {
|
||||
// Convert search to array of words
|
||||
search = search.split(' ');
|
||||
// Clone spells so we don't affect the original
|
||||
spells = clone(spells);
|
||||
// Reset rankings
|
||||
spells = spells.map(s => {
|
||||
s.ranking = 0;
|
||||
return s;
|
||||
});
|
||||
// Rank spells by # of occurances of search terms
|
||||
spells = spells.map(spell => {
|
||||
search.forEach(term => {
|
||||
let spellText = Object.values(spell).join(' ');
|
||||
let regFind = new RegExp(term, 'gi');
|
||||
spell.ranking += (spellText.match(regFind) || []).length;
|
||||
});
|
||||
return spell;
|
||||
});
|
||||
// Return spells that matched at least something
|
||||
return spells.filter(spell => spell.ranking);
|
||||
};
|
||||
|
||||
/**
|
||||
* Filter Spells by Class
|
||||
*/
|
||||
const filterSpellsByClass = (spells, classes) => {
|
||||
// If no classes, default to all classes
|
||||
classes = classes.length ? classes : store.classes.data;
|
||||
// Clone spells so we don't affect the original
|
||||
spells = clone(spells);
|
||||
return spells.filter(spell => {
|
||||
let spellClasses = spell.classes.join(' ');
|
||||
let match = false;
|
||||
classes.forEach(c => {
|
||||
if (spellClasses.indexOf(c) >= 0) {
|
||||
match = true;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return match;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply Filters
|
||||
* @returns {Array} of spells ranked based on searches and filters
|
||||
*/
|
||||
let applyFilters = () => sortSpells(searchSpells(filterSpellsByClass(store.spells, store.classes.current), store.search));
|
||||
|
||||
/**
|
||||
* Spell Details Updating
|
||||
*/
|
||||
const spellDetails = name => {
|
||||
if (!name) {
|
||||
view.spell_details.update({ data: {} });
|
||||
$('body').removeClass('details');
|
||||
} else {
|
||||
let data = clone(store.spells.find(spell => name === spell.name));
|
||||
data.description = descriptionPrettifier(data.description);
|
||||
data.details = basicDetails.map(detail => {
|
||||
if (data[detail]) {
|
||||
return {
|
||||
label: detail.replace('_', ' '),
|
||||
value: data[detail]
|
||||
};
|
||||
}
|
||||
});
|
||||
if (data.components && data.components.raw) {
|
||||
data.details.push({ label: 'components', value: data.components.raw });
|
||||
}
|
||||
|
||||
view.spell_details.update({
|
||||
data,
|
||||
url: window.location.href
|
||||
});
|
||||
componentHandler.upgradeDom();
|
||||
$('body').addClass('details');
|
||||
let clipboard = new Clipboard('.copy-to-clipboard');
|
||||
clipboard.on('success', e => $('#toast')[0].MaterialSnackbar.showSnackbar({ message: 'Copied link' })).on('error', e => $('#toast')[0].MaterialSnackbar.showSnackbar({ message: 'Sorry! Unable to copy link' }));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Render Print Page
|
||||
*/
|
||||
const renderPrint = () => {
|
||||
let selectedSpells = $('form[data-selected]')
|
||||
// Get array of items in form
|
||||
.serializeArray()
|
||||
// Find spells based on array from form
|
||||
.map(sel => store.spells.find(spell => sel.value === spell.name))
|
||||
// Sort by level then alphabetically
|
||||
.sort((a, b) => {
|
||||
let aName = a.name.toLowerCase();
|
||||
let bName = b.name.toLowerCase();
|
||||
if (a.level > b.level) return 1;
|
||||
if (a.level < b.level) return -1;
|
||||
if (aName > bName) return 1;
|
||||
if (aName < bName) return -1;
|
||||
return 0;
|
||||
})
|
||||
// Prettify Descriptions
|
||||
.map(spell => {
|
||||
spell = clone(spell);
|
||||
spell.description = descriptionPrettifier(spell.description);
|
||||
spell.details = basicDetails.map(detail => {
|
||||
if (spell[detail]) {
|
||||
return {
|
||||
label: detail.replace('_', ' '),
|
||||
value: spell[detail]
|
||||
};
|
||||
}
|
||||
});
|
||||
if (spell.components && spell.components.raw) {
|
||||
spell.details.push({ label: 'components', value: spell.components.raw });
|
||||
}
|
||||
return spell;
|
||||
});
|
||||
view.spell_list_print.update({ data: selectedSpells });
|
||||
if (selectedSpells.length) {
|
||||
$('[data-action=print] [data-badge]').attr('data-badge', selectedSpells.length);
|
||||
$('[data-action=print]').slideDown('fast');
|
||||
} else {
|
||||
$('[data-action=print]').slideUp('fast');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Event Bindings
|
||||
*/
|
||||
$('body')
|
||||
// Listen for header sorts
|
||||
.on('click', '[data-action-sort]', e => {
|
||||
let name = $(e.currentTarget).attr('data-action-sort');
|
||||
let rev = store.tableSort.current === name && !store.tableSort.rev;
|
||||
store.tableSort.current = name;
|
||||
store.tableSort.rev = rev;
|
||||
localStorage.setItem('tableSortName', name);
|
||||
localStorage.setItem('tableSortRev', rev);
|
||||
view.spell_list.update({ data: sortSpells(store.spells) });
|
||||
view.table_sort.update(store.tableSort);
|
||||
componentHandler.upgradeDom();
|
||||
})
|
||||
// Listen for checkbox changes to filter spells
|
||||
.on('change', '[data-action-classtoggle]', e => {
|
||||
let name = $(e.currentTarget).attr('data-action-classtoggle');
|
||||
let add = $(e.currentTarget).prop('checked');
|
||||
let index = store.classes.current.indexOf(name);
|
||||
if (index === -1 && add) {
|
||||
store.classes.current.push(name);
|
||||
} else if (!add) store.classes.current.splice(index, 1);
|
||||
store.tableSort.current = store.classes.current.length || store.search.length ? 'ranking' : null;
|
||||
localStorage.setItem('tableSortName', store.tableSort.current);
|
||||
localStorage.setItem('classes', store.classes.current);
|
||||
view.spell_list.update({ data: applyFilters() });
|
||||
view.table_sort.update({ current: store.tableSort.current });
|
||||
componentHandler.upgradeDom();
|
||||
})
|
||||
// Listen to search to filter by
|
||||
.on('change keyup cut paste', '[data-action-search]', e => {
|
||||
setTimeout(() => {
|
||||
// Delay for value to change
|
||||
store.search = $(e.currentTarget).val();
|
||||
store.tableSort.current = store.search.length || store.classes.current.length ? 'ranking' : null;
|
||||
store.tableSort.rev = false;
|
||||
localStorage.setItem('search', store.search);
|
||||
localStorage.setItem('tableSortName', store.tableSort.current);
|
||||
localStorage.setItem('tableSortRev', store.tableSort.rev);
|
||||
view.spell_list.update({ data: applyFilters() });
|
||||
view.table_sort.update(store.tableSort);
|
||||
componentHandler.upgradeDom();
|
||||
}, 0);
|
||||
})
|
||||
// Listen for click on spells to open details
|
||||
.on('click', '[data-action-details]', e => {
|
||||
let name = $(e.currentTarget).attr('data-action-details');
|
||||
if (name) {
|
||||
window.location.hash = matchingSystemProp(store.systems.current, 'value') + '/' + name;
|
||||
} else {
|
||||
window.location.hash = '';
|
||||
}
|
||||
spellDetails(name);
|
||||
})
|
||||
// Stop propogation if dontprop clicked
|
||||
.on('click', '.dontprop', e => {
|
||||
e.stopPropagation();
|
||||
})
|
||||
// Toggle All
|
||||
.on('change', 'label[for=table-header] input[type=checkbox]', e => {
|
||||
$(e.target).closest('form').find('[name=selected]').each(function () {
|
||||
this.checked = e.target.checked;
|
||||
if (this.checked) $(this).closest('label').addClass('is-checked');else $(this).closest('label').removeClass('is-checked');
|
||||
});
|
||||
renderPrint();
|
||||
}).on('change', 'input[name=selected][type=checkbox]', renderPrint).on('click', '[data-action=print]', e => {
|
||||
window.print();
|
||||
});
|
||||
// Article Scroll with User
|
||||
$('.mdl-layout__content').on('scroll', debounce(() => {
|
||||
let distance = $('.mdl-layout__content')[0].scrollTop;
|
||||
$('[data-template=spell-details]').css('margin-top', distance);
|
||||
}, 10));
|
||||
// System changed
|
||||
$('[data-action=system]').on('change', e => {
|
||||
let system = $(e.currentTarget).val();
|
||||
let systemValue = matchingSystemProp(system, 'value');
|
||||
window.location.hash = '';
|
||||
spellDetails('');
|
||||
store.systems.current = system;
|
||||
localStorage.setItem('system', systemValue);
|
||||
view.spell_list.update({ data: false });
|
||||
view.class_list.update({ data: false });
|
||||
fetchSpells(systemValue);
|
||||
});
|
||||
|
||||
/**
|
||||
* Fetch Spells
|
||||
*/
|
||||
const fetchSpells = (system = matchingSystemProp(store.systems.current, 'value')) => fetch(`./systems/${ system }.json`).then(response => response.json()).then(spells => initSpells(spells)).then(spells => {
|
||||
store.spells = spells;
|
||||
store.classes.data = discoverClasses(spells);
|
||||
view.spell_list.update({ data: applyFilters() });
|
||||
view.class_list.update(store.classes);
|
||||
componentHandler.upgradeDom();
|
||||
if (window.location.hash) spellDetails(window.location.hash.substr(1).split('/')[1]);
|
||||
return spells;
|
||||
}).catch(reason => console.error('Unable to retrieve spells list:', reason));
|
||||
fetchSpells();
|
7
dist/clipboard.min.js
vendored
3
dist/getmdl-select.min.css
vendored
|
@ -1,3 +0,0 @@
|
|||
.getmdl-select .mdl-icon-toggle__label{float:right;margin-top:-30px;color:rgba(0,0,0,0.4)}.getmdl-select.is-focused .mdl-icon-toggle__label{color:#3f51b5}.getmdl-select .mdl-menu__container{width:100% !important}.getmdl-select .mdl-menu__container .mdl-menu{width:100%}
|
||||
|
||||
/*# sourceMappingURL=getmdl-select.min.css.map */
|
2
dist/getmdl-select.min.js
vendored
|
@ -1,2 +0,0 @@
|
|||
"use strict";window.onload=function(){getmdlSelect.init(".getmdl-select"),document.addEventListener("DOMNodeInserted",function(e){componentHandler.upgradeDom()},!1)};var getmdlSelect={addEventListeners:function(e){var t=e.querySelector("input"),n=e.querySelectorAll("li");[].forEach.call(n,function(e){e.onclick=function(){if(t.value=e.textContent,"createEvent"in document){var n=document.createEvent("HTMLEvents");n.initEvent("change",!1,!0),t.dispatchEvent(n)}else t.fireEvent("onchange")}})},init:function(e){var t=document.querySelectorAll(e);[].forEach.call(t,function(e){getmdlSelect.addEventListeners(e)})}};
|
||||
//# sourceMappingURL=getmdl-select.min.js.map
|
4
dist/jquery.min.js
vendored
385
dist/monkberry.js
vendored
|
@ -1,385 +0,0 @@
|
|||
/** _ _
|
||||
* /\/\ ___ _ __ | | _| |__ ___ _ __ _ __ _ _
|
||||
* / \ / _ \| '_ \| |/ / '_ \ / _ \ '__| '__| | | |
|
||||
* / /\/\ \ (_) | | | | <| |_) | __/ | | | | |_| |
|
||||
* \/ \/\___/|_| |_|_|\_\_.__/ \___|_| |_| \__, |
|
||||
* |___/
|
||||
*
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* Enter -> | | | | | |
|
||||
* + + + +---+ +---+---+ +---+---+ + + +---+ + +---+ + + +
|
||||
* | | | | | | | | | | |
|
||||
* +---+---+---+---+---+ +---+---+---+---+ +---+---+ +---+ + +---+---+ +
|
||||
* | | | | | | | | | |
|
||||
* + + + +---+---+---+ + + +---+---+ + +---+ + +---+---+ + +
|
||||
* | | | | | | | | | | |
|
||||
* + +---+---+ +---+ + + +---+ + +---+---+---+---+---+ + + +---+
|
||||
* | | | | | | | | | | | | | |
|
||||
* + +---+ +---+ +---+---+---+ + + + + + + + +---+---+ + +
|
||||
* | | | | | | | | | | | | |
|
||||
* +---+---+---+ +---+ + + + +---+---+---+ +---+ +---+---+ + + +
|
||||
* | | | | | | | | | | |
|
||||
* + + + +---+---+---+ +---+ + + + +---+ +---+---+ +---+---+ +
|
||||
* | | | | | | | | | | | | |
|
||||
* + + +---+---+ +---+---+---+ +---+ +---+ + + + + + +---+ +
|
||||
* | | | | | | | | | |
|
||||
* +---+---+ + + +---+---+---+---+ +---+ +---+ + +---+---+ + +---+
|
||||
* | | | | | | -> Exit
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
*/
|
||||
(function (document) {
|
||||
/**
|
||||
* Monkberry
|
||||
* @class
|
||||
*/
|
||||
function Monkberry() {
|
||||
this.parent = null;
|
||||
this.nested = [];
|
||||
this.nodes = [];
|
||||
this.filters = null;
|
||||
this.directives = null;
|
||||
this.context = null;
|
||||
this.unbind = null;
|
||||
this.onRender = null;
|
||||
this.onUpdate = null;
|
||||
this.onRemove = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render template and attach it to node.
|
||||
* @param {Monkberry} template
|
||||
* @param {Element} node
|
||||
* @param {Object=} options
|
||||
* @return {Monkberry}
|
||||
*/
|
||||
Monkberry.render = function (template, node, options) {
|
||||
var view;
|
||||
|
||||
if (options && options.noCache) {
|
||||
view = new template();
|
||||
} else {
|
||||
view = template.pool.pop() || new template();
|
||||
}
|
||||
|
||||
if (node.nodeType == 8) {
|
||||
view.insertBefore(node);
|
||||
} else {
|
||||
view.appendTo(node);
|
||||
}
|
||||
|
||||
if (options) {
|
||||
if (options.parent) {
|
||||
view.parent = options.parent;
|
||||
}
|
||||
|
||||
if (options.context) {
|
||||
view.context = options.context;
|
||||
}
|
||||
|
||||
if (options.filters) {
|
||||
view.filters = options.filters;
|
||||
}
|
||||
|
||||
if (options.directives) {
|
||||
view.directives = options.directives;
|
||||
}
|
||||
}
|
||||
|
||||
if (view.onRender) {
|
||||
view.onRender();
|
||||
}
|
||||
|
||||
return view;
|
||||
};
|
||||
|
||||
/**
|
||||
* Prerepder template for future usage.
|
||||
* @param {Monkberry} template - Template name.
|
||||
* @param {Number} times - Times of prerender.
|
||||
*/
|
||||
Monkberry.prerender = function (template, times) {
|
||||
while (times--) {
|
||||
template.pool.push(new template());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Main loops processor.
|
||||
*/
|
||||
Monkberry.loop = function (parent, node, map, template, array, options) {
|
||||
var i, j, len, keys, transform, arrayLength, childrenSize = map.length;
|
||||
|
||||
// Get array length, and convert object to array if needed.
|
||||
if (Array.isArray(array)) {
|
||||
transform = transformArray;
|
||||
arrayLength = array.length;
|
||||
} else {
|
||||
transform = transformObject;
|
||||
keys = Object.keys(array);
|
||||
arrayLength = keys.length;
|
||||
}
|
||||
|
||||
// If new array contains less items what before, remove surpluses.
|
||||
len = childrenSize - arrayLength;
|
||||
for (i in map.items) {
|
||||
if (len-- > 0) {
|
||||
map.items[i].remove();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If there is already some views, update there loop state.
|
||||
j = 0;
|
||||
for (i in map.items) {
|
||||
map.items[i].__state__ = transform(array, keys, j, options);
|
||||
j++;
|
||||
}
|
||||
|
||||
// If new array contains more items when previous, render new views and append them.
|
||||
for (j = childrenSize, len = arrayLength; j < len; j++) {
|
||||
// Render new view.
|
||||
var view = Monkberry.render(template, node, {parent: parent, context: parent.context, filters: parent.filters, directives: parent.directives});
|
||||
|
||||
// Set view hierarchy.
|
||||
parent.nested.push(view);
|
||||
|
||||
// Remember to remove from children map on view remove.
|
||||
i = map.push(view);
|
||||
view.unbind = (function (i) {
|
||||
return function () {
|
||||
map.remove(i);
|
||||
};
|
||||
})(i);
|
||||
|
||||
// Set view state for later update in onUpdate.
|
||||
view.__state__ = transform(array, keys, j, options);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Main if processor.
|
||||
*/
|
||||
Monkberry.cond = function (parent, node, child/*.ref*/, template, test) {
|
||||
if (child.ref) { // If view was already inserted, update or remove it.
|
||||
if (!test) {
|
||||
child.ref.remove();
|
||||
}
|
||||
} else if (test) {
|
||||
// Render new view.
|
||||
var view = Monkberry.render(template, node, {parent: parent, context: parent.context, filters: parent.filters, directives: parent.directives});
|
||||
|
||||
// Set view hierarchy.
|
||||
parent.nested.push(view);
|
||||
|
||||
// Remember to remove child ref on remove of view.
|
||||
child.ref = view;
|
||||
view.unbind = function () {
|
||||
child.ref = null;
|
||||
};
|
||||
}
|
||||
|
||||
return test;
|
||||
};
|
||||
|
||||
/**
|
||||
* Main custom tags processor.
|
||||
*/
|
||||
Monkberry.insert = function (parent, node, child/*.ref*/, template, data) {
|
||||
if (child.ref) { // If view was already inserted, update or remove it.
|
||||
child.ref.update(data);
|
||||
} else {
|
||||
// Render new view.
|
||||
var view = Monkberry.render(template, node, {parent: parent, context: parent.context, filters: parent.filters, directives: parent.directives});
|
||||
|
||||
// Set view hierarchy.
|
||||
parent.nested.push(view);
|
||||
|
||||
// Remember to remove child ref on remove of view.
|
||||
child.ref = view;
|
||||
view.unbind = function () {
|
||||
child.ref = null;
|
||||
};
|
||||
|
||||
// Set view data (note what it must be after adding nodes to DOM).
|
||||
view.update(data);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove view from DOM.
|
||||
*/
|
||||
Monkberry.prototype.remove = function () {
|
||||
// Remove appended nodes.
|
||||
var i = this.nodes.length;
|
||||
while (i--) {
|
||||
this.nodes[i].parentNode.removeChild(this.nodes[i]);
|
||||
}
|
||||
|
||||
// Remove self from parent's children map or child ref.
|
||||
if (this.unbind) {
|
||||
this.unbind();
|
||||
}
|
||||
|
||||
// Remove all nested views.
|
||||
i = this.nested.length;
|
||||
while (i--) {
|
||||
this.nested[i].remove();
|
||||
}
|
||||
|
||||
// Remove this view from parent's nested views.
|
||||
if (this.parent) {
|
||||
i = this.parent.nested.indexOf(this);
|
||||
this.parent.nested.splice(i, 1);
|
||||
this.parent = null;
|
||||
}
|
||||
|
||||
// Call on remove callback.
|
||||
if (this.onRemove) {
|
||||
this.onRemove();
|
||||
}
|
||||
|
||||
// Store view in pool for reuse in future.
|
||||
this.constructor.pool.push(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Element} toNode
|
||||
*/
|
||||
Monkberry.prototype.appendTo = function (toNode) {
|
||||
for (var i = 0, len = this.nodes.length; i < len; i++) {
|
||||
toNode.appendChild(this.nodes[i]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Element} toNode
|
||||
*/
|
||||
Monkberry.prototype.insertBefore = function (toNode) {
|
||||
if (toNode.parentNode) {
|
||||
for (var i = 0, len = this.nodes.length; i < len; i++) {
|
||||
toNode.parentNode.insertBefore(this.nodes[i], toNode);
|
||||
}
|
||||
} else {
|
||||
throw new Error(
|
||||
"Can not insert child view into parent node. " +
|
||||
"You need append your view first and then update."
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return rendered node, or DocumentFragment of rendered nodes if more then one root node in template.
|
||||
* @returns {Element|DocumentFragment}
|
||||
*/
|
||||
Monkberry.prototype.createDocument = function () {
|
||||
if (this.nodes.length == 1) {
|
||||
return this.nodes[0];
|
||||
} else {
|
||||
var fragment = document.createDocumentFragment();
|
||||
for (var i = 0, len = this.nodes.length; i < len; i++) {
|
||||
fragment.appendChild(this.nodes[i]);
|
||||
}
|
||||
return fragment;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} query
|
||||
* @returns {Element}
|
||||
*/
|
||||
Monkberry.prototype.querySelector = function (query) {
|
||||
for (var i = 0; i < this.nodes.length; i++) {
|
||||
if (this.nodes[i].matches && this.nodes[i].matches(query)) {
|
||||
return this.nodes[i];
|
||||
}
|
||||
|
||||
if (this.nodes[i].nodeType === 8) {
|
||||
throw new Error('Can not use querySelector with non-element nodes on first level.');
|
||||
}
|
||||
|
||||
if (this.nodes[i].querySelector) {
|
||||
var element = this.nodes[i].querySelector(query);
|
||||
if (element) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Simple Map implementation with length property.
|
||||
*/
|
||||
function Map() {
|
||||
this.items = Object.create(null);
|
||||
this.length = 0;
|
||||
this.next = 0;
|
||||
}
|
||||
|
||||
Map.prototype.push = function (element) {
|
||||
this.items[this.next] = element;
|
||||
this.length += 1;
|
||||
this.next += 1;
|
||||
return this.next - 1;
|
||||
};
|
||||
|
||||
Map.prototype.remove = function (i) {
|
||||
if (i in this.items) {
|
||||
delete this.items[i];
|
||||
this.length -= 1;
|
||||
} else {
|
||||
throw new Error('You are trying to delete not existing element "' + i + '" form map.');
|
||||
}
|
||||
};
|
||||
|
||||
Map.prototype.forEach = function (callback) {
|
||||
for (var i in this.items) {
|
||||
callback(this.items[i]);
|
||||
}
|
||||
};
|
||||
|
||||
Monkberry.Map = Map;
|
||||
|
||||
//
|
||||
// Helper function for working with foreach loops data.
|
||||
// Will transform data for "key, value of array" constructions.
|
||||
//
|
||||
|
||||
function transformArray(array, keys, i, options) {
|
||||
if (options) {
|
||||
var t = {__index__: i};
|
||||
t[options.value] = array[i];
|
||||
|
||||
if (options.key) {
|
||||
t[options.key] = i;
|
||||
}
|
||||
|
||||
return t;
|
||||
} else {
|
||||
return array[i];
|
||||
}
|
||||
}
|
||||
|
||||
function transformObject(array, keys, i, options) {
|
||||
if (options) {
|
||||
var t = {__index__: i};
|
||||
t[options.value] = array[keys[i]];
|
||||
|
||||
if (options.key) {
|
||||
t[options.key] = keys[i];
|
||||
}
|
||||
|
||||
return t;
|
||||
} else {
|
||||
return array[keys[i]];
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof module !== 'undefined') {
|
||||
module.exports = Monkberry;
|
||||
} else {
|
||||
window.Monkberry = Monkberry;
|
||||
}
|
||||
})(window.document);
|
4
dist/remarkable.min.js
vendored
1241
dist/view.js
vendored
1
dist/view.js.map
vendored
|
@ -1 +0,0 @@
|
|||
{"version":3,"sources":["class-list.monk","search-field.monk","spell-details.monk","spell-list-print.monk","spell-list.monk","system-list.monk","table-sort.monk"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,mEAAM,IAAN,C;AAAA,oE;;;;;;AAAA;AAAA;AAAA,K;AAAA;AAAA;AAAA,K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACI,kEAAc,IAAd,kB;;;;;;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;;;;;;;;;;;;;;;;;;;EACI,6C;EACI,yC;;;;EAMI,2C;;;;;EAAM,4BAAO,mBAAP,E;;;EANL,2BAAO,+CAAP,E;;EADF,6BAAO,sBAAP,E;;;;;;AAEC,4EAAM,QAAQ,QAAR,CAAiB,GAAjB,CAAN,C;AAAA,6E;;;AAMI,0BAAG,G;;;;;;AANP;AAAA;AAAA,K;AAAA;AAAA;AAAA,K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EACI,6C;;;EAAO,sB;EAA4C,4BAAM,OAAN,E;EAAa,4BAAM,UAAN,E;EAAgB,6BAAO,mBAAP,E;;;;;AAAjE,qDAA4B,GAA5B,E;;;;;;;;;;;;;;;;;;;;;;;EAEf,6C;;;EAA2C,4BAAM,OAAN,E;EAAa,4BAAM,UAAN,E;EAAgB,6BAAO,mBAAP,E;;;;;AAAjE,qDAA4B,GAA5B,E;;;;;;;;;;;;;;;;;;;;;;;EASvB,yC;;;EAAK,2BAAO,sCAAP,E;;;;;;;;;;AAhBT;AAAA;;;;;;;;;ECAA,6C;;;EAA0B,6BAAO,sBAAP,E;EAA6B,8C;EAAmB,4BAAM,MAAN,E;EAAY,YAAI,yBAAJ,C;;;;;AAA/E,qBAAU,IAAV,C;;;;;;;;;;;;;;;AAAP;AAAA;;;;;;;;;;;;;;;;;;;;ACAA,sEAAM,KAAK,IAAX,C;AAAA,uE;;;;;;AAAA;AAAA;AAAA,K;AAAA;AAAA;AAAA,K;;;;;;;;;;;;;;;;;;;;;;;;EACI,+C;EACE,qC;EAEF,uC;;EACA,uC;;EAOA,qC;;EAEA,yC;EACI,6C;EACI,qC;EAEJ,6C;;;;EAhBC,yBAAO,gBAAP,E;;EADG,gD;EAAuB,8BAAO,+DAAP,E;;EAG3B,0BAAO,oDAAP,E;EACA,SAAI,SAAJ,C;EAOD,QAAI,aAAJ,C;;EAIQ,yBAAO,gBAAP,E;;EADA,6BAAO,6DAAP,E;EAAoE,2BAAK,WAAL,E;EAAgB,6CAAuB,YAAvB,E;EAGpF,oC;EAAS,6BAAO,sBAAP,E;EAA6B,4BAAM,MAAN,E;EAAY,YAAI,WAAJ,C;;;EAJxD,2BAAO,gCAAP,E;EAAuC,UAAI,MAAJ,C;;;;;AAVmB,0BAAG,KAAK,I;AAEnE,oEAAiB,KAAK,OAAtB,qB;AAMgB,iCAAU,KAAK,WAAf,C;;;AAMwD,qBAAU,GAAV,C;;;;;;AAZxE;AAAA;AAAA;AAAA,O;;;;;;;;;;;;;;;;;;;;;;;;;;;EACI,uC;EACI,+C;;;;;;;;;;;;;AAAQ,0BAAG,OAAO,K;AAAuB,0BAAG,OAAO,K;;;;;;;;;;;;;;;;;;;;;;;EAa/D,yC;EACI,uC;;;;EAAI,0BAAO,uBAAP,E;;EADH,UAAI,OAAJ,C;;;;;;;;;;AArBT;AAAA;;;;;;;;;;;;;;;;;;ACAA,oEAAgB,IAAhB,oB;;;;;;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;;;;;;;;;;;;;;;;;;EACI,uC;EACI,uC;EACI,+C;;EAIJ,uC;;EAGA,uC;EACI,uC;;;;;;;;EATA,0BAAO,YAAP,E;;EAKA,0BAAO,aAAP,E;EAII,SAAI,SAAJ,C;;;EADJ,0BAAO,mBAAP,E;;;;;;;;AANI,0BAAG,MAAM,I;AAIb,0BAAG,MAAM,K;AAIL,wEAAiB,MAAM,OAAvB,qB;AAOJ,sCAAU,MAAM,WAAhB,C;;;;;;AAPI;AAAA;AAAA;AAAA,O;;;;;;;;;;;;;;;;;;;;;;;;EACI,uC;EACI,+C;;;;;;;;;;;;;AAAQ,0BAAG,OAAO,K;AAAuB,0BAAG,OAAO,K;;;;;;;;;;;;;;;AAd3E;AAAA;;;;;;;;;;;;;;;;;;ACAA,mEAAM,KAAK,MAAX,C;AAAA,oE;;;;;;AAAA;AAAA;AAAA,K;AAAA;AAAA;AAAA,K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACI,kEAAgB,IAAhB,oB;;;;;;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACI,mEAAM,MAAM,IAAZ,C;;;;;;AAAA;AAAA;AAAA,K;;;;;;;;;;;;;;;;;;;;;;;EACI,uC;EACI,uC;EACI,6C;EACI,6C;EAGR,uC;EACI,+C;;EAIJ,uC;;EAGA,uC;;;;EAXe,4BAAM,UAAN,E;EAAgB,4BAAM,UAAN,E;EAAyC,6BAAO,8BAAP,E;;EAD7D,6BAAO,mFAAP,E;;EADP,0BAAO,YAAP,E;;;EAKA,0BAAO,8CAAP,E;;EAKA,0BAAO,gDAAP,E;;EAGA,0BAAO,aAAP,E;;;;;;;;;AAX2C,qBAAU,MAAM,IAAhB,C;AAKvC,0BAAG,MAAM,I;AAIb,0BAAG,MAAM,M;AAGT,2BAAG,MAAM,K;AAfb,8CAAwB,MAAM,IAA9B,E;;;;;;;;;;;;;;;;;;;;;;;;EAqBZ,uC;EACI,uC;;;;;EAAI,4BAAS,GAAT,E;;EADJ,0BAAO,YAAP,E;;;;;;AAEI,wEAAM,IAAN,C;AAAA,yE;;;;;;AAAA;AAAA;AAAA,K;AAAA;AAAA;AAAA,K;;;;;;;;;;;;;;;;;;;;;;;EACI,yC;EACI,qC;EAGA,uC;EACA,uC;;;;EAJG,yBAAO,+DAAP,E;;;;;;EADF,2BAAO,aAAP,E;;;;;;;;;;;;;;;;;;EAQL,yC;;;EAAK,2BAAO,sCAAP,E;;;;;;;;;;AAnCrB;AAAA;;;;;;;;;;;;;;;;ACAA,2DAAM,IAAN,C;;;;;;AAAA;AAAA;AAAA,K;;;;;;;;;;;;;;;;;;;;;;;;EACI,yC;EACI,6C;EACA,6C;EACA,uC;;;;EAFO,6BAAO,sBAAP,E;EAA6B,mCAAa,QAAb,E;EAA2C,4BAAM,MAAN,E;EAAY,YAAI,QAAJ,C;EAAY,oC;EAAS,gCAAU,IAAV,E;;EACzG,6BAAO,4CAAP,E;EAAmD,2BAAK,QAAL,E;EACtD,0BAAO,4CAAP,E;EAAmD,wBAAK,QAAL,E;;;;EAHtD,2BAAO,4EAAP,E;;;;;AACwD,qBAAU,OAAV,C;;;AAGrD,kEAAiB,IAAjB,qB;;;;;;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;;;;;;;;;;;;;;;;;;;;EACI,uC;;;;;EAAI,0BAAO,gBAAP,E;;;;;AAAuB,0BAAG,OAAO,Q;;;;;;;;;;;;;;;AANrD;AAAA;;;;;;;;;;ECAA,uC;EACI,6C;EACI,6C;;;;;EAAO,4BAAM,UAAN,E;EAAgB,YAAI,cAAJ,C;EAAkB,6BAAO,qBAAP,E;;EADtC,6BAAO,0EAAP,E;EAAiF,2BAAK,cAAL,E;;EADxF,0BAAO,YAAP,E;;;;;AAKJ,8DAAe,IAAf,mB;;;;;;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;;;;;;;;;;;;;;;;;;;EACI,uC;EACI,qC;;;;;;;EAYA,2C;;EAIA,qC;;;;;;;EAhBG,yBAAO,oCAAP,E;;;;EAgBA,yBAAO,8DAAP,E;;;;EAjB2B,0BAAO,oCAAP,E;;;;;AAE1B,+DAAM,YAAS,OAAT,CAAN,C;AAGA,+DAAM,YAAS,MAAT,CAAN,C;AAGA,+DAAM,YAAS,QAAT,CAAN,C;AAMO,0BAAG,I;AAdd,2CAAqB,IAArB,E;;;AAkBI,0BAAG,QAAM,mBAAN,GAA4B,qB;;;AADhC,gCAAO,8DAAP,KAAsE,aAAS,OAAT,KAAmB,0BAAnB,GAAgD,0BAAtH,G;;;AAjB2B,iCAAO,oCAAP,KAA4C,gBAAY,SAAZ,KAAwB,qCAAxB,GAAgE,EAA5G,G;;;;;;AAE1B;AAAA;AAAA,K;AAGA;AAAA;AAAA,K;AAGA;AAAA;AAAA,K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBANyB,qC;;;;;;;;;;;;;;;gBAGD,qC;;;;;;;;;;;;;;;gBAGE,mC;;;;;;;AAdtC;AAAA","file":"view.js"}
|
13
docker-compose.yml
Normal file
|
@ -0,0 +1,13 @@
|
|||
version: '2'
|
||||
|
||||
services:
|
||||
app:
|
||||
build: .
|
||||
image: your-docker-org/your-app-name
|
||||
command: sh
|
||||
volumes:
|
||||
- .:/opt/app
|
||||
- /opt/app/node_modules
|
||||
ports:
|
||||
- 8080:8080
|
||||
tty: true
|
15
dockerfile
Normal file
|
@ -0,0 +1,15 @@
|
|||
#change this to your own repo, should you have uploaded your image!
|
||||
FROM quasarframework/client-dev:latest
|
||||
|
||||
MAINTAINER Your Name <your.email@your-sites-address.com>
|
||||
|
||||
WORKDIR /opt/app
|
||||
|
||||
COPY package.json /opt/app/
|
||||
RUN npm install
|
||||
|
||||
COPY . /opt/app
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
CMD /bin/sh
|
116
index.html
|
@ -1,116 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>My Spells</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700" type="text/css">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
|
||||
<link rel="stylesheet" href="https://code.getmdl.io/1.1.3/material.teal-pink.min.css" />
|
||||
<link rel="stylesheet" href="./dist/getmdl-select.min.css" />
|
||||
<link rel="stylesheet" href="./assets/app.css" />
|
||||
<link rel="stylesheet" href="./assets/print.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="mdl-layout mdl-js-layout mdl-layout--fixed-drawer mdl-layout--fixed-header">
|
||||
<header class="mdl-layout__header">
|
||||
<div class="mdl-layout__header-row">
|
||||
<div data-template="system-list"></div>
|
||||
<div class="mdl-layout-spacer"></div>
|
||||
<button data-action="print" class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-color-text--white">
|
||||
<span class="mdl-badge" data-badge="0">
|
||||
<i class="material-icons">print</i>
|
||||
Print
|
||||
</span>
|
||||
</button>
|
||||
<div data-action-details="" role="button" tabindex="0"><i class="material-icons">keyboard_arrow_left</i></div>
|
||||
</div>
|
||||
</header>
|
||||
<aside class="mdl-layout__drawer">
|
||||
<span class="mdl-layout-title mdl-color-text--pink-600">
|
||||
<i class="material-icons">whatshot</i>
|
||||
My Spells
|
||||
</span>
|
||||
<nav class="mdl-navigation">
|
||||
<form>
|
||||
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
|
||||
<div data-template="search-field"></div>
|
||||
<label class="mdl-textfield__label">
|
||||
<i class="material-icons">search</i>
|
||||
Search
|
||||
</label>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form data-template="class-list">
|
||||
</form>
|
||||
</nav>
|
||||
</aside>
|
||||
<main class="mdl-layout__content">
|
||||
<div class="page-content">
|
||||
<form class="mdl-grid" id="selected-spells" data-selected>
|
||||
<table id="spell-list-container" class="mdl-cell mdl-cell--12-col mdl-cell--6-col-desktop mdl-data-table mdl-shadow--2dp">
|
||||
<thead>
|
||||
<tr data-template="table-sort"></tr>
|
||||
</thead>
|
||||
<tbody data-template="spell-list"></tbody>
|
||||
</table>
|
||||
<article data-template="spell-details" class="mdl-cell mdl-cell--12-col mdl-cell--6-col-desktop mdl-color-text--grey-600"></article>
|
||||
</form>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="mdl-mini-footer">
|
||||
<div class="mdl-mini-footer__right-section">
|
||||
<div class="mdl-logo hide-phone">My Spells</div>
|
||||
<ul class="mdl-mini-footer__link-list">
|
||||
<li>
|
||||
<a class="hide-phone mdl-navigation__link mdl-color-text--teal-100" href="https://github.com/sharpshark28/my_spells">
|
||||
<i class="material-icons">code</i>
|
||||
Fork Me On Github
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="mdl-navigation__link" href="https://dark12222000.github.io/lootsplit/">
|
||||
<i class="material-icons">local_atm</i>
|
||||
Loot Split
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="mdl-navigation__link" href="http://paulvmoreau.github.io/BeltFedNPCs/">
|
||||
<i class="material-icons">people</i>
|
||||
NPC Generator
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<div id="toast" class="mdl-js-snackbar mdl-snackbar">
|
||||
<div class="mdl-snackbar__text"></div>
|
||||
<button class="mdl-snackbar__action" type="button"></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="printonly">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Spell Name</th>
|
||||
<th>Level</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody data-template="spell-list-print">
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<script src="https://code.getmdl.io/1.1.3/material.min.js"></script>
|
||||
<script src="./dist/getmdl-select.min.js"></script>
|
||||
<script src="./dist/jquery.min.js"></script>
|
||||
<script src="./dist/monkberry.js"></script>
|
||||
<script src="./dist/remarkable.min.js"></script>
|
||||
<script src="./dist/clipboard.min.js"></script>
|
||||
<script src="./dist/view.js"></script>
|
||||
<script src="./dist/app.js"></script>
|
||||
</body>
|
||||
</html>
|
264
ogl.html
|
@ -1,133 +1,133 @@
|
|||
<html>
|
||||
|
||||
<head>
|
||||
<title>Open Game License v0.1 Simplified</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<center><a href="./index.html">OGF Main</a> |
|
||||
<a href="./licenses.html">List of Licenses</a> |
|
||||
Open Game License Text</center>
|
||||
|
||||
<P>THIS LICENSE IS APPROVED FOR GENERAL USE. PERMISSION TO DISTRIBUTE THIS LICENSE
|
||||
IS MADE BY WIZARDS OF THE COAST!</P>
|
||||
|
||||
<P>OPEN GAME LICENSE Version 1.0a</P>
|
||||
|
||||
<P>The following text is the property of Wizards of the Coast, Inc. and is
|
||||
Copyright 2000 Wizards of the Coast, Inc ("Wizards"). All Rights Reserved.</P>
|
||||
|
||||
<P>1. Definitions: (a)"Contributors" means the copyright and/or trademark
|
||||
owners who have contributed Open Game Content; (b)"Derivative Material"
|
||||
means copyrighted material including derivative works and translations
|
||||
(including into other computer languages), potation, modification,
|
||||
correction, addition, extension, upgrade, improvement, compilation,
|
||||
abridgment or other form in which an existing work may be recast,
|
||||
transformed or adapted; (c) "Distribute" means to reproduce, license, rent,
|
||||
lease, sell, broadcast, publicly display, transmit or otherwise distribute;
|
||||
(d)"Open Game Content" means the game mechanic and includes the methods,
|
||||
procedures, processes and routines to the extent such content does not
|
||||
embody the Product Identity and is an enhancement over the prior art and any
|
||||
additional content clearly identified as Open Game Content by the
|
||||
Contributor, and means any work covered by this License, including
|
||||
translations and derivative works under copyright law, but specifically
|
||||
excludes Product Identity. (e) "Product Identity" means product and product
|
||||
line names, logos and identifying marks including trade dress; artifacts;
|
||||
creatures characters; stories, storylines, plots, thematic elements,
|
||||
dialogue, incidents, language, artwork, symbols, designs, depictions,
|
||||
likenesses, formats, poses, concepts, themes and graphic, photographic and
|
||||
other visual or audio representations; names and descriptions of characters,
|
||||
spells, enchantments, personalities, teams, personas, likenesses and special
|
||||
abilities; places, locations, environments, creatures, equipment, magical or
|
||||
supernatural abilities or effects, logos, symbols, or graphic designs; and
|
||||
any other trademark or registered trademark clearly identified as Product
|
||||
identity by the owner of the Product Identity, and which specifically
|
||||
excludes the Open Game Content; (f) "Trademark" means the logos, names,
|
||||
mark, sign, motto, designs that are used by a Contributor to identify itself
|
||||
or its products or the associated products contributed to the Open Game
|
||||
License by the Contributor (g) "Use", "Used" or "Using" means to use,
|
||||
Distribute, copy, edit, format, modify, translate and otherwise create
|
||||
Derivative Material of Open Game Content. (h) "You" or "Your" means the
|
||||
licensee in terms of this agreement.</P>
|
||||
|
||||
<P>2. The License: This License applies to any Open Game Content that contains
|
||||
a notice indicating that the Open Game Content may only be Used under and in
|
||||
terms of this License. You must affix such a notice to any Open Game Content
|
||||
that you Use. No terms may be added to or subtracted from this License
|
||||
except as described by the License itself. No other terms or conditions may
|
||||
be applied to any Open Game Content distributed using this License.</P>
|
||||
|
||||
<P>3.Offer and Acceptance: By Using the Open Game Content You indicate Your
|
||||
acceptance of the terms of this License.</P>
|
||||
|
||||
<P>4. Grant and Consideration: In consideration for agreeing to use this
|
||||
License, the Contributors grant You a perpetual, worldwide, royalty-free,
|
||||
non-exclusive license with the exact terms of this License to Use, the Open
|
||||
Game Content.</P>
|
||||
|
||||
<P>5.Representation of Authority to Contribute: If You are contributing
|
||||
original material as Open Game Content, You represent that Your
|
||||
Contributions are Your original creation and/or You have sufficient rights
|
||||
to grant the rights conveyed by this License.</P>
|
||||
|
||||
<P>6.Notice of License Copyright: You must update the COPYRIGHT NOTICE portion
|
||||
of this License to include the exact text of the COPYRIGHT NOTICE of any
|
||||
Open Game Content You are copying, modifying or distributing, and You must
|
||||
add the title, the copyright date, and the copyright holder's name to the
|
||||
COPYRIGHT NOTICE of any original Open Game Content you Distribute.</P>
|
||||
|
||||
<P>7. Use of Product Identity: You agree not to Use any Product Identity,
|
||||
including as an indication as to compatibility, except as expressly licensed
|
||||
in another, independent Agreement with the owner of each element of that
|
||||
Product Identity. You agree not to indicate compatibility or
|
||||
co-adaptability with any Trademark or Registered Trademark in conjunction with a work containing
|
||||
Open Game Content except as expressly licensed in another, independent
|
||||
Agreement with the owner of such Trademark or Registered Trademark. The use of any Product Identity
|
||||
in Open Game Content does not constitute a challenge to the ownership of
|
||||
that Product Identity. The owner of any Product Identity used in Open Game
|
||||
Content shall retain all rights, title and interest in and to that Product
|
||||
Identity.</P>
|
||||
|
||||
<P>8. Identification: If you distribute Open Game Content You must clearly
|
||||
indicate which portions of the work that you are distributing are Open Game
|
||||
Content.</P>
|
||||
|
||||
<P>9. Updating the License: Wizards or its designated Agents may publish
|
||||
updated versions of this License. You may use any authorized version of
|
||||
this License to copy, modify and distribute any Open Game Content originally
|
||||
distributed under any version of this License.</P>
|
||||
|
||||
<P>10 Copy of this License: You MUST include a copy of this License with every
|
||||
copy of the Open Game Content You Distribute.</P>
|
||||
|
||||
<P>11. Use of Contributor Credits: You may not market or advertise the Open
|
||||
Game Content using the name of any Contributor unless You have written
|
||||
permission from the Contributor to do so.</P>
|
||||
|
||||
<P>12 Inability to Comply: If it is impossible for You to comply with any of
|
||||
the terms of this License with respect to some or all of the Open Game
|
||||
Content due to statute, judicial order, or governmental regulation then You
|
||||
may not Use any Open Game Material so affected.</P>
|
||||
|
||||
<P>13 Termination: This License will terminate automatically if You fail to
|
||||
comply with all terms herein and fail to cure such breach within 30 days of
|
||||
becoming aware of the breach. All sublicenses shall survive the termination
|
||||
of this License.</P>
|
||||
|
||||
<P>14 Reformation: If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent necessary
|
||||
to make it enforceable.</P>
|
||||
|
||||
<P>15 COPYRIGHT NOTICE<br>
|
||||
Open Game License v 1.0 Copyright 2000, Wizards of the Coast, Inc.</P>
|
||||
|
||||
<p>
|
||||
|
||||
<center><a href="./index.html">OGF Main</a></Center>
|
||||
|
||||
</p>
|
||||
|
||||
</body>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Open Game License v0.1 Simplified</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<center><a href="./index.html">OGF Main</a> |
|
||||
<a href="./licenses.html">List of Licenses</a> |
|
||||
Open Game License Text</center>
|
||||
|
||||
<P>THIS LICENSE IS APPROVED FOR GENERAL USE. PERMISSION TO DISTRIBUTE THIS LICENSE
|
||||
IS MADE BY WIZARDS OF THE COAST!</P>
|
||||
|
||||
<P>OPEN GAME LICENSE Version 1.0a</P>
|
||||
|
||||
<P>The following text is the property of Wizards of the Coast, Inc. and is
|
||||
Copyright 2000 Wizards of the Coast, Inc ("Wizards"). All Rights Reserved.</P>
|
||||
|
||||
<P>1. Definitions: (a)"Contributors" means the copyright and/or trademark
|
||||
owners who have contributed Open Game Content; (b)"Derivative Material"
|
||||
means copyrighted material including derivative works and translations
|
||||
(including into other computer languages), potation, modification,
|
||||
correction, addition, extension, upgrade, improvement, compilation,
|
||||
abridgment or other form in which an existing work may be recast,
|
||||
transformed or adapted; (c) "Distribute" means to reproduce, license, rent,
|
||||
lease, sell, broadcast, publicly display, transmit or otherwise distribute;
|
||||
(d)"Open Game Content" means the game mechanic and includes the methods,
|
||||
procedures, processes and routines to the extent such content does not
|
||||
embody the Product Identity and is an enhancement over the prior art and any
|
||||
additional content clearly identified as Open Game Content by the
|
||||
Contributor, and means any work covered by this License, including
|
||||
translations and derivative works under copyright law, but specifically
|
||||
excludes Product Identity. (e) "Product Identity" means product and product
|
||||
line names, logos and identifying marks including trade dress; artifacts;
|
||||
creatures characters; stories, storylines, plots, thematic elements,
|
||||
dialogue, incidents, language, artwork, symbols, designs, depictions,
|
||||
likenesses, formats, poses, concepts, themes and graphic, photographic and
|
||||
other visual or audio representations; names and descriptions of characters,
|
||||
spells, enchantments, personalities, teams, personas, likenesses and special
|
||||
abilities; places, locations, environments, creatures, equipment, magical or
|
||||
supernatural abilities or effects, logos, symbols, or graphic designs; and
|
||||
any other trademark or registered trademark clearly identified as Product
|
||||
identity by the owner of the Product Identity, and which specifically
|
||||
excludes the Open Game Content; (f) "Trademark" means the logos, names,
|
||||
mark, sign, motto, designs that are used by a Contributor to identify itself
|
||||
or its products or the associated products contributed to the Open Game
|
||||
License by the Contributor (g) "Use", "Used" or "Using" means to use,
|
||||
Distribute, copy, edit, format, modify, translate and otherwise create
|
||||
Derivative Material of Open Game Content. (h) "You" or "Your" means the
|
||||
licensee in terms of this agreement.</P>
|
||||
|
||||
<P>2. The License: This License applies to any Open Game Content that contains
|
||||
a notice indicating that the Open Game Content may only be Used under and in
|
||||
terms of this License. You must affix such a notice to any Open Game Content
|
||||
that you Use. No terms may be added to or subtracted from this License
|
||||
except as described by the License itself. No other terms or conditions may
|
||||
be applied to any Open Game Content distributed using this License.</P>
|
||||
|
||||
<P>3.Offer and Acceptance: By Using the Open Game Content You indicate Your
|
||||
acceptance of the terms of this License.</P>
|
||||
|
||||
<P>4. Grant and Consideration: In consideration for agreeing to use this
|
||||
License, the Contributors grant You a perpetual, worldwide, royalty-free,
|
||||
non-exclusive license with the exact terms of this License to Use, the Open
|
||||
Game Content.</P>
|
||||
|
||||
<P>5.Representation of Authority to Contribute: If You are contributing
|
||||
original material as Open Game Content, You represent that Your
|
||||
Contributions are Your original creation and/or You have sufficient rights
|
||||
to grant the rights conveyed by this License.</P>
|
||||
|
||||
<P>6.Notice of License Copyright: You must update the COPYRIGHT NOTICE portion
|
||||
of this License to include the exact text of the COPYRIGHT NOTICE of any
|
||||
Open Game Content You are copying, modifying or distributing, and You must
|
||||
add the title, the copyright date, and the copyright holder's name to the
|
||||
COPYRIGHT NOTICE of any original Open Game Content you Distribute.</P>
|
||||
|
||||
<P>7. Use of Product Identity: You agree not to Use any Product Identity,
|
||||
including as an indication as to compatibility, except as expressly licensed
|
||||
in another, independent Agreement with the owner of each element of that
|
||||
Product Identity. You agree not to indicate compatibility or
|
||||
co-adaptability with any Trademark or Registered Trademark in conjunction with a work containing
|
||||
Open Game Content except as expressly licensed in another, independent
|
||||
Agreement with the owner of such Trademark or Registered Trademark. The use of any Product Identity
|
||||
in Open Game Content does not constitute a challenge to the ownership of
|
||||
that Product Identity. The owner of any Product Identity used in Open Game
|
||||
Content shall retain all rights, title and interest in and to that Product
|
||||
Identity.</P>
|
||||
|
||||
<P>8. Identification: If you distribute Open Game Content You must clearly
|
||||
indicate which portions of the work that you are distributing are Open Game
|
||||
Content.</P>
|
||||
|
||||
<P>9. Updating the License: Wizards or its designated Agents may publish
|
||||
updated versions of this License. You may use any authorized version of
|
||||
this License to copy, modify and distribute any Open Game Content originally
|
||||
distributed under any version of this License.</P>
|
||||
|
||||
<P>10 Copy of this License: You MUST include a copy of this License with every
|
||||
copy of the Open Game Content You Distribute.</P>
|
||||
|
||||
<P>11. Use of Contributor Credits: You may not market or advertise the Open
|
||||
Game Content using the name of any Contributor unless You have written
|
||||
permission from the Contributor to do so.</P>
|
||||
|
||||
<P>12 Inability to Comply: If it is impossible for You to comply with any of
|
||||
the terms of this License with respect to some or all of the Open Game
|
||||
Content due to statute, judicial order, or governmental regulation then You
|
||||
may not Use any Open Game Material so affected.</P>
|
||||
|
||||
<P>13 Termination: This License will terminate automatically if You fail to
|
||||
comply with all terms herein and fail to cure such breach within 30 days of
|
||||
becoming aware of the breach. All sublicenses shall survive the termination
|
||||
of this License.</P>
|
||||
|
||||
<P>14 Reformation: If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent necessary
|
||||
to make it enforceable.</P>
|
||||
|
||||
<P>15 COPYRIGHT NOTICE<br>
|
||||
Open Game License v 1.0 Copyright 2000, Wizards of the Coast, Inc.</P>
|
||||
|
||||
<p>
|
||||
|
||||
<center><a href="./index.html">OGF Main</a></Center>
|
||||
|
||||
</p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
95
package.json
|
@ -1,31 +1,76 @@
|
|||
{
|
||||
"name": "my_spells_5e",
|
||||
"version": "1.0.0",
|
||||
"description": "5e Spells by Class",
|
||||
"main": "",
|
||||
"watch": {
|
||||
"views": "views/*.monk"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "mkdir -p dist && cp node_modules/clipboard/dist/clipboard.min.js dist && cp node_modules/jquery/dist/jquery.min.js dist && cp node_modules/monkberry/monkberry.js dist && cp node_modules/remarkable/dist/remarkable.min.js dist && cp node_modules/getmdl-select/getmdl-select.min.css dist && cp node_modules/getmdl-select/getmdl-select.min.js dist",
|
||||
"views": "monkberry src/views/*.monk --source-map --output dist/view.js",
|
||||
"js": "babel src/app.js --out-file dist/app.js",
|
||||
"develop": "nodemon --watch src -e monk,js --exec 'npm run views && npm run js'"
|
||||
},
|
||||
"author": "Joe Wroten <sharpshark28@gmail.com>",
|
||||
"name": "my_spells",
|
||||
"version": "2.0.5",
|
||||
"description": "My Spells is an open source web-based application to elegantly view spells and save them to your local spellbook.",
|
||||
"author": "Joe Wroten <joe@wroten.me>",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.11.4",
|
||||
"babel-plugin-transform-runtime": "^6.12.0",
|
||||
"babel-preset-es2017": "^1.6.1",
|
||||
"nodemon": "^1.10.0",
|
||||
"npm-watch": "^0.1.5"
|
||||
"scripts": {
|
||||
"clean": "node build/script.clean.js",
|
||||
"dev_web": "node build/process_spells.js --web && node build/script.dev.js ",
|
||||
"dev_app_cordova": "cd cordova && cordova run --device android",
|
||||
"build_web": "node build/process_spells.js --web && node build/script.build.js",
|
||||
"build_app": "node build/process_spells.js && node build/script.build.js",
|
||||
"build_app_cordova": "cd cordova && cordova build --release",
|
||||
"lint": "eslint --ext .js,.vue src"
|
||||
},
|
||||
"dependencies": {
|
||||
"clipboard": "^1.5.12",
|
||||
"getmdl-select": "^1.0.4",
|
||||
"jquery": "^3.1.0",
|
||||
"monkberry": "^4.0.7",
|
||||
"remarkable": "^1.6.2"
|
||||
"babel-runtime": "^6.0.0",
|
||||
"fastclick": "^1.0.6",
|
||||
"json-query-chain": "^1.0.0",
|
||||
"marked": "^0.3.6",
|
||||
"material-design-icons": "^3.0.1",
|
||||
"moment": "^2.15.0",
|
||||
"quasar-framework": "^0.13.4",
|
||||
"roboto-fontface": "^0.7.0",
|
||||
"vue": "^2.3.0",
|
||||
"vue-router": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^6.4.0",
|
||||
"babel-core": "^6.0.0",
|
||||
"babel-eslint": "^7.0.0",
|
||||
"babel-loader": "^7.0.0",
|
||||
"babel-plugin-transform-runtime": "^6.0.0",
|
||||
"babel-preset-es2015": "^6.0.0",
|
||||
"babel-preset-stage-2": "^6.0.0",
|
||||
"colors": "^1.1.2",
|
||||
"connect-history-api-fallback": "^1.1.0",
|
||||
"css-loader": "^0.28.0",
|
||||
"eslint": "^3.0.1",
|
||||
"eslint-config-standard": "^10.2.1",
|
||||
"eslint-friendly-formatter": "^2.0.5",
|
||||
"eslint-loader": "^1.3.0",
|
||||
"eslint-plugin-html": "^2.0.1",
|
||||
"eslint-plugin-import": "^2.2.0",
|
||||
"eslint-plugin-node": "^4.2.2",
|
||||
"eslint-plugin-promise": "^3.3.0",
|
||||
"eslint-plugin-standard": "^3.0.1",
|
||||
"eventsource-polyfill": "^0.9.6",
|
||||
"express": "^4.13.3",
|
||||
"extract-text-webpack-plugin": "^2.0.0-beta.4",
|
||||
"file-loader": "^0.11.1",
|
||||
"friendly-errors-webpack-plugin": "^1.1.3",
|
||||
"fs": "0.0.1-security",
|
||||
"html-webpack-plugin": "^2.8.1",
|
||||
"http-proxy-middleware": "^0.17.0",
|
||||
"json-loader": "^0.5.4",
|
||||
"opn": "^5.0.0",
|
||||
"optimize-css-assets-webpack-plugin": "^1.3.1",
|
||||
"postcss-loader": "^1.0.0",
|
||||
"progress-bar-webpack-plugin": "^1.9.0",
|
||||
"purify-css": "^1.1.9",
|
||||
"shelljs": "^0.7.0",
|
||||
"stylus": "^0.54.5",
|
||||
"stylus-loader": "^3.0.1",
|
||||
"url-loader": "^0.5.7",
|
||||
"vue-loader": "^12.0.2",
|
||||
"vue-style-loader": "^3.0.1",
|
||||
"vue-template-compiler": "^2.3.0",
|
||||
"webpack": "^2.2.1",
|
||||
"webpack-dev-middleware": "^1.8.4",
|
||||
"webpack-hot-middleware": "^2.17.0",
|
||||
"webpack-merge": "^4.0.0",
|
||||
"whatwg-fetch": "^2.0.3",
|
||||
"yargs": "^8.0.2"
|
||||
}
|
||||
}
|
||||
|
|
BIN
src/.DS_Store
vendored
88
src/App.vue
Normal file
|
@ -0,0 +1,88 @@
|
|||
<template>
|
||||
<div id="q-app">
|
||||
<q-layout class="bg-light">
|
||||
<nav-header
|
||||
slot="header"
|
||||
class="toolbar dark"
|
||||
></nav-header>
|
||||
|
||||
<div class="layout-view">
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
|
||||
<nav-footer
|
||||
slot="footer"
|
||||
class="toolbar pink"
|
||||
></nav-footer>
|
||||
</q-layout>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { LocalStorage, Loading, Dialog } from 'quasar'
|
||||
import Vue from 'vue'
|
||||
import 'whatwg-fetch'
|
||||
import { state, dispatch } from './store'
|
||||
import Header from './components/Header'
|
||||
import Footer from './components/Footer'
|
||||
import bakedInSpells from './tmp/spells'
|
||||
|
||||
Vue.component('nav-header', Header)
|
||||
Vue.component('nav-footer', Footer)
|
||||
|
||||
function fetchSuccess (data) {
|
||||
dispatch({
|
||||
type: 'SPELLS_RESOLVED',
|
||||
data: {
|
||||
data,
|
||||
loaded: true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function fetchFailure (reason) {
|
||||
let message = 'Unable to retrieve spells list'
|
||||
Dialog.create({
|
||||
title: 'Error',
|
||||
message,
|
||||
nobuttons: true
|
||||
})
|
||||
console.error(message, reason)
|
||||
}
|
||||
|
||||
function fetchSpells () {
|
||||
console.log('WOW DATA', bakedInSpells)
|
||||
if (bakedInSpells.length) {
|
||||
fetchSuccess(bakedInSpells)
|
||||
Loading.hide()
|
||||
}
|
||||
else {
|
||||
fetch('./statics/spells.json')
|
||||
.then(response => response.json())
|
||||
.then(fetchSuccess)
|
||||
.catch(fetchFailure)
|
||||
.then(() => { Loading.hide() })
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return { state }
|
||||
},
|
||||
mounted () {
|
||||
if (LocalStorage.has('chosen')) {
|
||||
dispatch({type: 'LOAD_LOCAL_CHOSEN'})
|
||||
}
|
||||
|
||||
if (!this.state.spells.loaded) {
|
||||
fetchSpells()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="stylus">
|
||||
.toolbar > .q-picker-textfield
|
||||
margin: 0 .75em
|
||||
</style>
|
435
src/app.js
|
@ -1,435 +0,0 @@
|
|||
/**
|
||||
* Misc helper functions
|
||||
*/
|
||||
Object.values = x =>
|
||||
Object.keys(x).reduce((y, z) =>
|
||||
y.push(x[z]) && y, []);
|
||||
const debounce = (func, wait, immediate) => {
|
||||
let timeout;
|
||||
return function() {
|
||||
let context = this, args = arguments;
|
||||
let later = function() {
|
||||
timeout = null;
|
||||
if (!immediate) func.apply(context, args);
|
||||
};
|
||||
let callNow = immediate && !timeout;
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
if (callNow) func.apply(context, args);
|
||||
};
|
||||
};
|
||||
const el = id => $(`[data-template=${id}]`)[0] || console.error('Unable to render to', id);
|
||||
const clone = obj => JSON.parse(JSON.stringify(obj));
|
||||
const basicDetails = ['level', 'range', 'duration', 'casting_time', 'saving_throw', 'aoe', 'source'];
|
||||
|
||||
/**
|
||||
* Global store and view holders
|
||||
*/
|
||||
let view = {};
|
||||
let store = {
|
||||
systems: {
|
||||
data: [{
|
||||
friendly: 'Dungeons & Dragons 5e',
|
||||
value: 'dnd5e'
|
||||
}, {
|
||||
friendly: 'HackMaster 4e (WIP)',
|
||||
value: 'hackmaster4e'
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* See Matching System Friendly and Value
|
||||
*/
|
||||
const matchingSystemProp = (system, requested) => store.systems.data.find(d => d[requested === 'value' ? 'friendly' : 'value'] === system)[requested];
|
||||
|
||||
/**
|
||||
* Init Local Storage
|
||||
*/
|
||||
const localStorageDefault = (key, val) => {
|
||||
if (localStorage.getItem(key) === null) localStorage.setItem(key, val);
|
||||
};
|
||||
let defaults = {
|
||||
tableSortName: 'name',
|
||||
tableSortRev: false,
|
||||
system: 'dnd5e',
|
||||
classes: [],
|
||||
search: ''
|
||||
};
|
||||
for (let cur in defaults) localStorageDefault(cur, defaults[cur]);
|
||||
|
||||
if (window.location.hash) {
|
||||
let urlSystem = window.location.hash.substr(1).split('/')[0];
|
||||
localStorage.setItem('system', store.systems.data.find(d => d.value === urlSystem).value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render Table Sort
|
||||
*/
|
||||
store.tableSort = {
|
||||
data: ['name', 'school', 'level'],
|
||||
current: localStorage.getItem('tableSortName'),
|
||||
rev: localStorage.getItem('tableSortRev') !== 'false'
|
||||
};
|
||||
view.table_sort = Monkberry.render(table_sort, el('table-sort'));
|
||||
view.table_sort.update(store.tableSort);
|
||||
|
||||
/**
|
||||
* Render Systems
|
||||
*/
|
||||
store.systems.current = matchingSystemProp(localStorage.getItem('system'), 'friendly');
|
||||
view.systems_list = Monkberry.render(system_list, el('system-list'));
|
||||
view.systems_list.update(store.systems);
|
||||
|
||||
/**
|
||||
* Render Spell List
|
||||
*/
|
||||
view.spell_list = Monkberry.render(spell_list, el('spell-list'));
|
||||
view.spell_list.update({data: false});
|
||||
|
||||
/**
|
||||
* Render Spell Print List
|
||||
*/
|
||||
view.spell_list_print = Monkberry.render(spell_list_print, el('spell-list-print'));
|
||||
view.spell_list_print.update({});
|
||||
|
||||
/**
|
||||
* Render Spell Details
|
||||
*/
|
||||
view.spell_details = Monkberry.render(spell_details, el('spell-details'));
|
||||
view.spell_details.update({data: {}});
|
||||
|
||||
/**
|
||||
* Render Class List
|
||||
*/
|
||||
store.classes = {
|
||||
data: [],
|
||||
current: localStorage.getItem('classes') ? localStorage.getItem('classes').split(',') : []
|
||||
};
|
||||
view.class_list = Monkberry.render(class_list, el('class-list'));
|
||||
view.class_list.update({data: false});
|
||||
|
||||
/**
|
||||
* Render Search
|
||||
*/
|
||||
store.search = localStorage.getItem('search');
|
||||
view.search_field = Monkberry.render(search_field, el('search-field'));
|
||||
view.search_field.update({data: store.search});
|
||||
|
||||
/**
|
||||
* Discover Classes
|
||||
*/
|
||||
const discoverClasses = spells => {
|
||||
let classes = [];
|
||||
spells.forEach(spell => {
|
||||
if (!spell.classes) return;
|
||||
spell.classes.forEach(current => {
|
||||
if (!classes.includes(current)) classes.push(current);
|
||||
});
|
||||
});
|
||||
return classes.sort((a, b) => a > b);
|
||||
};
|
||||
|
||||
/**
|
||||
* Emphasis on important string bits
|
||||
* @param {string} string
|
||||
*/
|
||||
const emphasis = (str = '') => {
|
||||
let keywords = ['constitution', 'con', 'intelligence', 'int', 'wisdom', 'wis', 'strength', 'str', 'dexterity', 'dex', 'charisma', 'cha', 'comeliness', 'com', 'saving throw', 'ability check', 'skill check'];
|
||||
keywords.forEach(word => {
|
||||
let r = new RegExp(` ${word} `, 'gi');
|
||||
str = str.replace(r, o => ` _${o.trim()}_ `);
|
||||
});
|
||||
|
||||
str = str.replace(/[\s()<>]+\d+d*\d*(th)*[\s()<>]+/gi, o => ` **${o.trim()}** `);
|
||||
return str;
|
||||
};
|
||||
|
||||
/**
|
||||
* Description Prettifier
|
||||
*/
|
||||
const descriptionPrettifier = description => {
|
||||
let md = new Remarkable();
|
||||
description = Array.isArray(description) ? description.join('\n') : description;
|
||||
description = emphasis(description);
|
||||
description = md.render(description);
|
||||
description = description.replace(/\n/g, '<br>');
|
||||
|
||||
return description;
|
||||
};
|
||||
|
||||
/**
|
||||
* Init Spells
|
||||
*/
|
||||
const initSpells = s => s.map((spell, i) => {
|
||||
spell.selected = false;
|
||||
spell.ranking = 0;
|
||||
spell.level = parseInt(spell.level) ? spell.level : 0;
|
||||
return spell;
|
||||
});
|
||||
|
||||
/**
|
||||
* Sort Spells
|
||||
*/
|
||||
const sortSpells = (s, sortBy, reverse) => s.sort((a, b) => {
|
||||
let hasFilters = store.classes.current.length || store.search.length;
|
||||
let by = sortBy || hasFilters ? 'ranking' : store.tableSort.current;
|
||||
let rev = reverse || hasFilters ? false : store.tableSort.rev;
|
||||
if (by) {
|
||||
if (a[by] < b[by]) return rev ? 1 : -1;
|
||||
if (a[by] > b[by]) return rev ? -1 : 1;
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Search Spells
|
||||
* @param {Array} spells
|
||||
* @param {String} ex 'acid spray'
|
||||
* @return {Array} filtered spells
|
||||
*/
|
||||
const searchSpells = (spells, search) => {
|
||||
// Convert search to array of words
|
||||
search = search.split(' ');
|
||||
// Clone spells so we don't affect the original
|
||||
spells = clone(spells);
|
||||
// Reset rankings
|
||||
spells = spells.map(s => {
|
||||
s.ranking = 0;
|
||||
return s;
|
||||
});
|
||||
// Rank spells by # of occurances of search terms
|
||||
spells = spells.map(spell => {
|
||||
search.forEach(term => {
|
||||
let spellText = Object.values(spell).join(' ');
|
||||
let regFind = new RegExp(term, 'gi');
|
||||
spell.ranking += (spellText.match(regFind) || []).length;
|
||||
});
|
||||
return spell;
|
||||
});
|
||||
// Return spells that matched at least something
|
||||
return spells.filter(spell => spell.ranking);
|
||||
};
|
||||
|
||||
/**
|
||||
* Filter Spells by Class
|
||||
*/
|
||||
const filterSpellsByClass = (spells, classes) => {
|
||||
// If no classes, default to all classes
|
||||
classes = classes.length ? classes : store.classes.data;
|
||||
// Clone spells so we don't affect the original
|
||||
spells = clone(spells);
|
||||
return spells.filter(spell => {
|
||||
let spellClasses = spell.classes.join(' ');
|
||||
let match = false;
|
||||
classes.forEach(c => {
|
||||
if (spellClasses.indexOf(c) >= 0) {
|
||||
match = true;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return match;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply Filters
|
||||
* @returns {Array} of spells ranked based on searches and filters
|
||||
*/
|
||||
let applyFilters = () => sortSpells(
|
||||
searchSpells(
|
||||
filterSpellsByClass(
|
||||
store.spells,
|
||||
store.classes.current
|
||||
),
|
||||
store.search
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Spell Details Updating
|
||||
*/
|
||||
const spellDetails = name => {
|
||||
if (!name) {
|
||||
view.spell_details.update({data: {}});
|
||||
$('body').removeClass('details');
|
||||
} else {
|
||||
let data = clone(store.spells.find(spell => name === spell.name));
|
||||
data.description = descriptionPrettifier(data.description);
|
||||
data.details = basicDetails.map(detail => {
|
||||
if (data[detail]) {
|
||||
return {
|
||||
label: detail.replace('_', ' '),
|
||||
value: data[detail]
|
||||
};
|
||||
}
|
||||
});
|
||||
if (data.components && data.components.raw) {
|
||||
data.details.push({label: 'components', value: data.components.raw});
|
||||
}
|
||||
|
||||
view.spell_details.update({
|
||||
data,
|
||||
url: window.location.href
|
||||
});
|
||||
componentHandler.upgradeDom();
|
||||
$('body').addClass('details');
|
||||
let clipboard = new Clipboard('.copy-to-clipboard');
|
||||
clipboard
|
||||
.on('success', e => $('#toast')[0].MaterialSnackbar.showSnackbar({message: 'Copied link'}))
|
||||
.on('error', e => $('#toast')[0].MaterialSnackbar.showSnackbar({message: 'Sorry! Unable to copy link'}));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render Print Page
|
||||
*/
|
||||
const renderPrint = () => {
|
||||
let selectedSpells = $('form[data-selected]')
|
||||
// Get array of items in form
|
||||
.serializeArray()
|
||||
// Find spells based on array from form
|
||||
.map(sel => store.spells.find(spell => sel.value === spell.name))
|
||||
// Sort by level then alphabetically
|
||||
.sort((a, b) => {
|
||||
let aName = a.name.toLowerCase();
|
||||
let bName = b.name.toLowerCase();
|
||||
if (a.level > b.level) return 1;
|
||||
if (a.level < b.level) return -1;
|
||||
if (aName > bName) return 1;
|
||||
if (aName < bName) return -1;
|
||||
return 0;
|
||||
})
|
||||
// Prettify Descriptions
|
||||
.map(spell => {
|
||||
spell = clone(spell);
|
||||
spell.description = descriptionPrettifier(spell.description);
|
||||
spell.details = basicDetails.map(detail => {
|
||||
if (spell[detail]) {
|
||||
return {
|
||||
label: detail.replace('_', ' '),
|
||||
value: spell[detail]
|
||||
};
|
||||
}
|
||||
});
|
||||
if (spell.components && spell.components.raw) {
|
||||
spell.details.push({label: 'components', value: spell.components.raw});
|
||||
}
|
||||
return spell;
|
||||
});
|
||||
view.spell_list_print.update({data: selectedSpells});
|
||||
if (selectedSpells.length) {
|
||||
$('[data-action=print] [data-badge]').attr('data-badge', selectedSpells.length);
|
||||
$('[data-action=print]').slideDown('fast');
|
||||
} else {
|
||||
$('[data-action=print]').slideUp('fast');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Event Bindings
|
||||
*/
|
||||
$('body')
|
||||
// Listen for header sorts
|
||||
.on('click', '[data-action-sort]', e => {
|
||||
let name = $(e.currentTarget).attr('data-action-sort');
|
||||
let rev = store.tableSort.current === name && !store.tableSort.rev;
|
||||
store.tableSort.current = name;
|
||||
store.tableSort.rev = rev;
|
||||
localStorage.setItem('tableSortName', name);
|
||||
localStorage.setItem('tableSortRev', rev);
|
||||
view.spell_list.update({data: sortSpells(store.spells)});
|
||||
view.table_sort.update(store.tableSort);
|
||||
componentHandler.upgradeDom();
|
||||
})
|
||||
// Listen for checkbox changes to filter spells
|
||||
.on('change', '[data-action-classtoggle]', e => {
|
||||
let name = $(e.currentTarget).attr('data-action-classtoggle');
|
||||
let add = $(e.currentTarget).prop('checked');
|
||||
let index = store.classes.current.indexOf(name);
|
||||
if (index === -1 && add) {
|
||||
store.classes.current.push(name);
|
||||
} else if (!add) store.classes.current.splice(index, 1);
|
||||
store.tableSort.current = store.classes.current.length || store.search.length ? 'ranking' : null;
|
||||
localStorage.setItem('tableSortName', store.tableSort.current);
|
||||
localStorage.setItem('classes', store.classes.current);
|
||||
view.spell_list.update({data: applyFilters()});
|
||||
view.table_sort.update({current: store.tableSort.current});
|
||||
componentHandler.upgradeDom();
|
||||
})
|
||||
// Listen to search to filter by
|
||||
.on('change keyup cut paste', '[data-action-search]', e => {
|
||||
setTimeout(() => { // Delay for value to change
|
||||
store.search = $(e.currentTarget).val();
|
||||
store.tableSort.current = store.search.length || store.classes.current.length ? 'ranking' : null;
|
||||
store.tableSort.rev = false;
|
||||
localStorage.setItem('search', store.search);
|
||||
localStorage.setItem('tableSortName', store.tableSort.current);
|
||||
localStorage.setItem('tableSortRev', store.tableSort.rev);
|
||||
view.spell_list.update({data: applyFilters()});
|
||||
view.table_sort.update(store.tableSort);
|
||||
componentHandler.upgradeDom();
|
||||
}, 0);
|
||||
})
|
||||
// Listen for click on spells to open details
|
||||
.on('click', '[data-action-details]', e => {
|
||||
let name = $(e.currentTarget).attr('data-action-details');
|
||||
if (name) {
|
||||
window.location.hash = matchingSystemProp(store.systems.current, 'value') + '/' + name;
|
||||
} else {
|
||||
window.location.hash = '';
|
||||
}
|
||||
spellDetails(name);
|
||||
})
|
||||
// Stop propogation if dontprop clicked
|
||||
.on('click', '.dontprop', e => {
|
||||
e.stopPropagation();
|
||||
})
|
||||
// Toggle All
|
||||
.on('change', 'label[for=table-header] input[type=checkbox]', e => {
|
||||
$(e.target).closest('form').find('[name=selected]').each(function() {
|
||||
this.checked = e.target.checked;
|
||||
if(this.checked) $(this).closest('label').addClass('is-checked');
|
||||
else $(this).closest('label').removeClass('is-checked');
|
||||
});
|
||||
renderPrint();
|
||||
})
|
||||
.on('change', 'input[name=selected][type=checkbox]', renderPrint)
|
||||
.on('click', '[data-action=print]', e => {
|
||||
window.print();
|
||||
});
|
||||
// Article Scroll with User
|
||||
$('.mdl-layout__content').on('scroll', debounce(() => {
|
||||
let distance = $('.mdl-layout__content')[0].scrollTop;
|
||||
$('[data-template=spell-details]').css('margin-top', distance);
|
||||
}, 10));
|
||||
// System changed
|
||||
$('[data-action=system]').on('change', e => {
|
||||
let system = $(e.currentTarget).val();
|
||||
let systemValue = matchingSystemProp(system, 'value');
|
||||
window.location.hash = '';
|
||||
spellDetails('');
|
||||
store.systems.current = system;
|
||||
localStorage.setItem('system', systemValue);
|
||||
view.spell_list.update({data: false});
|
||||
view.class_list.update({data: false});
|
||||
fetchSpells(systemValue);
|
||||
})
|
||||
|
||||
/**
|
||||
* Fetch Spells
|
||||
*/
|
||||
const fetchSpells = (system = matchingSystemProp(store.systems.current, 'value')) => fetch(`./systems/${system}.json`)
|
||||
.then(response => response.json())
|
||||
.then(spells => initSpells(spells))
|
||||
.then(spells => {
|
||||
store.spells = spells;
|
||||
store.classes.data = discoverClasses(spells);
|
||||
view.spell_list.update({data: applyFilters()});
|
||||
view.class_list.update(store.classes);
|
||||
componentHandler.upgradeDom();
|
||||
if (window.location.hash) spellDetails(window.location.hash.substr(1).split('/')[1]);
|
||||
return spells;
|
||||
})
|
||||
.catch(reason => console.error('Unable to retrieve spells list:', reason));
|
||||
fetchSpells();
|
72
src/components/About.vue
Normal file
|
@ -0,0 +1,72 @@
|
|||
<template>
|
||||
<main class="content">
|
||||
<h1>About</h1>
|
||||
<p>
|
||||
My Spells is an <a href="https://github.com/sharpshark28/my_spells"><i>code</i> open source</a>
|
||||
web-based application to elegantly view spells and save them to your local spellbook.
|
||||
</p>
|
||||
|
||||
<h2>Settings</h2>
|
||||
<button
|
||||
class="primary"
|
||||
v-on:click="wipeChosen"
|
||||
:disabled="disableChosen"
|
||||
>
|
||||
<i class="on-left">delete</i>
|
||||
Reset Spellbook
|
||||
</button>
|
||||
|
||||
<h2>License</h2>
|
||||
<p>
|
||||
Open Game License v1.0a Copyright 2000, Wizards of the Coast, Inc.
|
||||
</p>
|
||||
<p>
|
||||
App contains content from the SRD and is restricted and covered by the OGL. You can find the OGL 1.0a at ogl.html in this app's repo, or <a href="http://www.opengamingfoundation.org/ogl.html">online here</a>. When using said data, please make sure to conform appropriately with the proper licenses and whatnot.
|
||||
</p>
|
||||
|
||||
<h2>Credit</h2>
|
||||
<ul>
|
||||
<li>
|
||||
ephe's <a href="https://github.com/ephe/grimoire/">grimoire</a> spell list converted json by vorpalhex and cleaned up to meet OGL license standards <a href="https://github.com/vorpalhex/srd_spells">labeled under srd_spells</a>
|
||||
<li>
|
||||
Built on <a href="https://vuejs.org/">Vue.js</a>
|
||||
and the <a href="http://quasar-framework.org/">Quasar Framework</a>
|
||||
</li>
|
||||
<li>
|
||||
Logo magic wand icon by David from the Noun Project
|
||||
</li>
|
||||
</ul>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Toast } from 'quasar'
|
||||
import { dispatch, state } from '../store'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return { state }
|
||||
},
|
||||
computed: {
|
||||
disableChosen () {
|
||||
return this.state.chosen.length === 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
wipeChosen () {
|
||||
dispatch({
|
||||
type: 'WIPE_CHOSEN'
|
||||
})
|
||||
Toast.create({
|
||||
html: 'Spellbook Reset'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="stylus">
|
||||
main
|
||||
padding: 0 2em
|
||||
max-width: 40rem
|
||||
</style>
|
31
src/components/Empty.vue
Normal file
|
@ -0,0 +1,31 @@
|
|||
<template>
|
||||
<div class="empty text-center">
|
||||
<h1>
|
||||
{{title}}
|
||||
</h1>
|
||||
<p>
|
||||
<slot>
|
||||
This page is empty.
|
||||
</slot>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data () {
|
||||
return {}
|
||||
},
|
||||
props: [
|
||||
'title'
|
||||
]
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="stylus">
|
||||
.empty
|
||||
height: 100%
|
||||
background-image: url('/statics/empty-bg.svg')
|
||||
background-repeat: no-repeat
|
||||
background-position: top center
|
||||
</style>
|
58
src/components/Error404.vue
Normal file
|
@ -0,0 +1,58 @@
|
|||
<template>
|
||||
<div class="error-page window-height window-width bg-light column items-center">
|
||||
<div class="error-code bg-primary flex items-center justify-center">
|
||||
404
|
||||
</div>
|
||||
<div>
|
||||
<div class="error-card card bg-white column items-center justify-center">
|
||||
<i class="text-grey-5">error_outline</i>
|
||||
<p class="caption text-center">Oops. Nothing here...</p>
|
||||
<p class="text-center group">
|
||||
<button v-if="canGoBack" class="grey push small" @click="goBack">
|
||||
<i class="on-left">keyboard_arrow_left</i>
|
||||
Go back
|
||||
</button>
|
||||
<router-link to="/">
|
||||
<button class="grey push small">
|
||||
Go home
|
||||
<i class="on-right">home</i>
|
||||
</button>
|
||||
</router-link>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
canGoBack: window.history.length > 1
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goBack () {
|
||||
window.history.go(-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
.error-page
|
||||
.error-code
|
||||
height 50vh
|
||||
width 100%
|
||||
padding-top 15vh
|
||||
font-size 30vmax
|
||||
color rgba(255, 255, 255, .2)
|
||||
overflow hidden
|
||||
.error-card
|
||||
margin-top -25px
|
||||
width 90vw
|
||||
max-width 600px
|
||||
padding 50px
|
||||
i
|
||||
font-size 5rem
|
||||
</style>
|
67
src/components/Filter.vue
Normal file
|
@ -0,0 +1,67 @@
|
|||
<template>
|
||||
<div class="row">
|
||||
<q-select
|
||||
type="list"
|
||||
v-model="state.sortBy"
|
||||
:options="sortByOptions"
|
||||
></q-select>
|
||||
|
||||
<q-search
|
||||
v-model="state.search"
|
||||
@input="searchChanged"
|
||||
></q-search>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { state, dispatch } from '../store'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return { state }
|
||||
},
|
||||
computed: {
|
||||
sortByOptions () {
|
||||
let options = [
|
||||
{
|
||||
label: 'Name',
|
||||
value: 'name'
|
||||
},
|
||||
{
|
||||
label: 'Level',
|
||||
value: 'level'
|
||||
}
|
||||
]
|
||||
|
||||
if (this.state.search.length >= 3) {
|
||||
options.unshift({
|
||||
label: 'Relevance',
|
||||
value: 'sortScore'
|
||||
})
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
searchChanged (newSearch) {
|
||||
if (newSearch.length >= 3) {
|
||||
this.state.previousSortBy = this.state.sortBy
|
||||
this.state.sortBy = 'sortScore'
|
||||
}
|
||||
else {
|
||||
this.state.sortBy = this.state.previousSortBy
|
||||
}
|
||||
|
||||
dispatch({ type: 'SEARCH_CHANGED' })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="stylus">
|
||||
.row
|
||||
padding: 1em
|
||||
.q-picker-textfield
|
||||
margin-right: 1em
|
||||
</style>
|
57
src/components/Footer.vue
Normal file
|
@ -0,0 +1,57 @@
|
|||
<template>
|
||||
<footer>
|
||||
<q-tabs
|
||||
class="pink justified"
|
||||
:refs="$refs"
|
||||
default-tab="tab-all"
|
||||
>
|
||||
<q-tab
|
||||
icon="local_library"
|
||||
route="/"
|
||||
exact
|
||||
>
|
||||
All Spells
|
||||
</q-tab>
|
||||
<q-tab
|
||||
icon="bookmark"
|
||||
route="/my"
|
||||
exact
|
||||
>
|
||||
My Spells
|
||||
<span
|
||||
class="label pointing-left bg-yellow text-dark"
|
||||
v-show="state.chosen.length"
|
||||
>{{state.chosen.length}}</span>
|
||||
</q-tab>
|
||||
<q-tab
|
||||
hidden
|
||||
route="/spell"
|
||||
>
|
||||
Spell
|
||||
</q-tab>
|
||||
<q-tab
|
||||
hidden
|
||||
route="/about"
|
||||
>
|
||||
About
|
||||
</q-tab>
|
||||
</q-tabs>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { state } from '../store'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return { state }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="stylus">
|
||||
footer .q-tabs
|
||||
width: 100%
|
||||
.pointing-left:before
|
||||
transform: translateX(-50%) translateY(-50%) rotate(225deg)
|
||||
</style>
|
45
src/components/Header.vue
Normal file
|
@ -0,0 +1,45 @@
|
|||
<template>
|
||||
<div>
|
||||
<q-toolbar-title :padding="0">
|
||||
<router-link
|
||||
to="/my"
|
||||
class="text-white"
|
||||
>
|
||||
<img class="logo" src="statics/logo.svg" alt="" />
|
||||
My Spells
|
||||
<small>5e Personal Spellbook</small>
|
||||
</router-link>
|
||||
</q-toolbar-title>
|
||||
|
||||
<router-link
|
||||
to="/about"
|
||||
tag="button"
|
||||
>
|
||||
<i>help</i>
|
||||
<q-tooltip
|
||||
anchor="bottom right"
|
||||
self="top right"
|
||||
>
|
||||
About
|
||||
</q-tooltip>
|
||||
</router-link>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { state } from '../store'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
state
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="stylus">
|
||||
.logo
|
||||
height: 1.25em
|
||||
vertical-align: middle
|
||||
</style>
|
35
src/components/Index.vue
Normal file
|
@ -0,0 +1,35 @@
|
|||
<template>
|
||||
<main>
|
||||
<spell-list
|
||||
v-if="state.indexedSpells.length"
|
||||
:spells="state.indexedSpells"
|
||||
></spell-list>
|
||||
<page-empty
|
||||
v-else
|
||||
title="Writing Spellbook..."
|
||||
>
|
||||
Please wait...
|
||||
</page-empty>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue'
|
||||
import Empty from './Empty'
|
||||
import SpellList from './Spelllist'
|
||||
import { state } from '../store'
|
||||
|
||||
Vue.component('page-empty', Empty)
|
||||
Vue.component('spell-list', SpellList)
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return { state }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="stylus">
|
||||
main
|
||||
height: 90%
|
||||
</style>
|
49
src/components/Myspells.vue
Normal file
|
@ -0,0 +1,49 @@
|
|||
<template>
|
||||
<main>
|
||||
<spell-list
|
||||
v-if="mySpells.length"
|
||||
:spells="mySpells"
|
||||
></spell-list>
|
||||
<page-empty
|
||||
v-else
|
||||
title="You haven't chosen any spells"
|
||||
>
|
||||
Try <span class="text-pink"><i>bookmark</i> Bookmarking</span> spells from the
|
||||
<router-link to="/">all spells page</router-link> to add to your spellbook.
|
||||
</page-empty>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue'
|
||||
import Empty from './Empty'
|
||||
import SpellList from './Spelllist'
|
||||
import { state } from '../store'
|
||||
|
||||
Vue.component('page-empty', Empty)
|
||||
Vue.component('spell-list', SpellList)
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return { state }
|
||||
},
|
||||
computed: {
|
||||
mySpells () {
|
||||
if (!this.state.spells.loaded || this.state.chosen.length === 0) {
|
||||
return []
|
||||
}
|
||||
|
||||
return this.state.chosen.map(chosen => {
|
||||
return this.state.indexedSpells.find(spell => {
|
||||
return spell.id === chosen
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="stylus">
|
||||
main
|
||||
height: 90%
|
||||
</style>
|
166
src/components/Spell.vue
Normal file
|
@ -0,0 +1,166 @@
|
|||
<template>
|
||||
<div class="page-spell">
|
||||
<button
|
||||
v-go-back=" '/' "
|
||||
class="page-back-small primary shadow-1"
|
||||
>
|
||||
<i>arrow_back</i>
|
||||
Back
|
||||
</button>
|
||||
|
||||
<div class="card bg-white">
|
||||
<div class="card-title bg-pink text-white">
|
||||
{{spell.name}}
|
||||
<span class="label bg-white text-pink">
|
||||
Level {{level}}
|
||||
</span>
|
||||
|
||||
<q-checkbox
|
||||
class="float-right pink"
|
||||
v-model="checked"
|
||||
@input="toggle"
|
||||
></q-checkbox>
|
||||
<i
|
||||
class="bookmark float-right text-yellow pointer"
|
||||
v-if="checked"
|
||||
v-on:click="checked = false"
|
||||
>bookmark</i>
|
||||
<i
|
||||
class="bookmark float-right text-grey-5 pointer"
|
||||
v-else
|
||||
v-on:click="checked = true"
|
||||
>bookmark_border</i>
|
||||
</div>
|
||||
<ol class="list no-border">
|
||||
<li class="item">
|
||||
<i class="item-primary">short_text</i>
|
||||
<div
|
||||
class="item-content description"
|
||||
v-html="prettyDescription"
|
||||
></div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<i class="item-primary">accessibility</i>
|
||||
<div class="item-content">
|
||||
{{classes}}
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<i class="item-primary">group_work</i>
|
||||
<div class="item-content">
|
||||
{{spell.components.raw}}
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<i class="item-primary">school</i>
|
||||
<div class="item-content">
|
||||
{{spell.school}}
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<i class="item-primary">hourglass_full</i>
|
||||
<div class="item-content">
|
||||
{{spell.duration}}
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<i class="item-primary">av_timer</i>
|
||||
<div class="item-content">
|
||||
{{spell.casting_time}}
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Loading } from 'quasar'
|
||||
import { dispatch, state } from '../store'
|
||||
import { capitalize } from '../utils'
|
||||
import Marked from 'marked'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return { state }
|
||||
},
|
||||
mounted () {
|
||||
let scrollingPageElement = document.getElementsByClassName('layout-view')[0]
|
||||
scrollingPageElement.scrollTop = 0
|
||||
|
||||
if (this.state.spells.loaded === false) {
|
||||
Loading.show()
|
||||
}
|
||||
|
||||
this.state.lastSpell = this.spell.id
|
||||
},
|
||||
computed: {
|
||||
checked () {
|
||||
return this.state.chosen.indexOf(this.spell.id) >= 0
|
||||
},
|
||||
spell () {
|
||||
return this.state.spells.data.find(spell => spell.id === this.$route.params.id)
|
||||
},
|
||||
level () {
|
||||
return this.spell.level.toLowerCase() === 'cantrip' ? 'C' : this.spell.level
|
||||
},
|
||||
classes () {
|
||||
return this.spell.classes.map(cla => capitalize(cla)).join(', ')
|
||||
},
|
||||
prettyDescription () {
|
||||
let newDescription = this.spell.description
|
||||
let keywords = ['constitution', 'con', 'intelligence', 'int', 'wisdom', 'wis', 'strength', 'str', 'dexterity', 'dex', 'charisma', 'cha', 'comeliness', 'com', 'saving throw', 'ability check', 'skill check']
|
||||
keywords.forEach(word => {
|
||||
let r = new RegExp(` ${word} `, 'gi')
|
||||
newDescription = newDescription.replace(r, o => ` _${o.trim()}_ `)
|
||||
})
|
||||
|
||||
newDescription = newDescription.replace(/[\s()<>]+\d+d*\d*(th)*[\s()<>]+/gi, o => ` **${o.trim()}** `)
|
||||
return Marked(newDescription)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggle (want) {
|
||||
dispatch({
|
||||
type: 'CHANGE_CHOSEN',
|
||||
data: {
|
||||
want,
|
||||
id: this.spell.id
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="stylus">
|
||||
.pointer
|
||||
cursor: pointer
|
||||
.page-spell
|
||||
width: 100%
|
||||
height: 100%
|
||||
position: relative
|
||||
padding: 1rem
|
||||
.page-back-small
|
||||
margin-bottom: 1rem
|
||||
.page-back-big
|
||||
display: none
|
||||
.card
|
||||
margin: 0 auto
|
||||
max-width: 40rem
|
||||
.description
|
||||
padding-bottom: 0
|
||||
.card-title .label
|
||||
margin-left: .5em
|
||||
.list
|
||||
padding-left: 16px
|
||||
.item
|
||||
height: auto
|
||||
.item-primary
|
||||
margin: 12px 0
|
||||
.item-content
|
||||
margin-left: 50px
|
||||
.bookmark
|
||||
font-size: 1.25em
|
||||
line-height: 1em
|
||||
</style>
|
98
src/components/Spellitem.vue
Normal file
|
@ -0,0 +1,98 @@
|
|||
<template>
|
||||
<div v-bind:class="{'checked': checked}">
|
||||
<div class="item-primary">
|
||||
{{spell.level}}
|
||||
</div>
|
||||
<div class="item-content has-secondary">
|
||||
<router-link :to="spell.link">
|
||||
<span class="spell-link-alignment">
|
||||
<span class="spell-name">
|
||||
{{spell.name}}
|
||||
</span>
|
||||
<br />
|
||||
<span class="spell-classes">
|
||||
{{classes}}
|
||||
</span>
|
||||
</span>
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="item-secondary" v-on:click="toggle">
|
||||
<i
|
||||
class="float-left text-pink bookmark checked"
|
||||
v-if="checked"
|
||||
>bookmark</i>
|
||||
<i
|
||||
class="float-left text-grey-7 bookmark"
|
||||
v-else
|
||||
>bookmark_border</i>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { state, dispatch } from '../store'
|
||||
import { capitalize } from '../utils'
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
school () {
|
||||
return capitalize(this.spell.school)
|
||||
},
|
||||
classes () {
|
||||
return this.spell.classes.map(cla => capitalize(cla)).join(', ')
|
||||
},
|
||||
checked () {
|
||||
return this.state.chosen.indexOf(this.spell.id) >= 0
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return { state }
|
||||
},
|
||||
props: [
|
||||
'spell'
|
||||
],
|
||||
methods: {
|
||||
toggle () {
|
||||
dispatch({
|
||||
type: 'CHANGE_CHOSEN',
|
||||
data: {
|
||||
want: !this.checked,
|
||||
id: this.spell.id
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="stylus">
|
||||
.spell-classes
|
||||
color: rgba(0, 0, 0, .54)
|
||||
.item.two-lines > .item-content
|
||||
height: 100%
|
||||
padding: 0
|
||||
a
|
||||
color: black
|
||||
display: table
|
||||
height: 100%
|
||||
width: 100%
|
||||
.spell-link-alignment
|
||||
display: table-cell
|
||||
vertical-align: middle
|
||||
.item-secondary
|
||||
width: 50px
|
||||
height: 50px
|
||||
margin: 0
|
||||
padding: 12px
|
||||
.bookmark
|
||||
transition: transform .25s ease
|
||||
&:hover,
|
||||
&:target
|
||||
.bookmark
|
||||
transform: scale(1.5)
|
||||
.bookmark:not(.checked)
|
||||
color: yellow !important
|
||||
&:active
|
||||
.bookmark:not(.checked)
|
||||
color: deeppink !important
|
||||
</style>
|
60
src/components/Spelllist.vue
Normal file
|
@ -0,0 +1,60 @@
|
|||
<template>
|
||||
<div class="spell-list-container">
|
||||
<nav-filter></nav-filter>
|
||||
<section
|
||||
class="spell-list list striped no-border"
|
||||
id="spell_list"
|
||||
>
|
||||
<label
|
||||
is="spell-item"
|
||||
class="item two-lines item-link"
|
||||
v-for="spell in filteredSpells"
|
||||
:key="spell.id"
|
||||
:ref="spell.id"
|
||||
:spell="spell"
|
||||
>
|
||||
</label>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue'
|
||||
import Query from 'json-query-chain'
|
||||
import Filter from './Filter'
|
||||
import SpellItem from './Spellitem'
|
||||
import { state } from '../store'
|
||||
|
||||
Vue.component('nav-filter', Filter)
|
||||
Vue.component('spell-item', SpellItem)
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return { state }
|
||||
},
|
||||
props: [ 'spells' ],
|
||||
mounted () {
|
||||
if (this.state.lastSpell) {
|
||||
let lastSpellPosition = this.$refs[this.state.lastSpell][0].$el.offsetTop
|
||||
let scrollingPageElement = document.getElementsByClassName('layout-view')[0]
|
||||
scrollingPageElement.scrollTop = lastSpellPosition
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
filteredSpells () {
|
||||
let spells = this.spells
|
||||
return new Query(spells)
|
||||
.search('name', this.state.search)
|
||||
.sort(this.state.sortBy)
|
||||
.results
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
.list.striped .item:nth-child(2n).checked
|
||||
background: #fff9c4
|
||||
.list.striped .item:nth-child(2n+1).checked
|
||||
background: #fffde7
|
||||
</style>
|
16
src/index.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="msapplication-tap-highlight" content="no">
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
|
||||
|
||||
<title>My Spells DnD5e</title>
|
||||
<link rel="shortcut icon" type="image/x-icon" href="statics/favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<div id="q-app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
22
src/main.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
// === DEFAULT / CUSTOM STYLE ===
|
||||
// WARNING! always comment out ONE of the two require() calls below.
|
||||
// 1. use next line to activate CUSTOM STYLE (./src/themes)
|
||||
// require(`./themes/app.${__THEME}.styl`)
|
||||
// 2. or, use next line to activate DEFAULT QUASAR STYLE
|
||||
require(`quasar/dist/quasar.${__THEME}.css`)
|
||||
// ==============================
|
||||
|
||||
import Vue from 'vue'
|
||||
import Quasar from 'quasar'
|
||||
import router from './router'
|
||||
|
||||
Vue.use(Quasar) // Install Quasar Framework
|
||||
|
||||
Quasar.start(() => {
|
||||
/* eslint-disable no-new */
|
||||
new Vue({
|
||||
el: '#q-app',
|
||||
router,
|
||||
render: h => h(require('./App'))
|
||||
})
|
||||
})
|
30
src/router.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
import Vue from 'vue'
|
||||
import VueRouter from 'vue-router'
|
||||
|
||||
Vue.use(VueRouter)
|
||||
|
||||
function load (component) {
|
||||
return () => System.import(`components/${component}.vue`)
|
||||
}
|
||||
|
||||
export default new VueRouter({
|
||||
/*
|
||||
* NOTE! VueRouter "history" mode DOESN'T works for Cordova builds,
|
||||
* it is only to be used only for websites.
|
||||
*
|
||||
* If you decide to go with "history" mode, please also open /config/index.js
|
||||
* and set "build.publicPath" to something other than an empty string.
|
||||
* Example: '/' instead of current ''
|
||||
*
|
||||
* If switching back to default "hash" mode, don't forget to set the
|
||||
* build publicPath back to '' so Cordova builds work again.
|
||||
*/
|
||||
|
||||
routes: [
|
||||
{ path: '/', component: load('Index') }, // Default
|
||||
{ path: '/my', component: load('Myspells') },
|
||||
{ path: '/spell/:id', component: load('Spell') },
|
||||
{ path: '/about', component: load('About') },
|
||||
{ path: '*', component: load('Error404') } // Not found
|
||||
]
|
||||
})
|
|
@ -6178,7 +6178,7 @@
|
|||
"description": "Objects come to life at your command. Choose up to ten nonmagical objects within range that are not being worn or carried. Medium targets count as two objects, Large targets count as four objects, Huge targets count as eight objects. You can't animate any object larger than Huge. Each target animates and becomes a creature under your control until the spell ends or until reduced to 0 hit points.\n\nAs a bonus action, you can mentally command any creature you made with this spell if the creature is within 500 feet of you (if you control multiple creatures, you can command any or all of them at the same time, issuing the same command to each one). You decide what action the creature will take and where it will move during its next turn, or you can issue a general command, such as to guard a particular chamber or corridor. If you issue no commands, the creature only defends itself against hostile creatures. Once given an order, the creature continues to follow it until its task is complete.\n\n| Size | HP | AC | Attack | Str | Dex |\n\n| Tiny | 20 | 18 | +8 to hit, 1d4+4 damage | 4 | 18 |\n\n| Small | 25 | 16 | +6 to hit, 1d8+2 damage | 6 | 14 |\n\n| Medium | 40 | 13 | +5 to hit, 2d6+1 damage | 10 | 12 |\n\n| Large | 50 | 10 | +6 to hit, 2d10+2 damage | 14 | 10 |\n\n| Huge | 80 | 10 | +8 to hit, 2d12+2 damage | 18 | 6 |\n\nAn animated object is a construct with AC, hit points, attacks, Strength, and Dexterity determined by its size. Its Constitution is 10 and its Intelligence and Wisdom are 3, and its Charisma is 1. Its speed is 30 feet; if the object lacks legs or other appendages it can use for locomotion, it instead has a flying speed of 30 feet and can hover. If the object is securely attached to a surface or a larger object, such as a chain bolted to a wall, its speed is 0. It has blindsight with a radius of 30 feet and is blind beyond that distance. When the animated object drops to 0 hit points, it reverts to its original object form, and any remaining damage carries over to its original object form.\n\nIf you command an object to attack, it can make a single melee attack against a creature within 5 feet of it. It makes a slam attack with an attack bonus and bludgeoning damage determined by its size. The DM might rule that a specific object inflicts slashing or piercing damage based on its form.",
|
||||
"duration": "Concentration, up to 1 minute",
|
||||
"higher_levels": "If you cast this spell using a spell slot of 6th level or higher, you can animate two additional objects for each slot level above 5th.",
|
||||
"level": "animated",
|
||||
"level": "5",
|
||||
"name": "Animate Objects",
|
||||
"range": "120 feet",
|
||||
"ritual": false,
|
||||
|
@ -6202,7 +6202,7 @@
|
|||
"somatic": true,
|
||||
"verbal": true
|
||||
},
|
||||
"description": "A shimmering barrier extends out from you in a 10-foot-radius and moves with you, remaining centered on you and hedging out creatures other than undead and constructs. The barrier lasts for the duration.\n\nThe barrier prevents an affected creature from passing or reaching through. An affected creature can cast spells or make attacks with ranged or reach weapons through the barrier.\n\nIf you move so an affected creature is forced to pass through the barrier, the spell ends.",
|
||||
"description": "A shimmering barrier extends out from you in a 10-foot radius and moves with you, remaining centered on you and hedging out creatures other than undead and constructs. The barrier lasts for the duration.\n\nThe barrier prevents an affected creature from passing or reaching through. An affected creature can cast spells or make attacks with ranged or reach weapons through the barrier.\n\nIf you move so an affected creature is forced to pass through the barrier, the spell ends.",
|
||||
"duration": "Concentration, up to 1 hour",
|
||||
"level": "5",
|
||||
"name": "Antilife Shell",
|
||||
|
@ -6211,7 +6211,7 @@
|
|||
"school": "abjuration",
|
||||
"tags": [
|
||||
"druid",
|
||||
"level6"
|
||||
"level5"
|
||||
],
|
||||
"type": "5th-level abjuration"
|
||||
},
|
||||
|
@ -6243,30 +6243,6 @@
|
|||
],
|
||||
"type": "6th-level conjuration"
|
||||
},
|
||||
{
|
||||
"casting_time": "1 action",
|
||||
"classes": [
|
||||
"druid"
|
||||
],
|
||||
"components": {
|
||||
"material": false,
|
||||
"raw": "V, S",
|
||||
"somatic": true,
|
||||
"verbal": true
|
||||
},
|
||||
"description": "A shimmering barrier extends out from you in a 10-foot radius and moves with you, remaining centered on you and hedging out creatures other than undead and constructs. The barrier lasts for the duration.\n\nThe barrier prevents an affected creature from passing or reaching through. An affected creature can cast spells or make attacks with ranged or reach weapons through the barrier.\n\nIf you move so that an affected creature is forced to pass through the barrier, the spell ends.",
|
||||
"duration": "Concentration, up to 1 hour",
|
||||
"level": "5",
|
||||
"name": "Antilife Shell",
|
||||
"range": "Self (10-foot radius)",
|
||||
"ritual": false,
|
||||
"school": "abjuration",
|
||||
"tags": [
|
||||
"druid",
|
||||
"level5"
|
||||
],
|
||||
"type": "5th-level abjuration"
|
||||
},
|
||||
{
|
||||
"casting_time": "8 hours",
|
||||
"classes": [
|
68
src/statics/empty-bg.svg
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg id="svg7404" style="enable-background:new 232 -592.3 824.9 1155;" x="0px" y="0px" viewBox="232 -592.3 824.9 1155" xmlns="http://www.w3.org/2000/svg">
|
||||
<style type="text/css">
|
||||
.st0{fill:#EDF9F7;}
|
||||
.st1{fill:#7BCBBF;}
|
||||
.st2{fill:#9BD8D0;}
|
||||
.st3{fill:#CBE9E4;}
|
||||
.st4{fill:#6EC3BB;}
|
||||
.st5{fill:#FFFFFF;}
|
||||
.st6{fill:#EED7B2;}
|
||||
.st7{fill:#DAC4BF;}
|
||||
.st8{fill:#CCDBB9;}
|
||||
.st9{fill:#DBEFBE;}
|
||||
.st10{fill:#D4E6BC;}
|
||||
.st11{fill:#F9FBF5;}
|
||||
.st12{fill:#D6C2BE;}
|
||||
.st13{fill:#E0E4DD;}
|
||||
.st14{fill:#B3D3C8;}
|
||||
.st15{fill:#9FCABF;}
|
||||
.st16{fill:#D3DBD9;}
|
||||
.st17{fill:#A6C9C4;}
|
||||
.st18{fill:#BCD1CD;}
|
||||
.st19{fill:#92C0BB;}
|
||||
.st20{fill:#DFEAE9;}
|
||||
</style>
|
||||
<g transform="matrix(-0.992753, 0, 0, 1, 1266.810913, 17.852758)">
|
||||
<path class="st0" d="M544.6-229L544.6-229L544.6-229 M501.7-241.2L501.7-241.2l-19.1,22.8l31.1,13c0.1-1.1,0.4-2.1,1.1-2.9 		c1-1.2,2.4-1.8,4-1.8c1.4,0,2.9,0.5,4.1,1.5c0.9,0.7,1.5,1.6,1.9,2.6l19.4-23.3L501.7-241.2"/>
|
||||
<polyline class="st1" points="474.8,-209.1 447.4,-176.2 466.8,-136.4 489.6,-163.7 465.5,-197.8 474.9,-209.1 474.8,-209.1 	"/>
|
||||
<path class="st2" d="M544.5-229.4l-0.2,0.2l-19.4,23.3c0.7,1.8,0.5,3.9-0.7,5.4c-0.3,0.4-0.7,0.7-1.1,0.9l21.1,32.6l19.3-23.1 		L544.6-229l0,0L544.5-229.4"/>
|
||||
<polyline class="st3" points="489.9,-163.8 489.7,-163.6 489.6,-163.7 466.8,-136.4 466.7,-136.2 508.6,-124.3 508.6,-124.3 		527,-146.3 489.9,-163.8 	"/>
|
||||
<path class="st2" d="M482.6-218.4l-7.8,9.3l-9.4,11.3l24.2,34.1l0.1,0.1l0.2-0.2l-0.2-0.1l29.3-35c-1-0.2-2-0.7-2.9-1.4 		c-1.6-1.3-2.4-3.3-2.3-5.1L482.6-218.4L482.6-218.4"/>
|
||||
<path class="st4" d="M523.1-199.6c-0.8,0.6-1.9,0.8-2.9,0.8c-0.4,0-0.8,0-1.2-0.1l-29.3,35l0.2,0.1l37.1,17.5l8.2-9.7l9.1-10.9 		L523.1-199.6"/>
|
||||
<path class="st5" d="M518.9-210c-1.5,0-3,0.6-4,1.8c-0.7,0.8-1.1,1.9-1.1,2.9c-0.1,1.8,0.7,3.7,2.3,5.1c0.9,0.7,1.9,1.2,2.9,1.4 		c0.4,0.1,0.8,0.1,1.2,0.1c1,0,2.1-0.3,2.9-0.8c0.4-0.3,0.7-0.6,1.1-0.9c1.2-1.5,1.4-3.5,0.7-5.4c-0.4-1-1-1.9-1.9-2.6 		C521.7-209.5,520.3-210,518.9-210"/>
|
||||
<path class="st6" d="M874.4,91.9c-2,9.3-4.7,18-7.1,25.7l133.5,111.7l-2.3,2.7l0,0l13.2-15.9L874.4,91.9 M577.3-176.6l2.2,53.4 		L624-86.1c4.1-1.9,9-2.9,14.2-2.9c3.2,0,6.5,0.4,9.6,1.2c13,3.4,19.8,12.9,15,21.2c-0.3,0.5-0.6,1-1,1.5c-0.7,2.4-1.5,5.5-2.1,8.9 		L839.8,94.6c0-0.9,0-1.9-0.1-2.8l0,0c0,0,0,0,0,0c0.3-13.5,2-27.5-1.3-32.3L577.3-176.6"/>
|
||||
<path class="st7" d="M867.3,117.6c-2.8,8.9-5.1,16.4-5.1,21.9c-0.1,3.7,0.4,6.8,1.2,9.5L987.6,245l10.9-13.1l2.3-2.7L867.3,117.6 		 M659.7-56.2c-3,16.4-2.7,42.8,21.9,63.4c2.2,1.8,4.6,3.4,7,4.5l67.1,52.1l0,0c-0.5,0.2-1,0.4-1.5,0.7l87.3,67.6 		c-0.9-10.2-1.3-22.6-1.7-37.4L659.7-56.2 M579.6-123.3l0.1,2.5l-55.1,7.4L614-44.1c-0.6-5.7-0.7-10.8-0.7-15 		c0-8.5,0.7-13.6,0.7-13.6s0-0.1,0.1-0.3c-0.1-2,0.4-4,1.5-6c1.7-3,4.7-5.4,8.4-7.1L579.6-123.3"/>
|
||||
<path class="st8" d="M839.8,91.7L839.8,91.7c0,1,0,1.9,0.1,2.8c0.4,14.8,0.8,27.2,1.7,37.4c1.9,21.5,6,33.3,17.1,36.7 		c3.4,1.1,6.4,1.5,9,1.5c4.4,0,7.6-1.2,9.9-2.6c-2.3,1.4-5.5,2.6-9.9,2.6c-2.6,0-5.6-0.4-9-1.5C841.9,163.6,841,139.4,839.8,91.7 		 M806.6-3.9c-10.8,0-21.9,2-32.8,4.7l23.9,21.6c1,0,2.1-0.1,3.1-0.1c21.4,0,38,9.1,49.3,22.5c12.8,15.3,3.1,56.1,3.9,79 		c0.9,22.4-5.4,36.8,27.2,40.6c0.4-0.5,0.6-0.8,0.6-0.8s-14.1-0.8-18.4-14.8c-0.8-2.7-1.3-5.8-1.2-9.5c0.1-5.4,2.4-13,5.1-21.9 		c2.4-7.7,5.1-16.4,7.1-25.7c5.4-25.7,5-55.8-24.9-80.8C836.3,0,821.7-3.9,806.6-3.9 M613.2-59.1c0,4.2,0.2,9.3,0.7,15 		c2.5,25.9,12.6,64.3,47.8,93.6c20.4,17,39.5,23,56.7,23c13.2,0,25.2-3.5,35.8-8.1c0.5-0.2,1-0.4,1.5-0.7l0,0 		c-10.9,4.9-23.5,8.7-37.2,8.7c-17.2,0-36.3-5.9-56.7-23C618.9,13.7,613.2-35.6,613.2-59.1 M661.9-65.1c-4.1,5.4-12.5,8.6-21.6,8.6 		c-1.7,0-3.4-0.1-5.1-0.3c-0.8,25.1,5.1,61.8,29.9,82.4c10.6,8.8,25.2,11.8,40.9,11.8c4.8,0,9.7-0.3,14.7-0.8l35,27.1l-67.1-52.1 		c-2.3-1.1-4.7-2.6-7-4.5c-24.6-20.5-24.9-46.9-21.9-63.4C660.3-59.7,661.1-62.7,661.9-65.1"/>
|
||||
<path class="st9" d="M800.8,22.4c-1,0-2.1,0-3.1,0.1c0,0-0.1,0-0.1,0l40,36c0.3,0.3,0.6,0.6,0.8,0.9c3.3,4.9,1.6,18.9,1.3,32.3l0,0 		c1.2,47.7,2.2,71.8,18.9,77c3.4,1.1,6.4,1.5,9,1.5c4.4,0,7.6-1.2,9.9-2.6c1.8-1.1,3-2.3,3.7-3.1c0,0,0,0,0,0 		c-32.6-3.8-26.3-18.2-27.2-40.6c-0.8-22.9,8.9-63.7-3.9-79C838.8,31.5,822.2,22.4,800.8,22.4 M614.1-73c-0.1,0.2-0.1,0.3-0.1,0.3 		s-0.7,5.1-0.7,13.6c0,23.6,5.7,72.8,48.5,108.6c20.4,17,39.5,23,56.7,23c13.8,0,26.3-3.8,37.2-8.7l0,0l-35-27.1 		c-4.9,0.5-9.9,0.8-14.7,0.8c-15.7,0-30.3-3.1-40.9-11.8c-24.8-20.7-30.8-57.4-29.9-82.4c-1.5-0.2-3-0.5-4.5-0.9 		C620.6-60.3,614.3-66.5,614.1-73"/>
|
||||
<path class="st10" d="M638.2-59.6c-2,0-4.1-0.7-5.9-2.2c-3.7-3.1-4.4-8.2-1.7-11.4c1.4-1.7,3.5-2.5,5.7-2.5c2,0,4.1,0.7,5.9,2.2 		c3.7,3.1,4.4,8.2,1.7,11.4C642.5-60.5,640.4-59.6,638.2-59.6 M638.2-89c-5.2,0-10.1,1-14.2,2.9c-3.7,1.7-6.7,4.2-8.4,7.1 		c-1.1,2-1.6,4-1.5,6c0.3,6.5,6.6,12.7,16.5,15.3c1.5,0.4,3,0.7,4.5,0.9c1.7,0.2,3.4,0.3,5.1,0.3c9.1,0,17.5-3.2,21.6-8.6 		c0.4-0.5,0.7-1,1-1.5c4.7-8.3-2-17.8-15-21.2C644.6-88.6,641.4-89,638.2-89"/>
|
||||
<path class="st11" d="M636.3-75.8c-2.2,0-4.3,0.9-5.7,2.5c-2.7,3.3-2,8.4,1.7,11.4c1.8,1.5,3.9,2.2,5.9,2.2c2.2,0,4.3-0.9,5.7-2.5 		c2.7-3.3,2-8.4-1.7-11.4C640.5-75.1,638.4-75.8,636.3-75.8"/>
|
||||
<polyline class="st12" points="577.3,-178.5 549.7,-145.7 522.2,-113.1 524.5,-113.4 579.7,-120.8 579.6,-123.3 577.3,-176.6 		577.3,-178.5 	"/>
|
||||
<polyline class="st13" points="563.6,-190 563.5,-190 564.1,-188.9 537.9,-157.6 550.6,-147 577.1,-178.7 563.6,-190 	"/>
|
||||
<polyline class="st14" points="563.5,-190 544.2,-166.9 544.4,-166.7 537.2,-158.2 537.9,-157.6 564.1,-188.9 563.5,-190 	"/>
|
||||
<polyline class="st15" points="544.2,-166.9 535.1,-156 537,-158.3 537.2,-158.2 544.4,-166.7 544.2,-166.9 	"/>
|
||||
<polyline class="st16" points="537.9,-157.6 536.7,-156.1 536.7,-156.1 509.7,-124 508.6,-124.3 522.1,-113 550.6,-147 		537.9,-157.6 	"/>
|
||||
<polyline class="st17" points="537.2,-158.2 536.6,-157.4 537.3,-156.8 536.7,-156.1 536.7,-156.1 537.9,-157.6 537.2,-158.2 	"/>
|
||||
<polyline class="st18" points="536.6,-157.4 527.2,-146.2 527,-146.3 508.6,-124.3 508.6,-124.3 509.7,-124 536.7,-156.1 		537.3,-156.8 536.6,-157.4 	"/>
|
||||
<polyline class="st19" points="537,-158.3 535.1,-156 527,-146.3 527.2,-146.2 536.6,-157.4 537.2,-158.2 537,-158.3 	"/>
|
||||
<polygon class="st20" points="362.8,-106.5 366.8,-137.1 394.1,-151.2 366.3,-164.3 361.4,-194.7 340.3,-172.4 309.9,-177.1 		324.6,-150 310.7,-122.6 341,-128.3 	"/>
|
||||
<polygon class="st20" points="394.7,-386.8 409.4,-403.2 431.2,-400.3 420.2,-419.4 429.7,-439.2 408.2,-434.6 392.3,-449.7 		390,-427.9 370.7,-417.4 390.7,-408.5 	"/>
|
||||
<polygon class="st20" points="457,20.4 461.6,-14.7 493.1,-30.9 461.1,-46.1 455.4,-81.1 431,-55.3 396,-60.7 413,-29.6 397,2 		431.8,-4.5 	"/>
|
||||
<polygon class="st20" points="634.6,-418.3 636.7,-434.1 650.9,-441.4 636.5,-448.2 633.9,-463.9 623,-452.4 607.2,-454.8 		614.9,-440.8 607.7,-426.6 623.3,-429.5 	"/>
|
||||
<polygon class="st20" points="803.5,-10.6 800.3,-33.9 817.8,-49.6 794.6,-53.9 785,-75.3 773.8,-54.7 750.5,-52.1 766.7,-35.1 		761.9,-12.1 783.1,-22.3 	"/>
|
||||
<polygon class="st20" points="608.2,41.7 610.5,23.5 626.9,15.1 610.3,7.2 607.4,-10.9 594.7,2.5 576.6,-0.4 585.4,15.8 		577.1,32.1 595.1,28.8 	"/>
|
||||
<polygon class="st20" points="267.8,88.3 269.8,72.5 284,65.2 269.6,58.4 267,42.6 256.1,54.2 240.4,51.8 248,65.8 240.8,80 		256.5,77.1 	"/>
|
||||
<polygon class="st20" points="489.7,348 497.5,334.2 513.4,332.8 502.6,321 506.2,305.5 491.7,312.1 478,303.9 479.8,319.7 		467.8,330.2 483.4,333.4 	"/>
|
||||
<polygon class="st20" points="989.4,-441.9 997.3,-455.7 1013.1,-457.1 1002.4,-468.9 1005.9,-484.4 991.4,-477.8 977.8,-486 		979.6,-470.2 967.5,-459.7 983.2,-456.5 	"/>
|
||||
<polygon class="st20" points="934.4,137.9 939.1,126.4 951.4,123.8 941.9,115.7 943.1,103.3 932.5,109.8 921.1,104.8 924,116.9 		915.7,126.2 928.2,127.1 	"/>
|
||||
<polygon class="st20" points="326.5,108.6 324.9,96.3 334.1,87.9 321.8,85.6 316.8,74.3 310.8,85.2 298.5,86.6 307.1,95.6 		304.5,107.8 315.7,102.4 	"/>
|
||||
<polygon class="st20" points="530.6,104.7 532,93.7 541.9,88.7 531.9,83.9 530.1,73 522.5,81 511.6,79.3 516.9,89 511.9,98.9 		522.7,96.9 	"/>
|
||||
<polygon class="st20" points="742.1,-272 745.1,-282.7 755.5,-286.3 746.3,-292.4 746.1,-303.5 737.4,-296.6 726.8,-299.8 		730.7,-289.5 724.3,-280.4 735.4,-280.9 	"/>
|
||||
<polygon class="st20" points="939.7,-208.2 950.1,-211.9 959.1,-205.5 958.7,-216.6 967.5,-223.3 956.9,-226.3 953.4,-236.7 		947.2,-227.6 936.1,-227.4 943,-218.7 	"/>
|
||||
<polygon class="st20" points="825.7,-570.5 829.8,-574.5 835.4,-573.5 832.8,-578.6 835.5,-583.7 829.9,-582.8 825.9,-587 		825,-581.3 819.8,-578.8 824.9,-576.2 	"/>
|
||||
<polygon class="st20" points="862.9,475.8 867,471.8 872.6,472.8 870,467.7 872.7,462.6 867.1,463.5 863.1,459.3 862.2,465 		857,467.5 862.1,470.1 	"/>
|
||||
<polygon class="st20" points="503.3,-554 507.4,-558 513.1,-557 510.5,-562.1 513.2,-567.2 507.5,-566.3 503.6,-570.5 		502.7,-564.8 497.4,-562.3 502.6,-559.7 	"/>
|
||||
<polygon class="st20" points="706.5,302 710.6,297.9 716.3,299 713.6,293.8 716.4,288.7 710.7,289.6 706.7,285.5 705.8,291.1 		700.6,293.6 705.7,296.2 	"/>
|
||||
<polygon class="st20" points="328,488.5 333.8,487.9 337.6,492.2 338.7,486.5 344,484.2 339,481.4 338.4,475.7 334.2,479.6 		328.6,478.3 331,483.6 	"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 9.6 KiB |
BIN
src/statics/favicon.ico
Normal file
After Width: | Height: | Size: 4.2 KiB |
10
src/statics/logo.svg
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg x="0px" y="0px" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 59.895 42.143 L 52.865 36.872 C 51.891 36.14 50.509 36.339 49.778 37.312 L 41.205 48.744 L 51.762 56.661 L 60.335 45.229 C 61.067 44.257 60.869 42.874 59.895 42.143 Z" style="fill: rgb(38, 166, 154);"/>
|
||||
<path d="M 12.836 86.568 C 12.105 87.542 12.304 88.924 13.276 89.655 L 20.306 94.926 C 21.279 95.657 22.662 95.458 23.393 94.485 L 49.385 59.827 L 38.828 51.909 L 12.836 86.568 Z" style="fill: rgb(38, 166, 154);"/>
|
||||
<polygon points="17.06 46.888 22.612 41.476 14.941 40.363 11.513 33.412 8.082 40.363 0.411 41.476 5.963 46.888 4.654 54.528 11.513 50.918 18.375 54.528" style="fill: rgb(233, 30, 99);" transform="matrix(-0.374607, -0.927184, 0.927184, -0.374607, -24.944491, 71.114733)"/>
|
||||
<polygon points="26.854 23.295 33.715 19.687 40.577 23.295 39.266 15.656 44.813 10.243 37.143 9.129 33.715 2.181 30.283 9.129 22.612 10.243 28.164 15.656" style="fill: rgb(233, 30, 99);" transform="matrix(0.992546, 0.121869, -0.121869, 0.992546, 1.803659, -4.013573)"/>
|
||||
<polygon points="66.405 77.911 62.978 70.955 59.546 77.911 51.876 79.022 57.427 84.43 56.118 92.067 62.978 88.466 69.84 92.067 68.53 84.43 74.076 79.022" style="fill: rgb(233, 30, 99);" transform="matrix(0.573576, 0.819152, -0.819152, 0.573576, 93.624363, -16.828705)"/>
|
||||
<polygon points="99.629 49.419 91.958 48.305 88.528 41.352 85.096 48.305 77.427 49.419 82.974 54.827 81.665 62.466 88.528 58.861 95.384 62.466 94.077 54.827" style="fill: rgb(233, 30, 99);" transform="matrix(0.927184, 0.374607, -0.374607, 0.927184, 25.891722, -29.383358)"/>
|
||||
<polygon points="65.895 27.583 72.758 23.978 79.619 27.583 78.309 19.944 83.859 14.534 76.189 13.422 72.758 6.47 69.329 13.422 61.66 14.534 67.211 19.944" style="fill: rgb(233, 30, 99);" transform="matrix(0.97437, -0.224951, 0.224951, 0.97437, -1.965308, 16.803712)"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
51
src/store.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
import { LocalStorage } from 'quasar'
|
||||
import indexedSpells from './tmp/spells_index'
|
||||
|
||||
export let state = {
|
||||
indexedSpells,
|
||||
spells: {
|
||||
loaded: false,
|
||||
data: []
|
||||
},
|
||||
chosen: [],
|
||||
search: '',
|
||||
sortBy: 'name',
|
||||
previousSortBy: 'name',
|
||||
lastSpell: ''
|
||||
}
|
||||
|
||||
export function dispatch (action) {
|
||||
switch (action.type) {
|
||||
case 'SPELLS_RESOLVED':
|
||||
state.spells = action.data
|
||||
break
|
||||
case 'LOAD_LOCAL_CHOSEN' :
|
||||
state.chosen = LocalStorage.get.item('chosen').split(',')
|
||||
break
|
||||
case 'WIPE_CHOSEN':
|
||||
state.chosen = []
|
||||
LocalStorage.remove('chosen')
|
||||
break
|
||||
case 'CHANGE_CHOSEN':
|
||||
if (action.data.want) {
|
||||
state.chosen.push(action.data.id)
|
||||
}
|
||||
else {
|
||||
let index = state.chosen.indexOf(action.data.id)
|
||||
if (index >= 0) state.chosen.splice(index, 1)
|
||||
}
|
||||
|
||||
if (state.chosen.length) {
|
||||
LocalStorage.set('chosen', state.chosen.join(','))
|
||||
}
|
||||
else {
|
||||
LocalStorage.remove('chosen')
|
||||
}
|
||||
break
|
||||
case 'SEARCH_CHANGED':
|
||||
state.page = 1
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
export default { state, dispatch }
|
26
src/themes/app.ios.styl
Normal file
|
@ -0,0 +1,26 @@
|
|||
// This file is included in the build if src/main.js imports it.
|
||||
// Otherwise the default iOS CSS file is bundled.
|
||||
// Check "DEFAULT / CUSTOM STYLE" in src/main.js
|
||||
|
||||
// App Shared Variables
|
||||
// --------------------------------------------------
|
||||
// Shared Stylus variables go in the app.variables.styl file
|
||||
@import 'app.variables'
|
||||
|
||||
// App iOS Design Variables
|
||||
// --------------------------------------------------
|
||||
// iOS Design only Stylus variables can go here
|
||||
// http://quasar-framework.org/api/css-stylus-variables.html
|
||||
|
||||
$typography-font-family ?= '-apple-system', 'Helvetica Neue', Helvetica, Arial, sans-serif
|
||||
|
||||
$toolbar-color ?= #424242
|
||||
$toolbar-background ?= $light
|
||||
$toolbar-active-color ?= $light
|
||||
$toolbar-faded-color ?= composite-color($toolbar-color)
|
||||
|
||||
// Quasar iOS Design Stylus
|
||||
// --------------------------------------------------
|
||||
// Custom App variables must be declared before importing Quasar.
|
||||
// Quasar will use its default values when a custom variable isn't provided.
|
||||
@import '~quasar-framework/dist/quasar.ios.styl'
|
26
src/themes/app.mat.styl
Normal file
|
@ -0,0 +1,26 @@
|
|||
// This file is included in the build if src/main.js imports it.
|
||||
// Otherwise the default Material CSS file is bundled.
|
||||
// Check "DEFAULT / CUSTOM STYLE" in src/main.js
|
||||
|
||||
// App Shared Variables
|
||||
// --------------------------------------------------
|
||||
// Shared Stylus variables go in the app.variables.styl file
|
||||
@import 'app.variables'
|
||||
|
||||
// App Material Design Variables
|
||||
// --------------------------------------------------
|
||||
// Material Design only Stylus variables can go here
|
||||
// http://quasar-framework.org/api/css-stylus-variables.html
|
||||
|
||||
$typography-font-family ?= 'Roboto'
|
||||
|
||||
$toolbar-color ?= white
|
||||
$toolbar-background ?= $primary
|
||||
$toolbar-active-color ?= $primary
|
||||
$toolbar-faded-color ?= composite-color($primary)
|
||||
|
||||
// Quasar Material Design Stylus
|
||||
// --------------------------------------------------
|
||||
// Custom App variables must be declared before importing Quasar.
|
||||
// Quasar will use its default values when a custom variable isn't provided.
|
||||
@import '~quasar-framework/dist/quasar.mat.styl'
|
37
src/themes/app.variables.styl
Normal file
|
@ -0,0 +1,37 @@
|
|||
// This file is included in the build if src/main.js imports
|
||||
// either app.mat.styl or app.ios.styl.
|
||||
// Check "DEFAULT / CUSTOM STYLE" in src/main.js
|
||||
|
||||
// App Shared Variables
|
||||
// --------------------------------------------------
|
||||
// To customize the look and feel of this app, you can override
|
||||
// the Stylus variables found in Quasar's source Stylus files. Setting
|
||||
// variables before Quasar's Stylus will use these variables rather than
|
||||
// Quasar's default Stylus variable values. Stylus variables specific
|
||||
// to the themes belong in either the app.ios.styl or app.mat.styl files.
|
||||
|
||||
|
||||
// App Shared Color Variables
|
||||
// --------------------------------------------------
|
||||
// It's highly recommended to change the default colors
|
||||
// to match your app's branding.
|
||||
|
||||
$primary = #027be3
|
||||
$secondary = #26A69A
|
||||
$tertiary = #555
|
||||
|
||||
$neutral = #E0E1E2
|
||||
$positive = #21BA45
|
||||
$negative = #DB2828
|
||||
$info = #31CCEC
|
||||
$warning = #F2C037
|
||||
|
||||
$light = #f4f4f4
|
||||
$dark = #333
|
||||
$faded = #777
|
||||
|
||||
$text-color = lighten(black, 17%)
|
||||
$background-color = white
|
||||
|
||||
$link-color = lighten($primary, 25%)
|
||||
$link-color-active = $primary
|
1
src/utils.js
Normal file
|
@ -0,0 +1 @@
|
|||
export const capitalize = str => str.charAt(0).toUpperCase() + str.slice(1)
|
|
@ -1,19 +0,0 @@
|
|||
{% if data %}
|
||||
{% for cur of data %}
|
||||
<label class="mdl-navigation__link">
|
||||
<div class="mdl-switch mdl-js-switch mdl-js-ripple-effect">
|
||||
{% if current.includes(cur) %}
|
||||
<input checked data-action-classtoggle="{{ cur }}" name="class" type="checkbox" class="mdl-switch__input" />
|
||||
{% else %}
|
||||
<input data-action-classtoggle="{{ cur }}" name="class" type="checkbox" class="mdl-switch__input" />
|
||||
{% endif %}
|
||||
<span class="mdl-switch__label">
|
||||
{{ cur }}
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="mdl-spinner mdl-js-spinner is-active"></div>
|
||||
{% endif %}
|
||||
|
|
@ -1 +0,0 @@
|
|||
<input value="{{ data }}" class="mdl-textfield__input" data-action-search type="text" id="fixed-header-drawer-exp" />
|
|
@ -1,27 +0,0 @@
|
|||
{% if data.name %}
|
||||
<button data-action-details="" class="mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
<h5 class="mdl-typography--display-1 mdl-color-text--teal-600">{{ data.name }}</h5>
|
||||
<ul id="details">
|
||||
{% for detail of data.details %}
|
||||
<li>
|
||||
<strong>{{ detail.label }}</strong> {{ detail.value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<p id="description">{% unsafe data.description %}</p>
|
||||
|
||||
<div class="mdl-textfield mdl-js-textfield" id="copy">
|
||||
<label class="mdl-button mdl-js-button mdl-button--icon copy-to-clipboard" for="share-url" data-clipboard-target="#share-url">
|
||||
<i class="material-icons">content_copy</i>
|
||||
</label>
|
||||
<input readonly class="mdl-textfield__input" type="text" id="share-url" value="{{ url }}">
|
||||
</div>
|
||||
{% else %}
|
||||
<div id="empty">
|
||||
<h6 class="mdl-typography--title">
|
||||
Choose a Spell
|
||||
</h6>
|
||||
</div>
|
||||
{% endif %}
|
|
@ -1,23 +0,0 @@
|
|||
{% for spell of data %}
|
||||
<tr>
|
||||
<td class="spell-name">
|
||||
<strong>
|
||||
{{ spell.name }}
|
||||
</strong>
|
||||
</td>
|
||||
<td class="spell-level">
|
||||
{{ spell.level }}
|
||||
</td>
|
||||
<td class="spell-description">
|
||||
<ul id="details">
|
||||
{% for detail of spell.details %}
|
||||
<li>
|
||||
<strong>{{ detail.label }}</strong> {{ detail.value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% unsafe spell.description %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
|
@ -1,40 +0,0 @@
|
|||
{% if data.length %}
|
||||
{% for spell of data %}
|
||||
{% if spell.name %}
|
||||
<tr data-action-details="{{ spell.name }}">
|
||||
<td class="hide-phone">
|
||||
<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect mdl-data-table__select dontprop">
|
||||
<input type="checkbox" name="selected" value="{{ spell.name }}" class="mdl-checkbox__input dontprop" />
|
||||
</label>
|
||||
</td>
|
||||
<td class="spell-name mdl-data-table__cell--non-numeric">
|
||||
<strong>
|
||||
{{ spell.name }}
|
||||
</strong>
|
||||
</td>
|
||||
<td class="spell-school mdl-data-table__cell--non-numeric">
|
||||
{{ spell.school }}
|
||||
</td>
|
||||
<td class="spell-level">
|
||||
{{ spell.level }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr class="do-nothing">
|
||||
<td colspan="4">
|
||||
{% if data %}
|
||||
<div class="text-center">
|
||||
<i class="material-icons mdl-list__item-icon mdl-color-text--orange-600">
|
||||
warning
|
||||
</i>
|
||||
<h5>No Results</h5>
|
||||
<h6>Try refining your filters in the sidebar.</h6>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="mdl-spinner mdl-js-spinner is-active"></div>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
|
@ -1,11 +0,0 @@
|
|||
{% if data %}
|
||||
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label getmdl-select">
|
||||
<input class="mdl-textfield__input" data-action="system" value="{{ current }}" type="text" id="system" readonly tabIndex="-1"/>
|
||||
<label class="mdl-textfield__label mdl-color-text--white" for="system">System</label>
|
||||
<ul class="mdl-menu mdl-menu--bottom-left mdl-js-menu" for="system">
|
||||
{% for system of data %}
|
||||
<li class="mdl-menu__item">{{ system.friendly }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
|
@ -1,28 +0,0 @@
|
|||
<th class="hide-phone">
|
||||
<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect mdl-data-table__select" for="table-header">
|
||||
<input type="checkbox" id="table-header" class="mdl-checkbox__input" />
|
||||
</label>
|
||||
</th>
|
||||
{% for name of data %}
|
||||
<th data-action-sort="{{ name }}" class="mdl-data-table__cell--non-numeric {{ current === 'ranking' ? 'mdl-color-text--grey-200 do-nothing' : '' }}">
|
||||
<i class="material-icons mdl-list__item-icon">
|
||||
{% if name === 'level' %}
|
||||
exposure
|
||||
{% endif %}
|
||||
{% if name === 'name' %}
|
||||
flash_on
|
||||
{% endif %}
|
||||
{% if name === 'school' %}
|
||||
school
|
||||
{% endif %}
|
||||
</i>
|
||||
|
||||
<span>
|
||||
{{ name }}
|
||||
</span>
|
||||
|
||||
<i class="material-icons mdl-color-text--teal-600 mdl-list__item-icon {{ name === current ? 'mdl-color-text--teal-600' : 'mdl-color-text--grey-300' }}">
|
||||
{{ rev ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}
|
||||
</i>
|
||||
</th>
|
||||
{% endfor %}
|
14
templates/component.vue
Normal file
|
@ -0,0 +1,14 @@
|
|||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data () {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
55
templates/layout.vue
Normal file
|
@ -0,0 +1,55 @@
|
|||
<template>
|
||||
<q-layout>
|
||||
<div slot="header" class="toolbar">
|
||||
<!-- opens drawer below
|
||||
<button class="hide-on-drawer-visible" @click="$refs.drawer.open()">
|
||||
<i>menu</i>
|
||||
</button>
|
||||
-->
|
||||
<q-toolbar-title :padding="1">
|
||||
Title
|
||||
</q-toolbar-title>
|
||||
</div>
|
||||
|
||||
<!-- Navigation Tabs
|
||||
<q-tabs slot="navigation">
|
||||
<q-tab icon="mail" route="/layout" exact replace>Mails</q-tab>
|
||||
<q-tab icon="alarm" route="/layout/alarm" exact replace>Alarms</q-tab>
|
||||
<q-tab icon="help" route="/layout/help" exact replace>Help</q-tab>
|
||||
</q-tabs>
|
||||
-->
|
||||
|
||||
<!-- Drawer
|
||||
<q-drawer ref="drawer">
|
||||
<div class="toolbar">
|
||||
<q-toolbar-title>
|
||||
Drawer Title
|
||||
</q-toolbar-title>
|
||||
</div>
|
||||
|
||||
<div class="list no-border platform-delimiter">
|
||||
<q-drawer-link icon="mail" :to="{path: '/', exact: true}">
|
||||
Link
|
||||
</q-drawer-link>
|
||||
</div>
|
||||
</q-drawer>
|
||||
-->
|
||||
|
||||
<router-view class="layout-view"></router-view>
|
||||
|
||||
<!-- Footer
|
||||
<div slot="footer" class="toolbar"></div>
|
||||
-->
|
||||
</q-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data () {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
20
templates/view.vue
Normal file
|
@ -0,0 +1,20 @@
|
|||
<template>
|
||||
<!-- root node required -->
|
||||
<div>
|
||||
<!-- your content -->
|
||||
<div class="layout-padding">
|
||||
<!-- if you want automatic padding -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data () {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|