Backbone v1 for Backwater games

This commit is contained in:
Kurohyou
2022-12-22 11:26:42 -07:00
parent 5ab0ea8eb4
commit 2f490ee94e
173 changed files with 27960 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
node_modules/
Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1005 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 522 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 738 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 783 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.
+3
View File
@@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env"]
}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+5
View File
@@ -0,0 +1,5 @@
{
"ext":"pug, js, json, scss",
"ignore":["**/javascript/index.js","*.html","**/translation.json"],
"verbose":true
}
+13658
View File
File diff suppressed because it is too large Load Diff
+39
View File
@@ -0,0 +1,39 @@
{
"name": "Backbone",
"version": "1.0.0",
"description": "Below is the information on how the Backbone project will be handled and developed.",
"main": "index.js",
"scripts": {
"start": "nodemon render.js",
"test": "jest",
"wtest":"jest --watchAll"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/preset-env": "^7.16.11",
"babel-jest": "^27.5.1",
"jest": "^27.2.5",
"jest-summary-reporter": "^0.0.2",
"jsdom": "^20.0.0",
"nodemon": "^2.0.20",
"pug": "^3.0.2",
"sass-embedded": "^1.55.0",
"underscore": "^1.13.6"
},
"jest": {
"transform": {
"^.+\\.[t|j]sx?$": "babel-jest"
},
"reporters": [
"default",
[
"jest-summary-reporter",
{
"failuresOnly": false
}
]
]
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

+17
View File
@@ -0,0 +1,17 @@
const k = require('./source/scaffold');
const fs = require('fs/promises');
const jsdom = require('jsdom');
const { JSDOM } = jsdom;
const generate = async ()=>{
const [pugOut] = await k.all({source:'./source',destination:'./'});
const dom = new JSDOM(pugOut);
const { window } = dom;
const { document } = window;
const scriptContent = document.querySelector('script').innerHTML;
const scriptPrepend = await fs.readFile('./source/scaffold/scripts/mock20.js','utf8');
const scriptAppend = await fs.readFile('./source/scaffold/scripts/mockScaffold.js','utf8');
fs.writeFile('./source/javascript/index.js',`${scriptPrepend}\n${scriptContent}\n${scriptAppend}`);
}
generate();
+10
View File
@@ -0,0 +1,10 @@
{
"html": "backbone.html",
"css": "backbone.css",
"authors": "Scott Casey",
"roll20userid": "459831",
"preview": "preview.jpg",
"instructions": "This is the official sheet for the backbone system by [Backwater games](https://backwater-games.itch.io/).",
"legacy": false,
"compendium":"backbone"
}
+1
View File
@@ -0,0 +1 @@
&{template:backbone} {{character_name=John Smith of the overly complex surname}} {{title=Example Action That has some stupidly long name}} {{roll_name=Athletics}} {{roll=[[1d20+5]]}} {{damage=[[1d8+5]]}} {{description=Lorem ipsum dolor sit amet consectetur adipisicing elit. Id iure illum reprehenderit non minus voluptatem magni? Autem consequuntur rerum distinctio harum! Harum eaque culpa **tempore** [[1d100]] delectus unde officia? Doloribus id *deleniti* voluptatum eos? Nam, exercitationem voluptatum. Similique illum dolorum accusantium tenetur. Tenetur repellat consectetur, eum mollitia odit quod veritatis placeat? [Example button](!
Does a thing)}}
+7
View File
@@ -0,0 +1,7 @@
+tab({tabName:'npc',container:'article'})#npc
include npc/_header.pug
include npc/_basicStats.pug
include npc/_skills.pug
include npc/_weapons.pug
include npc/_abilities.pug
include npc/_gear.pug
+12
View File
@@ -0,0 +1,12 @@
include pc/_active_conditions.pug
+tab({tabName:'pc',container:'article'})#pc
include pc/_conditions.pug
include pc/_header.pug
include pc/_basic_stats.pug
include pc/_combat_stats.pug
include pc/_skills.pug
include pc/_gear.pug
include pc/_weapons.pug
include pc/_archetypes.pug
include pc/_traits.pug
include pc/_notes.pug
+19
View File
@@ -0,0 +1,19 @@
+hidden({name:'whisper',value:' '})
+tab({tabName:'settings',button:{class:'pictos',content:'y'},container:'article'})#settings
h1(data-i18n='settings')
+select-label({
inputObj:{name:'character type',class:'underlined',trigger:{
triggeredFuncs:['sheetTypeDisplay']
}},
spanObj:{'data-i18n':'character type'},
})
+option({'data-i18n':'pc',value:'pc',selected:''})
+option({'data-i18n':'npc',value:'npc'})
+select-label({
inputObj:{name:'whisper',class:'underlined',trigger:{
triggeredFuncs:['sheetTypeDisplay']
}},
spanObj:{'data-i18n':'whisper rolls to gm'},
})
+option({'data-i18n':'never',value:'',selected:''})
+option({'data-i18n':'always',value:'/w gm '})
@@ -0,0 +1,32 @@
section(aria-labelledby='npc-ability-header' id='npc-abilities').npc-abilities.npc-separator.repeating-container
h3(data-i18n='abilities')
+customControlFieldset({
name:'ability'
})
+collapse
.collapsed.inline
+roller({
name:'roll',
trigger:{triggeredFuncs:['rollRepeating']},
class:'inline-flex-box half-gap'
})
+span({name:'type','data-i18n-dynamic':''})
+span({name:'name'})
+span({name:'description',class:'inline-description'})
.expanded
.span-all.flex-box.half-gap.flex-wrap
+roller({name:'roll',trigger:{
triggeredFuncs:['rollRepeating']
}})
+select({name:'type',class:'underlined'})
+option({value:'','data-i18n':'select one'})
each value in ['action','blitz','counter','passive']
+option({value,'data-i18n':value})
+text({name:'name','data-i18n-placeholder':'name',class:'underlined flex-min-content'})
+skillSelect
.headed-textarea
h4(data-i18n='description')
+adaptiveTextarea({name:'description',class:'boxed'})
@@ -0,0 +1,25 @@
mixin npcCircleAttribute(name,attrName,i18n)
.overlay-content
div(class=attrName || name).circle.basic-border.ratio1-1
+input-label({
inputObj:{type:'number',name:attrName || name},
spanObj:{'data-i18n':i18n || `${name} abbreviation`,role:'heading','aria-level':3},
divObj:{class:`stacked center no-gap overlaid-content`}
})
section#npc-stats.tiny-gap.npc-separator
.attributes.flex-box.half-gap.justify-space-around.flex-wrap
each name in attributes
+attributeHolder(name)
.armor-movement.flex-box.half-gap.justify-space-around.flex-wrap
each name in ['health','resolve']
+npcCircleAttribute(name,`${name} max`,name)
each obj in [...movementArmor,{name:'adrenaline'}]
+npcCircleAttribute(obj.name)
.characteristics.half-gap.justify-space-between
each obj,name in characteristics
+input-label({
inputObj:{name,type:'number',class:'underlined'},
spanObj:{'data-i18n':`${name}-abbreviation`,role:'heading','aria-level':3},
divObj:{class:'no-gap'}
})
+3
View File
@@ -0,0 +1,3 @@
section(aria-labelledby='npc-gear-header' id='npc-gear').npc-gear
h3(data-i18n='items')
+adaptiveTextarea({name:'npc items',class:'boxed'})
+10
View File
@@ -0,0 +1,10 @@
section#npc-header.half-gap.align-items-end
+text({name:'character name',value:'',role:'heading','aria-level':2,class:'underlined'})
+dual-input-label({
inputArr:[
{type:'number',name:'difficulty size',class:'underlined'},
{type:'number',name:'difficulty level',class:'underlined'}
],
spanObj:{'data-i18n':'difficulty level abbreviation',class:'uppercase'},
separator:'-'
})
+34
View File
@@ -0,0 +1,34 @@
-
const skillRefs = {
skill: {i18n: 'skills', collection:basicSkills},
specialty: {i18n: 'specialty skills'},
combat: {i18n: 'combat skills', collection:combatSkills}
};
mixin npcSkillContainer(skill)
div(class=`npc-${skill.replace(/\s+/g,'-').replace(/\(|\)|\//g,'')}-container`).input-label.collapse-container.avoid-break
+roller({
name:skill,
role:'heading',
'aria-level':3,
'data-i18n':skill
})
+plusControl({
name:skill,
classAdd:'collapsed',
defaultValue:''
})
+number({
name:skill,
class:'expanded underlined',
trigger:{
triggeredFuncs:['displayNPCSkill']
}
})
//- End mixin
.collapse-container
+collapse('npc skills')
each name in ['skill','combat']
section(aria-labelledby=`npc-${name}-header` id=`npc-${name}`).collapse-container.npc-skill-container
h3(data-i18n=skillRefs[name].i18n id=`npc-${name}-header`)
each obj in skillRefs[name].collection
+npcSkillContainer(obj.name)
+28
View File
@@ -0,0 +1,28 @@
section(aria-labelledby='npc-weapon-header' id='npc-weapons').npc-weapons.npc-separator.repeating-container
h3(data-i18n='attacks')
+customControlFieldset({
name:'weapon'
})
+collapse
.collapsed.flex-box.flex-wrap.half-gap
+roller({
name:'roll',
trigger:{triggeredFuncs:['rollRepeating']},
class:'flex-box half-gap'
})
+span({name:'skill','data-i18n-dynamic':''})
+span({name:'name'})
+hidden({name:'damage',value:'',class:'empty-hider'})
.flex-box.tiny-gap
+span({name:'damage'})
span(data-i18n='damage-abbreviation')
+hidden({name:'range',value:'',class:'empty-hider'})
.flex-box.tiny-gap
span(data-i18n='range')
+span({name:'range'})
.expanded
+weaponDetails(true)
+sizeAndSlot
+adaptiveTextarea({name:'description',class:'boxed'}).description
@@ -0,0 +1,8 @@
ul(data-container-tab="backbone" data-tab="pc").tabs__container.flex-box.flex-wrap.justify-center.condition-summary.half-gap
each condition in conditions
+checkbox({name:condition,value:1,hidden:'',class:'display-control',trigger:{
triggeredFuncs:['resetCondition']
}})
li(class=`condition-item--${condition}`).condition-item.flex-box.tiny-gap
+conditionCheck(condition)
+inputWithControls({name:`track ${condition}`,type:'number',class:'underlined'})
@@ -0,0 +1,15 @@
section#archetype.repeating-container
h2(data-i18n='abilities').header
+customControlFieldset({
name:'ability'
})
+collapse
.span-all.flex-box.half-gap.flex-wrap
+roller({name:'roll',trigger:{
triggeredFuncs:['rollRepeating']
}})
+text({name:'name','data-i18n-placeholder':'name',class:'underlined flex-min-content'})
+skillSelect
.headed-textarea.expanded
h4(data-i18n='description')
+adaptiveTextarea({name:'description',class:'boxed'})
@@ -0,0 +1,64 @@
section(data-i18n-aria-label="basic stats")#basic-stats
.characteristics
h2(data-i18n='characteristics')
-
const groupHolder = Object.values(characteristics).reduce((acc,obj)=>{
const endIndex = Math.max(acc.length - 1,0)
if(!acc[endIndex] || acc[endIndex][1]){
const dest = [];
dest.push(obj);
acc.push(dest);
}else{
acc[endIndex].push(obj);
}
return acc;
},[]);
each arr in groupHolder
.even-flow
each obj in arr
- const trigger = {affects:obj.affects};
+statContainer({class:obj.name})
+input-label({
inputObj:{name:obj.name,type:'number',trigger},
spanObj:{'data-i18n':`${obj.name}-abbreviation`,role:'heading','aria-level':3},
divObj:{class:'stacked center no-gap'}
})
.attributes
h2(data-i18n='attributes')
-
const attrHolder = attributes.reduce((acc,name) => {
const endIndex = Math.max(acc.length - 1,0)
if(!acc[endIndex] || acc[endIndex][1]){
const dest = [];
dest.push(name);
acc.push(dest);
}else{
acc[endIndex].push(name);
}
return acc;
},[]);
each arr in attrHolder
.even-flow
each name in arr
+attributeHolder(name)
.armor-movement.collapse-container
+collapse('armor-collapse')(checked)
h2(data-i18n='armor-movement')
each obj in movementArmor
+statContainer({class:obj.name.replace(/\s.+/,'')}).circle
+input-label({
inputObj:{type:'number',...obj},
spanObj:{'data-i18n':`${obj.name} abbreviation`,role:'heading','aria-level':3},
divObj:{class:`stacked center no-gap`}
})
.headed-textarea.armor-details.collapse-container.tiny-gap
.flex-box.half-gap(style="width:100%")
+text({name:'armor name',value:'','data-i18n-placeholder':'equipped armor',class:'flex-min-content underlined'})
+action({
name:'unequip armor',
'data-i18n':'unequip',
class:'control-button',
trigger:{triggeredFuncs:['equipArmor']}
})
+adaptiveTextarea({name:'armor details',class:'boxed underlined--light'}).expanded
@@ -0,0 +1,32 @@
section(data-i18n-aria-label="combat stats")#combat-stats
each name in ['health','resolve']
.health-container
+statContainer({class:name})
+roller-label({
inputObj:{name:name,type:'number'},
buttonObj:{name,'data-i18n':name,role:'heading','aria-level':3,trigger:{
triggeredFuncs:['rollHealthCheck']
}},
divObj:{class:'stacked center'}
})
+statContainer({class:`${name} max`})
+input-label({
inputObj:{name:`${name} max`,type:'number'},
spanObj:{'data-i18n':'maximum',role:'heading','aria-level':3},
divObj:{class:'stacked'}
})
.luck-container
h3(data-i18n='luck')
each value in ['odd','even']
+input-label({
inputObj:{name:'luck',type:'radio',value},
spanObj:{'data-i18n':value}
})
+roller({name:'luck',role:'heading','aria-level':3,trigger:{triggeredFuncs:['rollLuck']}})
.adrenaline-container.input-label
label(for='adrenaline')
h3(data-i18n='adrenaline')
.parens-holder.adrenaline
span.parentheses.large-parentheses (
+inputWithControls({name:'adrenaline',id:'adrenaline',type:'number'})
span.parentheses.large-parentheses )
@@ -0,0 +1,10 @@
aside#pc-conditions.pc-conditions.sidebar.sidebar--left.conditions-sidebar.fresh
+action({
name:'condition display',
class:'sidebar-toggle sidebar--right fresh',
trigger:{triggeredFuncs:['showConditions']}
})
h4(data-i18n="conditions")
.flex-box.flex-wrap.justify-center
each condition in conditions
+conditionCheck(condition)
+66
View File
@@ -0,0 +1,66 @@
section#gear.tall-2
.coin
h2(data-i18n='coin & assets')
each name in ['credit','coin']
+input-label({
inputObj:{name,type:'number',class:'underlined'},
spanObj:{'data-i18n':name},
})
+input-label({
inputObj:{name:'badge',type:'text',class:'underlined'},
spanObj:{'data-i18n':'badge'},
})
.input-label
span(data-i18n='clothes').input-label__text
+adaptiveInput({name:'clothes',class:'underlined'}).input-label__input
.repeating-container.equipped
.flex.header.center
h2(data-i18n='equipped gear')
+checkbox({name:'overburdened',value:1,hidden:'',class:'over-equip-control',trigger:{
calculation:'calcOverburdened'
}})
+dual-input-label({
inputArr:[
{name:'item slots',type:'number',readonly:'',class:'underlined',trigger:{affects:['overburdened'],calculation:'calcUsedSlots'}},
{name:'item slots max',type:'number',class:'underlined',trigger:{affects:['overburdened'],calculation:'calcItemSlotsMax'}}
],
spanObj:{'data-i18n':'item slots'}
})
+customControlFieldset({
name:'equipped'
})
+collapse
.flex-box.half-gap.span-all.align-items-center
+checkbox({name:'equipped',value:1,checked:'',trigger:{triggeredFuncs:['equipItem'],affects:['item slots']}})
+text({name:'name',class:'underlined flex-min-content'})
+dual-input-label({
inputArr:[{name:'uses',type:'number',class:'underlined'},{name:'uses max',type:'number',class:'underlined expanded'}],
spanObj:{'data-i18n':'uses'},
divObj:{class:'collapse-container'},
separatorObj:{content:'/',class:'expanded'}
})
+roller({name:'roll',trigger:{
triggeredFuncs:['rollRepeating']
}})
+skillSelect.expanded.skill
+sizeAndSlot
+adaptiveTextarea({name:'description',class:'boxed'}).description.expanded
.repeating-container.stored
h2(data-i18n='stored gear').header
+customControlFieldset({
name:'stored'
})
+weaponDetails
+sectionControl({name:'type',value:'gear'}).expanded.gear
+dual-input-label({
inputArr:[{name:'uses',type:'number',class:'underlined'},{name:'uses max',type:'number',class:'underlined'}],
spanObj:{'data-i18n':'uses'}
})
+skillSelect.expanded.skill
+sectionControl({name:'type',value:'armor'}).expanded.gear
+input-label({
inputObj:{name:'armor bonus',type:'number',class:'underlined'},
spanObj:{'data-i18n':'armor bonus'}
})
+sizeAndSlot
+adaptiveTextarea({name:'description',class:'boxed'}).description.expanded
+16
View File
@@ -0,0 +1,16 @@
section#character-info.span-all
div
each name,i in ['character name','age','gender']
- inputObj = {name,class:'underlined',type:'text'};
if i > 0
- inputObj.class += ' text-center';
+input-label({
inputObj,
spanObj:{'data-i18n':name.replace(/character /,''),role:'heading','aria-level':2}
})
div
each obj in [{name:'origin',type:'text'},{name:'dialect',type:'text'},{name:'level',type:'number'},{name:'archetype',type:'text'},{name:'ideals',type:'text'},{name:'fortune',type:'text'}]
+input-label({
inputObj:{name:obj.name,class:'underlined',type:obj.type},
spanObj:{'data-i18n':obj.name,role:'heading','aria-level':2}
})
+5
View File
@@ -0,0 +1,5 @@
each name in ['backstory','notes']
section(id=name)
.headed-textarea
h2(data-i18n=name)
+adaptiveTextarea({name:name,class:'boxed'})
+33
View File
@@ -0,0 +1,33 @@
section(aria-label="skills")#skills.tall-2
.basic-skills
div
h2(data-i18n='basic-skills' style='column-span:all;')#basic-skills
.input-label
span(data-i18n='skill points').input-label__text
+inputWithControls({name:'skill points',type:'number',class:'underlined'})
.skill-container
+skillRows(basicSkills)
.combat-skills
h2(data-i18n="combat skills")
+skillRows(combatSkills)
.specialty-skills.repeating-container
h2(data-i18n="specialty skills").header
+customControlFieldset({
name:'specialty',
})
+roller({name:'roll',role:'heading','aria-level':3,class:'dicefontd20',trigger:{
triggeredFuncs:['rollSkill']
}})
+text({name:'name',class:'underlined skill-name'})
+fillLeft({
radioObj:{name:`proficiency`,value:-1},
divObj:{class:'proficiency'},
valueArray:[-1,0,1,2,3,4],
noClear:true,
displayValues:['-1','+0','+1','+2','+3','+4']
})
+select({name:'characteristic'})
+option({value:'','data-i18n':'select',selected:''})
each obj,value in characteristics
+option({value,'data-i18n':`${value} abbreviation`})
+checkbox({name:`${name} mastery`,value:1,class:'mastery'})
+16
View File
@@ -0,0 +1,16 @@
section#favorable-traits.repeating-container
h3(data-i18n='favorable traits').header
+customControlFieldset({
name:'favorable'
})
+collapse
+text({name:'name',class:'underlined'})
+adaptiveTextarea({name:'description',class:'boxed'}).expanded
section#unfavorable-traits.repeating-container
h3(data-i18n='unfavorable traits').header
+customControlFieldset({
name:'unfavorable'
})
+collapse
+text({name:'name',class:'underlined'})
+adaptiveTextarea({name:'description',class:'boxed'}).expanded
+24
View File
@@ -0,0 +1,24 @@
section#weapons.repeating-container
h2(data-i18n='equipped weapons').header
+customControlFieldset({
name:'weapon',
trigger:{
addFuncs:['addWeapon']
}
})
+weaponDetails(true)
+sizeAndSlot
+adaptiveTextarea({name:'description',class:'boxed'}).description.expanded
.flex-box.gap.flex-wrap.justify-center
- let ammoCount = 1;
each i in [1,2]
.ammo-container.flex-box.half-gap.align-items-center
+text({name:`container ${i}`,type:'text',class:'underlined container-name','data-i18n-placeholder':'ammo container'})
each n in [1,2]
.parens-holder
span.parentheses.large-parentheses (
.flex-box.stacked.center
+number({name:`ammo ${ammoCount}`,class:'underlined'})
+text({name:`ammo type ${ammoCount}`,'data-i18n-placeholder':'type',class:'ammo-type'})
- ammoCount++;
span.parentheses.large-parentheses )
@@ -0,0 +1,211 @@
//This file will store all of our generic styling for the sheet. Styling for specific sections will be done in individual scss files to make the code easier to read.
@use 'mixinsandplaceholders';
@use 'systemVariables';
@use 'placeholders/systemPlaceholders';
@import url('https://fonts.googleapis.com/css?family=IM+Fell+English+SC|Trade+Winds|Material+Icons&display=swap');
html{
font-size:16px;
}
.ui-dialog{
@extend %systemVariables;
.tab-content .charsheet{
.repitem{
.roller:nth-last-child(3){
padding-right:var(--half-gap);
}
}
.large-parentheses {
align-items: center;
font-size: 2rem;
}
.fill-left__radio[data-value]:checked:before{
font-family:var(--contentFont);
}
.parentheses{
font-family:var(--topHeaderFont);
}
.text-center{
text-align: center;
}
.input-controls{
display:grid;
grid-template-columns: [input-start increment-start] auto [increment-end] 1fr [decrement-start] auto [input-end decrement-end];
grid-template-rows: [increment-start input-start decrement-start] auto [increment-end input-end decrement-end];
> input{
grid-area:input;
}
}
.input-control--button{
font-family:var(--topHeaderFont);
z-index:100;
&:first-of-type{
grid-area:increment;
}
&:last-of-type{
grid-area:decrement;
}
}
.even-flow{
gap:inherit;
display:flex;
}
/*
First of all we apply our default styles.
Note that because we are using the placeholder, these styles would be first up in the cascade even if we put the extend declaration last.
This is done first so that when we read the code, we can easily see that it is applied, and anything after it will overwrite those default styles.
*/
// Clears the default Roll20 styling from all elements so that we can style them as we want more easily. We are using 3 classes here because we have to use at least that level of specificity to overcome many of the default Roll20 styles.
@extend %defaultStyles;
padding-top:0;
.roller{
&:not([role]){
@extend %h4;
}
display:flex;
gap:var(--half-gap);
align-items:center;
&:before{
font-family:dicefontd20;
content:'T'
}
}
button{
color:var(--fontColor);
cursor:pointer;
}
h3{
grid-area:header;
}
.styled-button{
@extend %sectionBoxShadow;
background-color: var(--backColor);
border: 0;
border-radius: .5rem;
box-sizing: border-box;
cursor:pointer;
transition: {
property:background-color,color;
duration:var(--revealTime);
};
padding-inline:var(--half-gap);
text-align:center;
&:hover {
background-color: var(--selectedColor);
&,
& *{
color:var(--dark-secondarytext);
}
}
&:focus {
outline: 2px solid transparent;
outline-offset: 2px;
}
&:focus-visible {
box-shadow: none;
}
}
.styled-button--controlled,
.styled-button--controlled *{
@extend %h4;
}
.styled-button-control:is(:checked,[type='hidden']:not([value='']):not([value='0'])) + .styled-button--controlled{
background-color:var(--selectedColor);
&,
& *{
color:var(--dark-secondarytext);
}
}
.parens-holder{
display:flex;
align-items:center;
> .input-label{
gap:0;
span{
font-size:.8rem;
}
}
}
.stat-container{
--shadowSize: 1px;
border:2px solid var(--fontColor);
display:flex;
flex-direction:column;
align-items:center;
break-inside:avoid;
aspect-ratio: 1 / 1;
justify-content: center;
&:not(.circle){
border-radius:20px;
}
}
:is(.stat-container,.overlay-content){
.input-label__text,
.roller{
text-shadow:
var(--shadowSize) 0 var(--backColor),
calc( var(--shadowSize) * -1 ) 0 var(--backColor),
0px var(--shadowSize) var(--backColor),
0px calc( var(--shadowSize) * -1 ) var(--backColor);
}
}
.circle{
@extend %circle;
}
.overlay-content{
display:grid;
grid-template-areas:content;
place-items:center;
> * {
grid-area:content !important;
}
> .overlaid-content{
z-index: 100;
}
}
.basic-border{
border: 2px solid var(--fontColor);
}
.avoid-break{
break-inside: avoid;
}
article{
position:relative;
}
.text-check{
span{
transition: {
duration:var(--revealTime);
property:color,background-color;
};
}
> input:checked{
+ span{
background-color:var(--selectedColor);
color:var(--backColor);
}
}
}
}
}
.ui-dialog .sheetform{
background-color:var(--backColor);
transition: {
property:background-color;
duration:var(--revealTime);
};
}
.sheet-darkmode .ui-dialog{
@extend %darkmodeStyle;
--imgInvert:invert(0.9);
}
//the declarations for styles specifically applying to our main element.
#main{
display:grid;
grid-area:content;
}
@@ -0,0 +1,40 @@
//- This file will store all mixins and placeholders that have generic use
@use 'placeholders/materialIcons';
@use 'placeholders/pictos';
@use 'placeholders/hidden';
@use 'placeholders/textLevel';
@use 'placeholders/button';
@use 'placeholders/inputBase';
@use 'placeholders/inputlabel';
@use 'placeholders/collapse';
@use 'placeholders/adaptiveInputs';
@use 'placeholders/headedText';
@use 'placeholders/borderPlaceholders';
@use 'placeholders/fieldsetStyling';
@use 'placeholders/sizingAndRatio';
@use 'placeholders/fillLeft';
@use 'placeholders/layout';
//- Default styles. This Placeholder gets a little complicated. We're going to define several CSS variables in the first lines that will allow us to easily use the same layout principles across the sheet. Additionally, this placeholder is going to apply several styles to various elements. The reason we do this as a placeholder instead of directly in a class' CSS declaration is so that we can easily apply the same styling to our sheet as a whole and to the rolltemplate (note that many of these class specifications have versions prefixed and unprefixed with `.sheet-`
%defaultStyles{
@extend %textElements;
@extend %materialIcons;
@extend %hideBase;
@extend %textStyles;
@extend %headerElements;
@extend %inputBase;
@extend %button;
@extend %r20FontClasses;
@extend %input-label;
@extend %headed-textarea;
@extend %borderStyles;
@extend %adaptiveText;
@extend %sizesAndRatios;
@extend %collapsible;
@extend %fieldsetStyling;
@extend %fillLeft;
@extend %layout;
}
@@ -0,0 +1,10 @@
.ui-dialog .tab-content .charsheet {
select,
textarea,
input,
.uneditable-input,
label,
button {
all: initial;
}
}
@@ -0,0 +1,161 @@
@use 'mixinsandplaceholders';
@use 'systemVariables';
@use 'placeholders/systemPlaceholders';
.sheet-rolltemplate-backbone{
@extend %systemVariables;
@extend %defaultStyles;
--backColor:#FCF5E5;
--borderImgRadiusFit:20px;
margin-right:-16px;
margin-left:-45px;
margin-bottom:-7px;
padding:var(--grid-gap);
&:not(:first-child){
margin-top:var(--grid-gap);
}
.sheet-image-border{
position: absolute;
inset: 0;
border: var(--maskSize) solid;
border-image-source: var(--borderImageSource);
border-image-slice: var(--borderImageSlice);
border-image-width: var(--maskSize);
border-image-repeat: round;
pointer-events: none;
z-index:-1;
}
.sheet-template{
position:relative;
padding:4px;
isolation:isolate;
filter: drop-shadow(var(--shadowSize) 0 var(--shadowBlur) var(--shadowColor)) drop-shadow(calc(var(--shadowSize) * -1) 0 var(--shadowBlur) var(--shadowColor)) drop-shadow(0 var(--shadowSize) var(--shadowBlur) var(--shadowColor)) drop-shadow(0 calc(var(--shadowSize) * -1) var(--shadowBlur) var(--shadowColor)) drop-shadow(var(--shadowSize) 0 calc(var(--shadowBlur) * 1.5 ) var(--shadowColor2)) drop-shadow(calc(var(--shadowSize) * -1) 0 calc(var(--shadowBlur) * 1.5 ) var(--shadowColor2)) drop-shadow(0 var(--shadowSize) calc(var(--shadowBlur) * 1.5 ) var(--shadowColor2)) drop-shadow(0 calc(var(--shadowSize) * -1) calc(var(--shadowBlur) * 1.5 ) var(--shadowColor2));
> :nth-child(2){
border-top-left-radius: var(--borderImgRadiusFit);
border-top-right-radius: var(--borderImgRadiusFit);
}
> :last-child{
border-bottom-left-radius: var(--borderImgRadiusFit);
border-bottom-right-radius: var(--borderImgRadiusFit);
}
p,span{
font-size:1.3rem;
}
p{
overflow-y:auto;
max-height:30rem;
margin:0;
}
a{
background-color:transparent;
border:none;
padding:0;
color:var(--fontColor);
font-weight:700;
&[href^='!'],
&[href^='~']{
display:inline-grid;
grid-template-columns:10px auto;
grid-template-areas: 'icon text';
&:before{
content:'';
background:{
image: url('https://s3.amazonaws.com/files.d20.io/images/305391097/UIK_ZAJSwqtkuDg5I2g_LQ/original.png?16636241805');
repeat:no-repeat;
size:contain;
position:center;
}
}
}
}
}
@mixin pureResult{
position:relative;
display:flex;
align-items:center;
&:before{
position:absolute;
left:-24px;
}
}
@mixin pureSuccess{
&:before{
content:'';
display:block;
background-image:var(--successCircle);
background-repeat:no-repeat;
background-size:contain;
width: 24px;
height:24px;
}
}
@mixin pureFail{
&:before{
content:'';
display:block;
background-image:var(--failCircle);
background-repeat:no-repeat;
background-size:contain;
width: 24px;
height:24px;
}
}
.sheet-content{
padding: var(--big-gap);
.inlinerollresult{
@extend %h3-style;
background-color: transparent;
border:0px solid transparent;
font-weight:700;
&.fullcrit{
color:green;
}
&.fullfail{
color:red;
}
&.importantroll{
color:blue;
}
}
.sheet-pure-success{
+ .inlinerollresult{
color:var(--fontColor) !important;
@include pureResult;
&.fullcrit{
color:var(--fontColor);
@include pureSuccess
}
&.fullfail{
color:var(--fontColor);
@include pureFail;
}
}
}
.sheet-result .inlinerollresult{
@extend %h1;
font-size:3rem;
}
.sheet-result--no-crit{
.inlinerollresult{
color:var(--fontColor);
}
}
.sheet-result--is-fumble{
.inlinerollresult{
@include pureResult;
@include pureFail;
}
}
.sheet-result--is-crit{
.inlinerollresult{
@include pureResult;
@include pureSuccess;
}
}
}
.sheet-description{
width:100%;
}
}
@@ -0,0 +1,36 @@
@use 'placeholders/defaultVariables';
@use 'placeholders/darkmode';
%systemVariables{
@extend %universalVariables;
// Color component variables
--errorColor:red;
// Images
--failCircle: url('https://s3.amazonaws.com/files.d20.io/images/318562209/I3x7bfc3_M_QcFnt8tV85Q/original.png?16710625345');
--successCircle: url('https://s3.amazonaws.com/files.d20.io/images/318562210/oX_VbZJwiNoujxFnSVumpA/original.png?16710625345');
--conditionIcon: url('https://s3.amazonaws.com/files.d20.io/images/318557936/fEiMDUb_UctEstYyXkKlEA/original.png?16710607145');
--heart:url('https://s3.amazonaws.com/files.d20.io/images/303476002/EGcfkMfeF7mIRowjCyVy-w/original.png?16625716925');
--boot:url('https://s3.amazonaws.com/files.d20.io/images/303476005/Ap6DSJSqAVUkpkEwmKazPA/original.png?16625716925');
--bolt:url('https://s3.amazonaws.com/files.d20.io/images/303476003/7La7gESx4Th7OYnkHc4u2Q/original.png?16625716925');
--flame:url('https://s3.amazonaws.com/files.d20.io/images/303476004/9l3GwDqA2PNTAULgIvC8EA/original.png?16625716915');
--armor:url('https://s3.amazonaws.com/files.d20.io/images/303476001/9BHZGaCcM8H3wbj2W23zdw/original.png?16625716925');
--skull: url('https://s3.amazonaws.com/files.d20.io/images/303477021/Vm1A4GWATnboxP65WqEW0A/original.png?16625722085');
--borderImageSource: url(https://s3.amazonaws.com/files.d20.io/images/312349470/ovngRYPae8cWAT9W489wJw/original.png?166741640555);
--borderImageSlice: 175 fill;
--maskSize: 20px;
--shadowSize: 0px;
--shadowBlur: 4px;
--shadowColor: rgb(0 0 0 / 0.2);
--shadowColor2: rgb(0 0 0 / 0.1);
// Fonts
--topHeaderFont: 'Trade Winds', cursive;
--midHeaderFont: 'IM Fell English SC';
--contentFont: 'IM Fell English SC';
--radioSize:15px;
--columnSize:370px;
--imgInvert: invert(0);
}
@@ -0,0 +1,43 @@
@use '_borderPlaceholders.scss';
%adaptiveText{
.adaptive{
display:grid;
grid-template-columns: auto;
grid-template-rows: auto;
grid-template-areas: "content";
position:relative;
>*{
grid-area: content;
}
> span{
opacity: 0;
z-index: -10;
@extend %base-border;
text-transform: initial;
border-radius:0px;
}
}
.adaptive--text{
min-height:4rem;
}
.adaptive--text__span{
white-space: pre-wrap;
padding:2px;
}
.adaptive--text__textarea{
width:100%;
height:100%;
resize: none;
}
.adaptive--text__textarea,
.adaptive--input__input{
position:absolute;
}
.adaptive--input__input{
width:100%;
}
.adaptive--input__span{
padding:2px;
min-height:1.5rem;
}
}
@@ -0,0 +1,60 @@
//- Creates our basic border for inputs
%inputHighlight{
border-width: 1px 3px;
border-style: solid;
border-color: var(--borderColor);
border-radius: 5px;
box-sizing: border-box;
}
%base-border{
border-width: 1px 3px;
border-style: solid;
border-radius: 5px;
border-color: transparent;
box-sizing: border-box;
}
//- Styling for elements that should have a box around them
%boxed{
border: 2px solid var(--borderColor);
border-radius:0;
box-sizing:border-box;
}
%borderStyles{
.boxed,
.sheet-boxed{
@extend %boxed;
&.thick-left{
border-left-width: 5px;
}
&.thick-bottom{
border-bottom-width: 5px;
}
&.thick-right{
border-right-width: 5px;
}
&.thick-top{
border-top-width: 5px;
}
}
.underlined,
.sheet-underlined{
@extend %base-border;
border-radius: 0;
border-bottom: 1px solid var(--borderColor);
transition: var(--focusTrans);
}
:is(.underlined,.boxed){
&:not([readonly]):not([type='checkbox']):not([type='radio']):is(:hover, :focus,:focus-within){
@extend %inputHighlight;
}
&:not([readonly]):not([type='checkbox']):not([type='radio']):is(:focus,:focus-within){
background-color: var(--subHeadBackColor);
}
}
.underlined--invisible{
border-color:transparent !important;
}
}
%sectionBoxShadow{
box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px;
}
@@ -0,0 +1,81 @@
@use 'textLevel';
@use 'borderPlaceholders';
//- Our basic button styling
%base-button{
background-color: #DCDCDC33;
border-radius: 5px;
box-shadow: 0 2px 4px black;
border-width: 0;
transition: {
property:box-shadow,backdrop-filter;
duration:200ms;
timing-function:ease-out;
};
backdrop-filter:blur(1px);
overflow:hidden;
&:is(:hover,:focus){
background-color: #85858580;
box-shadow: 0 4px 6px black;
backdrop-filter:blur(2px);
}
&:active{
background-color: #858585ff;
box-shadow: 0 1px 2px black;
backdrop-filter:blur(0px);
}
}
//- Styling for our dice buttons
%die-button{
@extend %base-button;
line-height: 14px;
/*height to vertically center a 2rem dicefontd10*/
font-size: 2rem;
font-weight: normal;
font-style: normal;
padding: 5px 3px 7px;
}
//- styling for buttons that have standard text in them
%text-button{
padding: 5px 7px;
@extend %base-button;
}
//- Styling for our roll buttons
%roller{
display: inline-flex;
align-items: center;
align-self:start;
gap: var(--half-gap);
color:var(--fontColor);
&:before{
content:'L';
font-family:dicefontd6;
}
}
%button{
button{
cursor: pointer;
}
.roller{
display:flex;
gap:var(--half-gap);
align-items:center;
&:before{
font-family:dicefontd20;
content:'T'
}
}
.control-button{
@extend %inputHighlight;
align-self:center;
padding-inline:var(--tiny-gap);
transition: {
property: background-color, color;
duration: var(--revealTime);
timing-function: ease;
}
&:hover{
background-color:var(--borderColor);
color:var(--backColor);
}
}
}
@@ -0,0 +1,83 @@
@use 'borderPlaceholders';
@use 'materialIcons';
%collapsible{
.collapse-container{
position:relative;
}
.text-collapse{
cursor:pointer;
display:flex;
justify-content:flex-start;
align-items:center;
&:before{
content:'unfold_less';
@extend %materialStyle;
}
}
.text-collapse__text{
display:inline;
}
.text-collapse__check{
&:not(:checked) + .text-collapse{
@extend %inputHighlight;
}
&:checked + .text-collapse:before{
content:'unfold_more';
}
}
.repitem,
.collapse-container{
&:hover{
.collapse,.roll-container{
opacity:1;
}
}
.collapse{
opacity:0;
position:absolute;
right:-10px;
top:0px;
border:0px solid black;
border-radius:0;
color:var(--selectedColor);
text-transform:none;
background-color:transparent;
&:before{
content:'y';
font-family:pictos;
}
&:checked{
color:var(--unselectedColor1);
background-color:transparent;
~ .expanded,
~ .collapse-container .expanded{
display:none !important;
}
~ .expanded--empty:is(:not([value]),[value='']) + *,
~ .collapse-container ~ .expanded--empty:is(:not([value]),[value='']) + *{
display:none !important;
}
}
&:not(:checked){
~ .collapsed,
~ .collapse-container .collapsed{
display:none !important;
}
}
&:hover{
color:var(--selectedColor);
}
}
}
.repcontainer.editmode{
.collapse{
display:none;
}
}
.section-control:not(:checked) + .section-display{
display:none !important;
}
.empty-hider:is([value=''],:not([value])) + *{
display:none;
}
}
@@ -0,0 +1,12 @@
//- A placeholder for creating a stackable grid of elements. Particularly for making stacked input labels.
%darkmodeStyle{
--borderColor: var(--dark-secondarytext);//Our basic border color
--fontColor: var(--dark-secondarytext);//Our basic font color
--backColor: var(--dark-surface1);//Set our background to match the dark mode background of the sheet
--selectedColor:var(--fontColor);
--subHeadBackColor:var(--dark-primary);
--checkColor: var(--darkCheck);
img{
filter: brightness(.8) contrast(1.2);
}
}
@@ -0,0 +1,39 @@
//Our various fonts that can be used on the sheet. For now, these are all set to Arial until we find fonts we like, which won't be done until the very end.
%font-vars{
--topHeaderFont:Arial;
--midHeaderFont:Arial;
--contentFont:Arial;
}
%universalVariables{
// Layout variables
--grid-gap: 1rem;//Variable to define our basic gap between layout elements. Followed by several gaps that are mathematically related to it.
--half-gap: calc(var(--grid-gap) / 2);
--tiny-gap: calc(var(--half-gap) / 2);
--big-gap: calc(var(--grid-gap) * 2);
--spanSectionColumn:1/-1;//How a section should span when it is meant to span large numbers of columns (default span all)
--fillLeftRadioSize: 1rem;
--fillLeftRadioWidth:var(--fillLeftRadioSize);
--fillLeftRadioHeight:var(--fillLeftRadioSize);
// Animation variables
--revealTime: 500ms;//Our basic reveal time for transitions
--delayTime: 200ms;//Our basic delay time before a transition occurs
--inputSwap: opacity var(--revealTime) ease var(--delayTime);//Transition properties for swapping the visibility of two elements
--focusTiming: 500ms ease;//our basic timing for the transition used when an element is focused or hovered on
--focusTrans: all var(--focusTiming);//The full transition properties for focusing/hovering on an element
// color variables
--borderColor: black;//Our basic border color
--fontColor: black;//Our basic font color
--backColor: #ffffff;//Our basic background color
--subHeadBackColor:grey;//Our sub header background color
--unselectedColor1:lightgrey;//Our default font color for items that are currently inactive
--unselectedColor2:transparent;
--selectedColor:black;
--checkColor:black;
--darkCheck:white;
// Border sizing variables
--displayBorderWidth: 2px;//Our default border width
@extend %font-vars;
}
@@ -0,0 +1,74 @@
@use 'button';
@mixin repButton{
opacity:0;
transition: {
property:opacity,background-color;
duration: var(--revealTime);
};
@extend %text-button;
font-family:pictos;
}
%fieldsetStyling{
.repitem{
> input:not([type='checkbox']){
width:100%;
}
.headed-textarea,
.description{
grid-column:1/-1;
}
}
.repcontainer{
display:grid;
gap:var(--grid-gap);
}
.repeating-container{
display:grid;
grid-template-areas:'header';
align-self:start;
> .header{
grid-area:header;
}
&:is(:hover,:focus-within,:focus){
.repcontrol_edit:after,
.repcontrol-button{
opacity:1;
}
}
}
.repcontrol_edit{
visibility:hidden;
text-transform:none;
&:after{
@include repButton;
visibility:visible;
content:'p';
}
}
.repcontrol-button{
grid-area:header;
align-self:start;
~ .repcontrol{
display:contents;
.repcontrol_edit{
grid-area:header;
align-self:start;
justify-self:end;
display:flex;
float:none;
}
.repcontrol_add{
display:none !important;
}
}
}
.repcontrol-button--add{
justify-self:start;
@include repButton;
&:before{
font-family:pictos;
content:'&';
}
}
}

Some files were not shown because too many files have changed in this diff Show More