diff --git a/client/homebrew/brewRenderer/brewRenderer.less b/client/homebrew/brewRenderer/brewRenderer.less index 16087512a..facaab4fe 100644 --- a/client/homebrew/brewRenderer/brewRenderer.less +++ b/client/homebrew/brewRenderer/brewRenderer.less @@ -1,5 +1,5 @@ -@import (less) './client/homebrew/phbStyle/phb.style.less'; +@import (less) 'naturalcrit/phbStyle/phb.style.less'; .pane{ position : relative; } diff --git a/client/main/main.jsx b/client/main/main.jsx index 815d2c73e..0624fe61c 100644 --- a/client/main/main.jsx +++ b/client/main/main.jsx @@ -22,13 +22,13 @@ var Main = React.createClass({ beta : false }, { - id : 'homebrew2', - path : '/homebrew', - name : 'The Homebrewery', + id : 'spellsort', + path : '/spellsort', + name : 'Spellsort', icon : , - desc : 'Make authentic-looking 5e homebrews using Markdown', + desc : 'Sort and search through spells', - show : false, + show : true, beta : true }, { diff --git a/client/spellsort/navbar/navbar.jsx b/client/spellsort/navbar/navbar.jsx new file mode 100644 index 000000000..c532be1ca --- /dev/null +++ b/client/spellsort/navbar/navbar.jsx @@ -0,0 +1,21 @@ +var React = require('react'); +var _ = require('lodash'); + +var Nav = require('naturalcrit/nav/nav.jsx'); + +var Navbar = React.createClass({ + render : function(){ + return + + + +
Spellsort
+
+ v0.0.0 +
+ {this.props.children} +
+ } +}); + +module.exports = Navbar; diff --git a/client/spellsort/navbar/navbar.less b/client/spellsort/navbar/navbar.less new file mode 100644 index 000000000..1777d4198 --- /dev/null +++ b/client/spellsort/navbar/navbar.less @@ -0,0 +1,16 @@ + +.spellsort nav{ + .spellsortLogo{ + .animate(color); + font-family : CodeBold; + font-size : 12px; + color : white; + div{ + margin-top : 2px; + margin-bottom : -2px; + } + &:hover{ + color : @teal; + } + } +} \ No newline at end of file diff --git a/client/spellsort/sorter/sorter.jsx b/client/spellsort/sorter/sorter.jsx new file mode 100644 index 000000000..ca70e7962 --- /dev/null +++ b/client/spellsort/sorter/sorter.jsx @@ -0,0 +1,32 @@ +var React = require('react'); +var _ = require('lodash'); +var cx = require('classnames'); + +var Sorter = React.createClass({ + getDefaultProps: function() { + return { + spells : [] + }; + }, + + + renderSpell : function(spell){ + return
+ {spell.name} +
+ }, + + renderSpells : function(){ + return _.map(this.props.spells, (spell)=>{ + return this.renderSpell(spell) + }); + }, + + render : function(){ + return
+ {this.renderSpells()} +
+ } +}); + +module.exports = Sorter; diff --git a/client/spellsort/sorter/sorter.less b/client/spellsort/sorter/sorter.less new file mode 100644 index 000000000..6bb4bdf5e --- /dev/null +++ b/client/spellsort/sorter/sorter.less @@ -0,0 +1,3 @@ +.COM{ + +} \ No newline at end of file diff --git a/client/spellsort/spellRenderer/spellRenderer.jsx b/client/spellsort/spellRenderer/spellRenderer.jsx new file mode 100644 index 000000000..134d0bc5c --- /dev/null +++ b/client/spellsort/spellRenderer/spellRenderer.jsx @@ -0,0 +1,97 @@ +var React = require('react'); +var _ = require('lodash'); +var cx = require('classnames'); + +var Markdown = require('marked'); + +var SpellRenderer = React.createClass({ + getDefaultProps: function() { + return { + spells : [] + }; + }, + + //TODO: Add in ritual tag + getSubtitle : function(spell){ + if(spell.level == 0) return

{spell.school} cantrip

; + if(spell.level == 1) return

{spell.level}st-level {spell.school}

; + if(spell.level == 2) return

{spell.level}nd-level {spell.school}

; + if(spell.level == 3) return

{spell.level}rd-level {spell.school}

; + return

{spell.level}th-level {spell.school}

; + }, + + getComponents : function(spell){ + var result = []; + if(spell.components.v) result.push('V'); + if(spell.components.s) result.push('S'); + if(spell.components.m) result.push('M ' + spell.components.m); + return result.join(', '); + }, + + getHigherLevels : function(spell){ + if(!spell.scales) return null; + return

+ At Higher Levels. + +

; + }, + + getClasses : function(spell){ + if(!spell.classes || !spell.classes.length) return null; + + var classes = _.map(spell.classes, (cls)=>{ + return _.capitalize(cls); + }).join(', '); + + return
  • + Classes: {classes} +
  • + }, + + + renderSpell : function(spell){ + console.log('rendering', spell); + return
    + +

    {spell.name}

    + {this.getSubtitle(spell)} +
    + + + + {this.getHigherLevels(spell)} +
    + }, + + renderSpells : function(){ + return _.map(this.props.spells, (spell)=>{ + return this.renderSpell(spell); + }) + }, + + render : function(){ + return
    + +
    + {this.renderSpells()} +
    + +
    + } +}); + +module.exports = SpellRenderer; diff --git a/client/spellsort/spellRenderer/spellRenderer.less b/client/spellsort/spellRenderer/spellRenderer.less new file mode 100644 index 000000000..ccd8dae4e --- /dev/null +++ b/client/spellsort/spellRenderer/spellRenderer.less @@ -0,0 +1,40 @@ +@import (less) 'naturalcrit/phbStyle/phb.style.less'; +.pane{ + position : relative; +} +.spellRenderer{ + overflow-y : scroll; + + &>.phb{ + margin-right : auto; + margin-bottom : 30px; + margin-left : auto; + box-shadow : 1px 4px 14px #000; + + height : auto; + width : 100%; + + display: flex; + flex-direction: column; + flex-wrap: wrap; + + column-count : initial; + column-fill : initial; + column-gap : initial; + column-width : initial; + -webkit-column-count : initial; + -moz-column-count : initial; + -webkit-column-width : initial; + -moz-column-width : initial; + -webkit-column-gap : initial; + -moz-column-gap : initial; + + .spell{ + display: inline; + width : 8cm; + + } + + } + +} \ No newline at end of file diff --git a/client/spellsort/spellsort.jsx b/client/spellsort/spellsort.jsx new file mode 100644 index 000000000..79c307b71 --- /dev/null +++ b/client/spellsort/spellsort.jsx @@ -0,0 +1,45 @@ +var React = require('react'); +var _ = require('lodash'); +var cx = require('classnames'); + +var Nav = require('naturalcrit/nav/nav.jsx'); +var Navbar = require('./navbar/navbar.jsx'); + +var SplitPane = require('naturalcrit/splitPane/splitPane.jsx'); +var SpellRenderer = require('./spellRenderer/spellRenderer.jsx'); +var Sorter = require('./sorter/sorter.jsx'); + +var SpellSort = React.createClass({ + + getDefaultProps: function() { + return { + spells : [] + }; + }, + + handleSplitMove : function(){ + + }, + + render : function(){ + console.log(this.props.spells); + + return
    + + + yo + + +
    + + + + + + +
    +
    + } +}); + +module.exports = SpellSort; diff --git a/client/spellsort/spellsort.less b/client/spellsort/spellsort.less new file mode 100644 index 000000000..a63ea7996 --- /dev/null +++ b/client/spellsort/spellsort.less @@ -0,0 +1,4 @@ +@import 'naturalcrit/styles/core.less'; +.spellsort{ + +} \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index a06b07b87..dc249c01a 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -8,6 +8,7 @@ var gulp = vitreumTasks(gulp, { entryPoints: [ './client/main', './client/homebrew', + './client/spellsort', './client/admin' ], @@ -43,7 +44,7 @@ var gulp = vitreumTasks(gulp, { var rename = require('gulp-rename'); var less = require('gulp-less'); gulp.task('phb', function(){ - gulp.src('./client/homebrew/phbStyle/phb.style.less') + gulp.src('./shared/naturalcrit/phbStyle/phb.style.less') .pipe(less()) .pipe(rename('phb.standalone.css')) .pipe(gulp.dest('./')); diff --git a/server.js b/server.js index ebd6f4ae5..6f274e3e4 100644 --- a/server.js +++ b/server.js @@ -46,6 +46,9 @@ app = require('./server/homebrew.api.js')(app); app = require('./server/homebrew.server.js')(app); +//Populate Spellsort routes +app = require('./server/spellsort.server.js')(app); + app.get('*', function (req, res) { vitreumRender({ diff --git a/server/5espells.js b/server/5espells.js new file mode 100644 index 000000000..1c4745964 --- /dev/null +++ b/server/5espells.js @@ -0,0 +1,164 @@ +module.exports = { + "Abi-Dalzim's Horrid Wilting": { + "athigherlevel": "", + "description": "(a bit of sponge)\r\nYou draw the moisture from every creature in a 30-foot cube centered on a point you choose within range. Each creature in that area must make a Constitution saving throw. Constructs and undead aren't affected, and plants and water elementals make this saving throw with disadvantage. A creature takes 10d8 necrotic damage on a failed save, or half as much damage on a successful one.", + "source": "Elemental Evil", + "level": "8", + "range": "150 feet", + "casting_time": "1 Action", + "id": "406", + "slug": "abi-dalzims-horrid-wilting", + "scag": "0", + "page": "15", + "components": "V, S, M", + "ritual": "No", + "name": "Abi-Dalzim's Horrid Wilting", + "school": "Necromancy", + "ee": "1", + "classes": [ + "Sorcerer", + "Wizard" + ], + "duration": "Instantaneous", + "concentration": "No" + }, + "Absorb Elements ": { + "athigherlevel": " When you cast this spell using a spell slot of 2nd level or higher, the extra damage increases by 1d6 for each slot level above 1st.", + "description": "1 Reaction, which you take when you take acid, cold, fire, lightning, or thunder damage\n\nThe spell captures some of the incoming energy, lessening its effect on you and storing it for your next melee attack. You have resistance to the triggering damage type until the start of your next turn. Also, the first time you hit with a melee attack on your next turn, the target takes an extra 1d6 damage of the triggering type, and the spell ends.\r\n", + "source": "Elemental Evil", + "level": "1", + "range": "Self", + "casting_time": "Special", + "id": "377", + "slug": "absorb-elements", + "scag": "0", + "page": "15", + "components": "S", + "ritual": "No", + "name": "Absorb Elements ", + "school": "Abjuration", + "ee": "1", + "classes": [ + "Druid", + "Ranger", + "Wizard" + ], + "duration": "1 round", + "concentration": "No" + }, + "Acid Splash": { + "athigherlevel": "This spell's damage increases by 1d6 when you reach 5th level (2d6), 11th level (3d6), and 17th level (4d6).", + "description": "You hurl a bubble of acid. \nChoose one creature within range, or choose two creatures within range that are within 5 feet of each other. A target must succeed on a Dexterity saving throw or take 1d6 acid damage. \n\n", + "source": "Player's Handbook", + "level": "0", + "range": "60 feet", + "casting_time": "1 Action", + "id": "1", + "slug": "acid-splash", + "scag": "0", + "page": "211", + "components": "V, S", + "ritual": "No", + "name": "Acid Splash", + "school": "Conjuration", + "ee": "0", + "classes": [ + "Sorcerer", + "Wizard" + ], + "duration": "Instantaneous", + "concentration": "No" + }, + "Aganazzar's Scorcher": { + "athigherlevel": " When you cast this spell using a spell slot of 3rd level or higher, the damage increases by 1d8 for each slot level above 2nd.", + "description": "A line of roaring flame 30 feet long and 5 feet wide emanates from you in a direction you choose. Each creature in the line must make a Dexterity saving throw. A creature takes 3d8 fire damage on a failed save, or half as much damage on a successful one.\r\n", + "source": "Elemental Evil", + "level": "2", + "range": "30 feet", + "casting_time": "1 Action", + "id": "399", + "slug": "aganazzars-scorcher", + "scag": "0", + "page": "15", + "components": "V, S, M", + "ritual": "No", + "name": "Aganazzar's Scorcher", + "school": "Evocation", + "ee": "1", + "classes": [ + "Sorcerer", + "Wizard" + ], + "duration": "Instantaneous", + "concentration": "No" + }, + "Aid": { + "athigherlevel": "When you cast this spell using a spell slot of 3rd level or higher, a target's hit points increase by an additional 5 for each slot level above 2nd.", + "description": "Your spell bolsters your allies with toughness and resolve. \nChoose up to three creatures within range. Each target's hit point maximum and current hit points increase by 5 for the duration.", + "source": "Player's Handbook", + "level": "2", + "range": "30 feet", + "casting_time": "1 Action", + "id": "2", + "slug": "aid", + "scag": "0", + "page": "211", + "components": "V, S, M (a tiny strip of white cloth)", + "ritual": "No", + "name": "Aid", + "school": "Abjuration", + "ee": "0", + "classes": [ + "Cleric", + "Paladin" + ], + "duration": "8 hours", + "concentration": "No" + }, + "Alarm (Ritual)": { + "athigherlevel": "", + "description": "You set an alarm against unwanted intrusion. \r\nChoose a door, a window, or an area within range that is no larger than a 20-foot cube. Until the spell ends, an alarm alerts you whenever a tiny or larger creature touches or enters the warded area. When you cast the spell, you can designate creatures that won't set off the alarm. You also choose whether the alarm is mental or audible. \n\nA mental alarm alerts you with a ping in your mind if you are within 1 mile of the warded area. This ping awakens you if you are sleeping. \r\nAn audible alarm produces the sound of a hand bell for 10 seconds within 60 feet.", + "source": "Player's Handbook", + "level": "1", + "range": "30 feet", + "casting_time": "1 Minute", + "id": "3", + "slug": "alarm-ritual", + "scag": "0", + "page": "211", + "components": "V, S, M (a tiny bell and a piece of fine silver wire)", + "ritual": "Yes", + "name": "Alarm (Ritual)", + "school": "Abjuration", + "ee": "0", + "classes": [ + "Ranger", + "Wizard" + ], + "duration": "8 hours", + "concentration": "No" + }, + "Alter Self": { + "athigherlevel": "", + "description": "You assume a different form.\r\nWhen you cast the spell, choose one of the following options, the effects of which last for the duration of the spell. While the spell lasts, you can end one option as an action to gain the benefits of a different one.\r\n\r\nAquatic Adaptation. You adapt your body to an aquatic environment, sprouting gills, and growing webbing between your fingers. You can breathe underwater and gain a swimming speed equal to your walking speed.\r\n\r\nChange Appearance. You transform your appearnce. You decide what you look like, including your height, weight, facial features, sound of your voice, hair length, coloration, and distinguishing characteristics, if any. \r\nYou can make yourself appear as a member of another race, though none of your statistics change. You also don't appear as a creature of a different size than you, and your basic shape stays the same; if you're bipedal, you can't use this spell to become quadrupedal, for instance. At any time for the duration of the spell, you can use your action to change your appearance in this way again.\r\n\n Natural Weapons. You grow claws, fangs, spines, horns, or a different natural weapon of your choice. Your unarmed strikes deal 1d6 bludgeoning, piercing, or slashing damage, as appropriate to the natural weapon you chose, and you are proficient with your unarmed strikes. Finally, the natural weapon is magic and you have a +1 bonus to the attack and damage rolls you make using it.", + "source": "Player's Handbook", + "level": "2", + "range": "Self", + "casting_time": "1 Action", + "id": "4", + "slug": "alter-self", + "scag": "0", + "page": "211", + "components": "V, S", + "ritual": "No", + "name": "Alter Self", + "school": "Transmutation", + "ee": "0", + "classes": [ + "Sorcerer", + "Wizard" + ], + "duration": "Concentration, up to 1 hour", + "concentration": "Yes" + }, +} \ No newline at end of file diff --git a/server/homebrew.server.js b/server/homebrew.server.js index 7ea9099da..85c010252 100644 --- a/server/homebrew.server.js +++ b/server/homebrew.server.js @@ -7,15 +7,6 @@ var HomebrewModel = require('./homebrew.model.js').model; module.exports = function(app){ - /* - app.get('/homebrew/new', function(req, res){ - var newHomebrew = new HomebrewModel(); - newHomebrew.save(function(err, obj){ - return res.redirect('/homebrew/edit/' + obj.editId); - }) - }) - */ - //Edit Page app.get('/homebrew/edit/:id', function(req, res){ diff --git a/server/parsespell.js b/server/parsespell.js new file mode 100644 index 000000000..c53674023 --- /dev/null +++ b/server/parsespell.js @@ -0,0 +1,49 @@ +var _ = require('lodash'); + +var spells = require('./5espells.js'); + +String.prototype.replaceAll = function(s,r){return this.split(s).join(r)} + + +var parsedSpells = _.map(spells, (spell)=>{ + + var comp = {} + + var name = spell.name.replace(' (Ritual)', ''); + + + return { + id : _.snakeCase(name), + name : name, + description : spell.description + .replaceAll('\r\n', '\n') + .replaceAll(' ', ''), + + scales : spell.athigherlevel, + + components : {}, + classes : _.map(spell.classes || [], (cls)=>{return cls.toLowerCase();}), + + + level : Number(spell.level), + + ritual : spell.ritual == "Yes", + concentration : spell.concentration == "Yes", + + range : spell.range, + duration : spell.duration, + + + school : spell.school.toLowerCase(), + + source : spell.source, + page : spell.page, + } + + + + +}); + +module.exports = parsedSpells; + diff --git a/server/spellsort.server.js b/server/spellsort.server.js new file mode 100644 index 000000000..43d918ac0 --- /dev/null +++ b/server/spellsort.server.js @@ -0,0 +1,27 @@ +var _ = require('lodash'); +var vitreumRender = require('vitreum/render'); + + + +console.log(JSON.stringify(require('./parsespell.js'), null, ' ')); + + +module.exports = function(app){ + app.get('/spellsort*', (req, res)=>{ + vitreumRender({ + page: './build/spellsort/bundle.dot', + globals:{}, + prerenderWith : './client/spellsort/spellsort.jsx', + initialProps: { + url: req.originalUrl, + //spells : require('./spellsort.spells.js') + spells : require('./parsespell.js') + }, + clearRequireCache : !process.env.PRODUCTION, + }, function (err, page) { + return res.send(page) + }); + }); + + return app; +}; \ No newline at end of file diff --git a/server/spellsort.spells.js b/server/spellsort.spells.js new file mode 100644 index 000000000..84c20aa03 --- /dev/null +++ b/server/spellsort.spells.js @@ -0,0 +1,59 @@ +var _ = require('lodash'); + +var spells = [ + { + name : "Acid Splash", + casting_time : "1 action", + components : {v : true, s : true}, + description : `You hurl a bubble of acid. Choose one creature within range, or choose two creatures within range that are within 5 feet of each other. + A target must succeed on a Dexterity saving throw or take 1d6 acid damage.`, + scales : 'This spell’s damage increases by 1d6 when you reach 5th level (2d6), 11th level (3d6), and 17th level (4d6).', + duration : "Instantaneous", + concentration : false, + level : 0, + ritual : false, + range : "60 feet", + school : "Conjuration", + classes : ["sorcerer", "wizard"], + source : "Player's Handbook", + page : "pg.211" + }, + { + name : "Aid", + casting_time : "1 action", + components : {v : true, s : true, m : "(a tiny strip of white cloth)"}, + description : `Your spell bolsters your allies with toughness and resolve. Choose up to three creatures within range. Each target’s hit point maximum and current hit points increase by 5 for the duration. At Higher Levels. When you cast this spell using a spell slot of 3rd level or higher, a target’s hit points increase by an additional 5 for each slot level above 2nd.`, + duration : "8 hours", + concentration : false, + level : 2, + ritual : false, + range : "30 feet", + school : "Abjuration", + classes : [], + source : "Player's Handbook", + page : "pg.211" + }, + { + name : "Antimagic Field", + casting_time : "1 action", + components : {v : true, s : true, m : "(a pinch of powdered iron or iron filings)"}, + description : `A 10-foot-radius invisible sphere of antimagic surrounds you. This area is divorced from the magical energy that suffuses the multiverse. Within the sphere, spells can’t be cast, summoned creatures disappear, and even magic items become mundane. Until the spell ends, the sphere moves with you, centered on you. Spells and other magical effects, except those created by an artifact or a deity, are suppressed in the sphere and can’t protrude into it. A slot expended to cast a suppressed spell is consumed. While an effect is suppressed, it doesn’t function, but the time it spends suppressed counts against its duration. Targeted Effects. Spells and other magical effects, such as magic missile and charm person, that target a creature or an object in the sphere have no effect on that target. Areas of Magic. The area of another spell or magical effect, such as fireball, can’t extend into the sphere. If the sphere overlaps an area of magic, the part of the area that is covered by the sphere is suppressed. For example, the flames created by a wall of fire are suppressed within the sphere, creating a gap in the wall if the overlap is large enough. Spells. Any active spell or other magical effect on a creature or an object in the sphere is suppressed while the creature or object is in it. Magic Items. The properties and powers of magic items are suppressed in the sphere. For example, a +1 longsword in the sphere functions as a nonmagical longsword. A magic weapon’s properties and powers are suppressed if it is used against a target in the sphere or wielded by an attacker in the sphere. If a magic weapon or a piece of magic ammunition fully leaves the sphere (for example, if you fire a magic arrow or throw a magic spear at a target outside the sphere), the magic of the item ceases to be suppressed as soon as it exits. Magical Travel. Teleportation and planar travel fail to work in the sphere, whether the sphere is the destination or the departure point for such magical travel. A portal to another location, world, or plane of existence, as well as an opening to an extradimensional space such as that created by the rope trick spell, temporarily closes while in the sphere. Creatures and Objects. A creature or object summoned or created by magic temporarily winks out of existence in the sphere. Such a creature instantly reappears once the space the creature occupied is no longer within the sphere. Dispel Magic. Spells and magical effects such as dispel magic have no effect on the sphere. Likewise, the spheres created by different antimagic field spells don’t nullify each other.`, + duration : "Concentration, up to 1 hour", + concentration : true, + level : 8, + ritual : false, + range : "Self (10-foot-radius sphere)", + school : "Abjuration", + classes : [], + source : "Player's Handbook", + page : "pg.213" + } + +]; + + + +module.exports = _.map(spells, (spell)=>{ + spell.id = _.snakeCase(spell.name); + return spell; +}); \ No newline at end of file diff --git a/client/homebrew/phbStyle/border.png b/shared/naturalcrit/phbStyle/border.png similarity index 100% rename from client/homebrew/phbStyle/border.png rename to shared/naturalcrit/phbStyle/border.png diff --git a/client/homebrew/phbStyle/note_border.png b/shared/naturalcrit/phbStyle/note_border.png similarity index 100% rename from client/homebrew/phbStyle/note_border.png rename to shared/naturalcrit/phbStyle/note_border.png diff --git a/client/homebrew/phbStyle/phb.assets.less b/shared/naturalcrit/phbStyle/phb.assets.less similarity index 100% rename from client/homebrew/phbStyle/phb.assets.less rename to shared/naturalcrit/phbStyle/phb.assets.less diff --git a/client/homebrew/phbStyle/phb.fonts.css b/shared/naturalcrit/phbStyle/phb.fonts.css similarity index 100% rename from client/homebrew/phbStyle/phb.fonts.css rename to shared/naturalcrit/phbStyle/phb.fonts.css diff --git a/client/homebrew/phbStyle/phb.style.less b/shared/naturalcrit/phbStyle/phb.style.less similarity index 98% rename from client/homebrew/phbStyle/phb.style.less rename to shared/naturalcrit/phbStyle/phb.style.less index b358b74e0..83b26c3d0 100644 --- a/client/homebrew/phbStyle/phb.style.less +++ b/shared/naturalcrit/phbStyle/phb.style.less @@ -1,7 +1,7 @@ @import (less) 'shared/naturalcrit/styles/reset.less'; -@import (less) './client/homebrew/phbStyle/phb.fonts.css'; -@import (less) './client/homebrew/phbStyle/phb.assets.less'; +@import (less) 'shared/naturalcrit/phbStyle/phb.fonts.css'; +@import (less) 'shared/naturalcrit/phbStyle/phb.assets.less'; //Colors @background : #EEE5CE; @noteGreen : #e0e5c1; diff --git a/client/homebrew/phbStyle/red.png b/shared/naturalcrit/phbStyle/red.png similarity index 100% rename from client/homebrew/phbStyle/red.png rename to shared/naturalcrit/phbStyle/red.png diff --git a/todo.md b/todo.md index 032a25885..7d2a3baea 100644 --- a/todo.md +++ b/todo.md @@ -68,5 +68,6 @@ X Print Dialog now auto-opens on print page - should support `has:somatic`, `class:wizard`, `school:divination`, `level:6` - Add a dropdown box with clickable elements to inject search terms - Clean up the 5th edition spells json +- Split up the spells into separate josn based on the source