Compare commits

..

52 commits
v0.0.7 ... main

Author SHA1 Message Date
Oliver-Akins
cf13b986d4 Change how embedded ActiveEffects are created 2024-04-27 00:37:49 -06:00
Oliver-Akins
f8364888f2 Fix issues with the localizer's replacement to be more reliable 2024-04-27 00:37:30 -06:00
Oliver-Akins
e2579e12f8 Ignore all ref files in the root rather than just the foundry.js file 2024-04-23 23:19:59 -06:00
Oliver-Akins
2c2c4cc83f Make the AE deletion context menu option actually work 2024-04-23 23:19:23 -06:00
Oliver-Akins
dbeb511bdc Implement the ability to create AE's (closes #177) 2024-04-23 23:18:33 -06:00
Oliver-Akins
ec6378092f Snapshot pre-AE data on actors (closes #178) 2024-04-23 19:47:14 -06:00
Oliver-Akins
d479ef7559 Add basic displaying for ActiveEffects and dropdown support 2024-04-20 23:14:16 -06:00
Oliver-Akins
c466e0e539 Some ActiveEffect shenanigans with training levels 2024-04-20 23:12:38 -06:00
Oliver-Akins
cfaed0d230 Add a generic ActiveEffect class + proxy 2024-04-20 22:08:23 -06:00
Oliver-Akins
8aff8b0fda Remove icon preloading from the systems in favour of the async web component 2024-04-20 21:38:42 -06:00
Oliver-Akins
6b80f3530d Localize the photo dropdown options 2024-04-20 21:29:27 -06:00
Oliver-Akins
002438398b Implement the image context menu functionality (closes #148) 2024-04-20 16:52:37 -06:00
Oliver-Akins
af4f0f60a4 Add layout to the effects tab (closes #145) 2024-04-20 15:40:40 -06:00
Oliver-Akins
6198146c6c Make it so that Materials can only be in unknown location or your inventory 2024-04-19 19:06:15 -06:00
Oliver-Akins
484c7a375c Fix deprecation warnings for v12 2024-04-18 17:37:18 -06:00
Oliver-Akins
2df7d2243f Get the combat relevance toggle working (closes #155) 2024-04-17 22:41:04 -06:00
Oliver-Akins
10449acf37 Makes the calculated capacity viewable on the sheet (closes #158) 2024-04-17 22:36:04 -06:00
Oliver-Akins
c6a7f86926 Implement the Quantity affecting Capacity toggle (closes #157) 2024-04-17 22:34:08 -06:00
Oliver-Akins
48ceade1d1 Implement the toggle for capacity usage. (closes #156) 2024-04-17 22:31:45 -06:00
Oliver-Akins
6d41a33b0c Remove DialogManager from the globalThis 2024-04-15 23:56:50 -06:00
Oliver-Akins
c3bb67ad7c Get the calculated capacity "tooltip" implemented (closes #147 and closes #125) 2024-04-15 23:51:24 -06:00
Oliver-Akins
2737c46ffe Optimization & reorganization of icon files 2024-04-13 17:39:20 -06:00
Oliver-Akins
7e5fc036aa Remove duplicate event listener that's causing an error when editing an item (closes #164) 2024-04-13 17:24:08 -06:00
Oliver-Akins
aa41635f88 Update the inventory icons to be using the dd-icon component 2024-04-13 17:17:15 -06:00
Oliver-Akins
050fecd4f6 Update the material item to use the incrementer component 2024-04-13 17:10:42 -06:00
Oliver-Akins
44eaec2d38 Only listen to custom components that have the name attribute for form submission 2024-04-13 17:09:57 -06:00
Oliver-Akins
8c83d304b7 Remove the really annoying blur on the incrementer component 2024-04-13 17:08:52 -06:00
118dcfb71c
Merge pull request #175 from Oliver-Akins/feature/incrementer-component
Custom Web Components
2024-04-13 14:45:43 -04:00
Oliver-Akins
1598081e3b Add the icon element to the html-data spec 2024-04-13 12:40:09 -06:00
Oliver-Akins
a8c94ee16f Add common SCSS for all custom components 2024-04-13 12:36:32 -06:00
Oliver-Akins
ca0d3eb970 Add a couple incrementer elements as an example for using them 2024-04-13 12:19:32 -06:00
Oliver-Akins
f2c169c077 Make a mixin for loading a stylesheet for components, including HMR auto-update support (only in devMode) 2024-04-13 12:18:36 -06:00
Oliver-Akins
fde3881653 Add Hot Module Replacement for SVG icons using the custom component 2024-04-12 23:23:42 -06:00
Oliver-Akins
f15f3a4456 Get the icon component coded and being used in the incrementer component 2024-04-11 22:32:04 -06:00
Oliver-Akins
3ace1df5a2 Begin work on an icon component 2024-04-10 21:38:44 -06:00
Oliver-Akins
92652262f3 A spot of cleanup 2024-04-10 21:38:30 -06:00
Oliver-Akins
c5c5a71587 Finish the custom incrementer component 2024-04-10 21:27:10 -06:00
Oliver-Akins
878d278303 Remove debug log 2024-04-10 20:52:02 -06:00
Oliver-Akins
1d148d39db Add missing newline 2024-04-07 23:54:44 -06:00
Oliver-Akins
4efa89915a Make progress on the input being focusable from an external label 2024-04-07 23:53:34 -06:00
Oliver-Akins
1c372415f4 Move the CSS into a path-versioned location 2024-04-07 23:08:41 -06:00
Oliver-Akins
1558468526 Add HTML data for the custom incrementer element 2024-04-07 23:07:52 -06:00
Oliver-Akins
e0e4a7b68a Version bump 2024-04-06 15:56:41 -06:00
Oliver-Akins
a0f17fc4f5 Fix item list gaps (closes #163) 2024-04-06 12:03:47 -06:00
Oliver-Akins
14827195fe Version bump 2024-04-06 12:00:51 -06:00
Oliver-Akins
f4d7ea59f3 For now, register all of the devMode stuff in the release 2024-04-06 12:00:36 -06:00
Oliver-Akins
0ac7f07081 Fix a bug with the Sync actor 2024-04-06 12:00:06 -06:00
Oliver-Akins
a1e9c565af Add datasheet for sync sheets 2024-04-06 11:59:27 -06:00
Oliver-Akins
e0a3b4985b Begin making the proper CSS for the component 2024-04-04 22:48:19 -06:00
Oliver-Akins
566faf61d2 Remove stray console logs 2024-04-04 20:02:19 -06:00
Oliver-Akins
9f6a8e5e73 Get the incrementer being able to be submitted, causing submits, and styling without flickering 2024-04-04 19:59:42 -06:00
Oliver-Akins
d5429b7b34 Begin work on a custom element for incrementer 2024-04-03 23:00:57 -06:00
85 changed files with 1101 additions and 306 deletions

2
.gitignore vendored
View file

@ -6,7 +6,7 @@ references/
/.*/
!/.vscode/
!/.github/
/foundry.js
/*.ref.*
*.lock
*.zip

27
.vscode/components.html-data.json vendored Normal file
View file

@ -0,0 +1,27 @@
{
"version": 1.1,
"tags": [
{
"name": "dd-incrementer",
"description": "A number input that allows more flexible increase/decrease buttons",
"attributes": [
{ "name": "value", "description": "The initial value to put in the input" },
{ "name": "name", "description": "The form name to use when this input is used to submit data" },
{ "name": "min", "description": "The minimum value that this input can contain" },
{ "name": "max", "description": "The maximum value that this input can contain" },
{ "name": "smallStep", "description": "The value that the input is changed by when clicking a delta button or using the up/down arrow key" },
{ "name": "largeStep", "description": "The value that the input is changed by when clicking a delta button with control held or using the page up/ page down arrow key" }
]
},
{
"name": "dd-icon",
"description": "Loads an icon asynchronously, caching the result for future uses",
"attributes": [
{ "name": "name", "description": "The name of the icon, this is relative to the assets folder of the dotdungeon system" },
{ "name": "path", "description": "The full path of the icon, this will only be used if `name` isn't provided or fails to fetch." }
]
}
],
"globalAttributes": [],
"valueSets": []
}

View file

@ -12,5 +12,8 @@
"node_modules": true,
"packs": true,
".gitattributes": true,
}
}
},
"html.customData": [
"./.vscode/components.html-data.json"
]
}

View file

@ -1,3 +0,0 @@
<svg width="100%" height="100%" version="1.1" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" fill="currentColor">
<path d="m50.016 82.137c-2.6133-0.003907-5.1016-1.1172-6.8438-3.0664l-40.48-44.16c-1.7383-1.9023-2.6992-4.3906-2.6914-6.9688 0-1.4727 0.30469-2.9297 0.89844-4.2773 1.4492-3.4961 4.8555-5.7812 8.6367-5.8008h80.93c3.7812 0.019531 7.1875 2.3047 8.6367 5.8008 1.6836 3.7734 0.98047 8.1836-1.793 11.246l-40.457 44.172c-1.7422 1.9414-4.2266 3.0508-6.8359 3.0547z"/>
</svg>

Before

Width:  |  Height:  |  Size: 492 B

View file

@ -1,3 +0,0 @@
<svg width="100%" height="100%" version="1.1" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" fill="currentColor">
<path d="m82.137 50.016c-0.003907 2.6133-1.1172 5.1055-3.0664 6.8477l-44.16 40.445c-1.8984 1.75-4.3867 2.7227-6.9688 2.7266-1.4727 0-2.9297-0.30859-4.2773-0.90234-3.5078-1.4531-5.7969-4.875-5.8008-8.668v-80.93c0.019531-3.7812 2.3047-7.1875 5.8008-8.6367 3.7734-1.6836 8.1836-0.98047 11.246 1.793l44.172 40.457c1.9492 1.75 3.0625 4.25 3.0547 6.8672z"/>
</svg>

Before

Width:  |  Height:  |  Size: 484 B

View file

@ -1,3 +0,0 @@
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" fill="currentColor">
<path d="M 61.24 9 L 42.776 9 C 21.393 9 4.095 26.336 4.095 47.679 C 2.013 74.103 34.856 91.236 48.486 97.153 C 51.236 98.362 54.278 96.319 54.278 93.319 L 54.278 84.775 C 54.278 82.482 56.154 80.606 58.447 80.606 L 61.197 80.606 C 80.995 80.606 97 64.561 97 44.804 C 97 25.046 80.954 9 61.197 9 L 61.24 9 Z M 32.854 54.389 C 29.813 54.389 27.354 51.93 27.354 48.888 C 27.354 45.844 29.813 43.388 32.854 43.388 C 35.899 43.388 38.358 45.844 38.358 48.888 C 38.358 51.93 35.899 54.389 32.854 54.389 Z M 50.527 54.389 C 47.486 54.389 45.025 51.93 45.025 48.888 C 45.025 45.844 47.486 43.388 50.527 43.388 C 53.571 43.388 56.03 45.844 56.03 48.888 C 56.03 51.93 53.571 54.389 50.527 54.389 Z M 68.202 54.389 C 65.158 54.389 62.697 51.93 62.697 48.888 C 62.697 45.844 65.158 43.388 68.202 43.388 C 71.242 43.388 73.703 45.844 73.703 48.888 C 73.703 51.93 71.242 54.389 68.202 54.389 Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 975 B

View file

@ -1,3 +0,0 @@
<svg width="100%" height="100%" version="1.1" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<path d="m96.293 83.457c3.543 3.5469 3.543 9.2891 0 12.836-3.5469 3.543-9.2891 3.543-12.836 0l-31.992-31.992c-0.80859-0.8125-2.1211-0.8125-2.9297 0l-31.992 31.992c-3.5469 3.543-9.2891 3.543-12.836 0-3.543-3.5469-3.543-9.2891 0-12.836l31.992-31.988c0.8125-0.8125 0.8125-2.125 0-2.9336l-31.992-31.992c-3.543-3.5469-3.543-9.2891 0-12.836 3.5469-3.543 9.2891-3.543 12.836 0l31.992 31.996c0.80859 0.80859 2.1211 0.80859 2.9297 0l31.992-31.996c3.5469-3.543 9.2891-3.543 12.836 0 3.543 3.5469 3.543 9.2891 0 12.836l-31.992 31.992c-0.8125 0.80859-0.8125 2.1211 0 2.9336z"/>
</svg>

Before

Width:  |  Height:  |  Size: 678 B

View file

@ -1,3 +1 @@
<svg width="100%" height="100%" version="1.1" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<path d="m52.348 11.457c-1.1094-0.91797-2.7305-0.91797-3.8398 0l-36.531 30.484c-0.67969 0.57031-1.0781 1.4102-1.0781 2.3008v10.949c0 0.87891 0.39062 1.7188 1.0586 2.2891l36.535 31.043c0.55859 0.48047 1.25 0.71094 1.9414 0.71094s1.3789-0.23828 1.9414-0.71094l36.742-31.043c0.66797-0.57031 1.0586-1.4102 1.0586-2.2891l-0.003906-10.941c0-0.89062-0.39844-1.7383-1.0781-2.3086zm31.824 39.934-15.445-3.9297-10.316-23.188 25.773 21.387zm-33.73 3.5195-12.258-6.2891 12.258-27.496 12.258 27.496zm-16.508-1.7227 13.508 6.9297v19.637l-27.176-23.086zm19.504 6.9297 13.508-6.9297 13.797 3.5195-27.305 23.066zm-10.996-35.773-10.297 23.105-15.246 3.8906v-5.6797z"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path d="M52.348 11.457a3.021 3.021 0 0 0-3.84 0l-36.53 30.484a3.005 3.005 0 0 0-1.079 2.3v10.95c0 .879.39 1.719 1.059 2.289l36.535 31.043a3.01 3.01 0 0 0 3.883 0L89.118 57.48a3.02 3.02 0 0 0 1.058-2.29l-.004-10.94c0-.89-.398-1.739-1.078-2.309zm31.824 39.934-15.445-3.93-10.316-23.188L84.184 45.66zm-33.73 3.52-12.258-6.29 12.258-27.496L62.7 48.621zm-16.508-1.723 13.508 6.93v19.636L20.266 56.668zm19.504 6.93 13.508-6.93 13.797 3.52-27.305 23.065zM42.442 24.343 32.145 47.45 16.899 51.34v-5.68z"/></svg>

Before

Width:  |  Height:  |  Size: 763 B

After

Width:  |  Height:  |  Size: 566 B

Before After
Before After

View file

@ -1,3 +1 @@
<svg width="100%" height="100%" version="1.1" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<path d="m85.484 37.672-12.418-17.098c-0.37109-0.51172-0.89844-0.89062-1.5-1.0898l-20.098-6.5273c-0.60156-0.19922-1.25-0.19922-1.8516 0l-20.098 6.5273c-0.60156 0.19922-1.1289 0.57812-1.5 1.0898l-12.422 17.098c-0.37109 0.51172-0.57031 1.1289-0.57031 1.7578v21.125c0 0.62891 0.19922 1.25 0.57031 1.7578l12.418 17.098c0.37109 0.51172 0.89844 0.89062 1.5 1.0898l20.098 6.5273c0.30078 0.10156 0.60938 0.14844 0.92969 0.14844 0.32031 0 0.62891-0.050781 0.92969-0.14844l20.098-6.5273c0.60156-0.19922 1.1289-0.57812 1.5-1.0898l12.414-17.094c0.37109-0.51172 0.57031-1.1289 0.57031-1.7578v-21.125c0-0.63281-0.20313-1.25-0.57031-1.7617zm-7.0586 0.49219-9.3398 4.0078-15.547-11.297v-10.93l15.238 4.9492zm-18.836 25.793h-18.098l-5.5898-17.207 14.637-10.637 14.637 10.637zm-27.297-39.062 15.238-4.9492v10.938l-15.539 11.289-9.3398-4.0078zm-11.266 34.695v-15.598l8.918 3.8281 6.0078 18.484-5.3477 6.457zm29.512 21.445-14.969-4.8594 5.1484-6.2188h19.625l5.1484 6.2188zm19.938-8.2695-5.3477-6.457 6.0078-18.484 8.918-3.8281v15.598z"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path d="M85.484 37.672 73.066 20.574a3.024 3.024 0 0 0-1.5-1.09l-20.098-6.527c-.602-.2-1.25-.2-1.852 0l-20.098 6.527c-.601.2-1.128.578-1.5 1.09L15.596 37.672a2.998 2.998 0 0 0-.57 1.758v21.125c0 .629.2 1.25.57 1.758L28.014 79.41c.371.511.899.89 1.5 1.09l20.098 6.527a2.988 2.988 0 0 0 1.86 0L71.57 80.5a3.024 3.024 0 0 0 1.5-1.09l12.414-17.093c.37-.512.57-1.13.57-1.758V39.434c0-.633-.203-1.25-.57-1.762zm-7.059.492-9.34 4.008L53.54 30.875v-10.93l15.238 4.95zM59.59 63.957H41.491l-5.59-17.207L50.54 36.113 65.176 46.75zM32.292 24.895l15.238-4.949v10.938L31.991 42.173l-9.34-4.008zM21.026 59.59V43.992l8.918 3.828 6.008 18.484-5.347 6.457zm29.512 21.445-14.969-4.86 5.149-6.218h19.625l5.148 6.219zm19.938-8.27L65.13 66.31l6.007-18.484 8.919-3.828v15.598z"/></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 825 B

Before After
Before After

View file

@ -1,3 +1 @@
<svg width="100%" height="100%" version="1.1" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<path d="m82.172 32.355c-0.019531-0.14844-0.03125-0.30078-0.070313-0.44141-0.039062-0.12891-0.10156-0.23828-0.14844-0.37109-0.039063-0.10938-0.070313-0.21875-0.12891-0.32031-0.011719-0.011718-0.019531-0.019531-0.019531-0.03125-0.070313-0.10938-0.16016-0.21094-0.23828-0.32031-0.078125-0.10156-0.14844-0.21094-0.23828-0.30078-0.078125-0.078124-0.17969-0.14062-0.26953-0.21094-0.10938-0.089844-0.21875-0.19141-0.35156-0.26172-0.019531-0.011718-0.03125-0.019531-0.039062-0.03125l-29.312-16.195c-0.94141-0.51953-2.0781-0.5-3 0.058594l-28.676 17.297c-0.019532 0.011719-0.03125 0.03125-0.050782 0.039063-0.12109 0.070313-0.21875 0.17188-0.32812 0.26172-0.089843 0.078125-0.19141 0.14844-0.28125 0.23828-0.078125 0.089844-0.14844 0.19922-0.21875 0.28906-0.078125 0.10937-0.17188 0.21875-0.23047 0.33984-0.011718 0.019531-0.019531 0.03125-0.03125 0.039063-0.050781 0.10156-0.070312 0.19922-0.10156 0.30078-0.050781 0.12891-0.10938 0.25-0.14062 0.39062s-0.039063 0.28125-0.050781 0.41797c-0.011719 0.10156-0.039063 0.19922-0.039063 0.30859l0.62891 33.484c0.019531 1.0703 0.60937 2.0508 1.5508 2.5703l29.332 16.207c0.44922 0.25 0.94922 0.37109 1.4492 0.37109 0.53906 0 1.0703-0.14062 1.5508-0.42969l28.684-17.285c0.91797-0.55078 1.4688-1.5508 1.4492-2.6289l-0.62891-33.484c0-0.10156-0.039062-0.20312-0.050781-0.30078zm-21.926 27.652-8.8789 15.816-9.4688-15.477zm-18.926-6.1992 8.8789-15.816 9.4688 15.477zm-5.3594-2.707-9.4375-14.605 18.258-1.1094zm29.305 0.027344-9.7578-15.945 18.617 0.41797zm-12.215-22.004-0.089843-7.4883 14.129 7.8086zm-6 0.10938-13.828 0.83984 13.746-8.2891zm-14.969 26.914-7.3398 5.3398-0.32813-17.195zm3.2891 5.0195 9.3867 15.348-17.336-9.5781zm31.105-0.011719 7.707 4.9609-15.848 9.5469zm2.9609-5.2383 6.9883-12.258 0.32031 16.965z"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path d="M82.172 32.355c-.02-.148-.031-.3-.07-.441-.04-.13-.102-.239-.149-.372-.039-.109-.07-.218-.129-.32-.011-.012-.02-.02-.02-.031-.07-.11-.16-.211-.237-.32-.079-.102-.149-.211-.239-.301-.078-.078-.18-.14-.27-.211-.109-.09-.218-.192-.35-.262a.113.113 0 0 1-.04-.031L51.356 13.87a2.985 2.985 0 0 0-3 .059L19.68 31.227c-.02.011-.031.03-.05.039-.122.07-.22.171-.329.261-.09.078-.191.149-.281.239-.078.09-.148.199-.219.289-.078.109-.172.218-.23.34a.113.113 0 0 1-.032.039c-.05.101-.07.199-.101.3-.05.13-.11.25-.14.391s-.04.281-.051.418c-.012.101-.04.2-.04.309l.63 33.484c.019 1.07.609 2.05 1.55 2.57L49.72 86.113c.45.25.95.37 1.45.37.538 0 1.07-.14 1.55-.429L81.403 68.77a2.994 2.994 0 0 0 1.45-2.629l-.63-33.484c0-.101-.039-.203-.05-.3zM60.246 60.007l-8.879 15.816-9.469-15.477zm-18.926-6.2 8.879-15.815 9.469 15.477zm-5.36-2.706-9.437-14.605 18.258-1.11zm29.306.027-9.758-15.945 18.617.418zM53.05 29.124l-.09-7.488 14.129 7.808zm-6 .11-13.828.84 13.746-8.29zM32.08 56.148l-7.34 5.34-.327-17.196zm3.29 5.019 9.386 15.348-17.336-9.578zm31.105-.012 7.707 4.961-15.848 9.547zm2.96-5.238 6.989-12.258.32 16.965z"/></svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Before After
Before After

View file

@ -1,3 +1 @@
<svg width="100%" height="100%" version="1.1" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<path d="m52.91 11.938c-0.57031-0.73828-1.4492-1.168-2.3789-1.168s-1.8086 0.42969-2.3789 1.168l-37.773 48.949c-0.51953 0.66797-0.73047 1.5312-0.57812 2.3711 0.14844 0.82813 0.64844 1.5703 1.3711 2.0078l37.781 23.516c0.48828 0.30078 1.0391 0.44922 1.5898 0.44922s1.1016-0.14844 1.5898-0.44922l37.781-23.516c0.71875-0.44922 1.2188-1.1797 1.3711-2.0078 0.14844-0.82812-0.058594-1.6914-0.57812-2.3711zm-5.3711 10.629v58.277l-30.383-18.918zm6 58.266v-58.266l30.383 39.363z"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path d="M52.91 11.938a3.005 3.005 0 0 0-4.758 0L10.38 60.887a2.993 2.993 0 0 0-.578 2.371c.149.828.649 1.57 1.371 2.008l37.781 23.516a3.028 3.028 0 0 0 3.18 0l37.78-23.516a3.02 3.02 0 0 0 1.372-2.008 3.03 3.03 0 0 0-.578-2.371zm-5.371 10.629v58.277L17.156 61.926zm6 58.266V22.567L83.922 61.93z"/></svg>

Before

Width:  |  Height:  |  Size: 583 B

After

Width:  |  Height:  |  Size: 365 B

Before After
Before After

View file

@ -1,3 +1 @@
<svg width="100%" height="100%" version="1.1" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<path d="m83.664 28.203-31.953-13.527c-0.75-0.32031-1.5898-0.32031-2.3398 0l-31.953 13.527c-1.1016 0.46875-1.8203 1.5508-1.8281 2.7383v0.019532 37.602c0 1.1914 0.71094 2.2695 1.8008 2.75l31.953 13.996c0.37891 0.17188 0.78906 0.25 1.1992 0.25 0.41016 0 0.82031-0.078125 1.1992-0.25l31.953-13.996c1.0898-0.48047 1.8008-1.5586 1.8008-2.75l-0.003906-37.598v-0.019532c-0.007813-1.1914-0.71875-2.2695-1.8281-2.7422zm-33.125-7.5078 24.375 10.316-24.375 10.68-24.375-10.676zm-28.965 14.859 25.965 11.367v31.055l-25.965-11.371zm31.965 42.418v-31.051l25.953-11.367v31.055z"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path d="M83.664 28.203 51.711 14.676c-.75-.32-1.59-.32-2.34 0L17.418 28.203a3.006 3.006 0 0 0-1.828 2.738v37.622c0 1.191.711 2.27 1.8 2.75l31.954 13.996c.379.172.789.25 1.2.25.41 0 .82-.078 1.198-.25l31.953-13.996a3.012 3.012 0 0 0 1.801-2.75l-.004-37.598v-.02a3 3 0 0 0-1.828-2.742zm-33.125-7.508 24.375 10.316-24.375 10.68-24.375-10.676zm-28.965 14.86L47.539 46.92v31.055l-25.965-11.37zm31.965 42.417v-31.05l25.953-11.368V66.61z"/></svg>

Before

Width:  |  Height:  |  Size: 678 B

After

Width:  |  Height:  |  Size: 502 B

Before After
Before After

View file

@ -1,3 +1 @@
<svg width="100%" height="100%" version="1.1" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<path d="m80.785 31.625-28.047-16.949c-0.91797-0.55078-2.0586-0.57812-3-0.058593l-28.691 15.809c-0.94141 0.51953-1.5312 1.5-1.5508 2.5703l-0.64844 32.762c-0.019531 1.0703 0.53125 2.0703 1.4492 2.6289l28.043 16.945c0.48047 0.28906 1.0117 0.42969 1.5508 0.42969 0.5 0 1-0.12109 1.4492-0.37109l28.695-15.816c0.94141-0.51953 1.5312-1.5 1.5508-2.5703l0.64844-32.762c0.019531-1.0703-0.53125-2.0703-1.4492-2.6172zm-4.9688 23.793-17.156-30.164 17.535 10.598zm-2.4102 7.9102-45.199-0.44922 22.566-39.363zm-30.543-38.074-17.828 31.094 0.42969-21.504zm7.0859 54.039-17.164-10.367 35.352 0.35156z"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path d="M80.785 31.625 52.738 14.676a3.004 3.004 0 0 0-3-.059l-28.691 15.81a2.999 2.999 0 0 0-1.55 2.57l-.65 32.762a3.013 3.013 0 0 0 1.45 2.629L48.34 85.333c.48.289 1.012.43 1.55.43.5 0 1-.122 1.45-.372l28.695-15.816a2.999 2.999 0 0 0 1.55-2.57l.65-32.762a2.98 2.98 0 0 0-1.45-2.617zm-4.969 23.793L58.66 25.254l17.535 10.598zm-2.41 7.91-45.199-.449 22.566-39.363zM42.863 25.254 25.035 56.348l.43-21.504zm7.086 54.04L32.785 68.925l35.352.352z"/></svg>

Before

Width:  |  Height:  |  Size: 700 B

After

Width:  |  Height:  |  Size: 514 B

Before After
Before After

View file

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg fill="currentColor" width="100%" height="100%" version="1.1" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<g>
<path d="m67.5 12.801c-3.1992-3.1992-8.3984-3.1992-11.602 0l-38.797 38.801c-2.3008 2.3008-2.3008 6.1016 0 8.3984l21.5 21.5c2.3008 2.3008 6.1016 2.3008 8.3984 0l38.801-38.801c3.1992-3.1992 3.1992-8.3984 0-11.602z"/>
<path d="m18.602 88.102h0.19922l10.301-0.30078c3.1016-0.10156 4.6016-3.8984 2.3984-6.1016l-14.699-14.699c-2.1992-2.1992-6-0.69922-6.1016 2.3984l-0.30078 10.301c-0.10156 2.3008 0.80078 4.5 2.3984 6.1016 1.5039 1.5 3.6016 2.3008 5.8047 2.3008z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 645 B

View file

@ -1,6 +0,0 @@
<svg width="100%" height="100%" version="1.1" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" fill="currentColor">
<g>
<path d="m82.199 25.301h-64.398c-1.3008 0-2.3008 1.1016-2.1992 2.3984l7.5 62.398c0.5 4.1992 4.1016 7.3984 8.3984 7.3984h37c4.3008 0 7.8984-3.1992 8.3984-7.3984l7.5-62.398c0.10156-1.3008-0.89844-2.3984-2.1992-2.3984zm-45.301 57.699h-0.19922c-1.1992 0-2.1992-0.89844-2.3008-2.1016l-4.1016-38.699c-0.10156-1.3008 0.80078-2.3984 2.1016-2.5 1.3008-0.10156 2.3984 0.80078 2.5 2.1016l4.1016 38.699c0.10156 1.3008-0.80078 2.3984-2.1016 2.5zm15.402-2.3008c0 1.3008-1 2.3008-2.3008 2.3008s-2.3008-1-2.3008-2.3008v-38.699c0-1.3008 1-2.3008 2.3008-2.3008s2.3008 1 2.3008 2.3008zm13.301 0.30078c-0.10156 1.1992-1.1016 2.1016-2.3008 2.1016h-0.19922c-1.3008-0.10156-2.1992-1.3008-2.1016-2.5l4.1016-38.699c0.10156-1.3008 1.3008-2.1992 2.5-2.1016 1.3008 0.10156 2.1992 1.3008 2.1016 2.5z"/>
<path d="m86.602 10.801h-19.301l-4.6016-6.3984c-0.80078-1.1992-2.1992-1.8984-3.6992-1.8984l-18-0.003906c-1.5 0-2.8008 0.69922-3.6992 1.8984l-4.6016 6.3984-19.301 0.003906c-2.3984 0-4.3008 1.8984-4.3008 4.3008 0 2.3984 1.8984 4.3008 4.3008 4.3008h73.199c2.3984 0 4.3008-1.8984 4.3008-4.3008 0-2.4023-1.8984-4.3008-4.2969-4.3008z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -1,3 +0,0 @@
<svg width="100%" height="100%" version="1.1" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" fill="currentColor">
<path d="m12.633 38.727h74.734c6.2578 0 11.336 6.2266 11.336 11.273 0 6.2266-5.0742 11.273-11.336 11.273h-74.734c-6.2578 0-11.336-6.2266-11.336-11.273 0-6.2266 5.0742-11.273 11.336-11.273z" fill-rule="evenodd"/>
</svg>

Before

Width:  |  Height:  |  Size: 343 B

View file

@ -1,8 +0,0 @@
<svg height="100%" width="100%" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(1.0666639804840088, 0, 0, 1.0666639804840088, -4.5322370529174805, -4.2468461990356445)">
<path d="m16.086 76.617c0 1.3672 1.1133 2.4805 2.4805 2.4805h49.793c1.3672 0 2.4805-1.1133 2.4805-2.4805v-66.324c0-1.3672-1.1133-2.4805-2.4805-2.4805h-35.352v12.695c0 2.2812-1.8555 4.1328-4.1367 4.1328l-12.785 0.003906zm7.6328-48.016h39.492c0.45703 0 0.82812 0.36719 0.82812 0.82813 0 0.46094-0.36719 0.82812-0.82812 0.82812h-39.492c-0.45703 0-0.82812-0.36719-0.82812-0.82812 0-0.46094 0.37109-0.82813 0.82812-0.82813zm0 10.609h39.492c0.45703 0 0.82812 0.36719 0.82812 0.82812 0 0.46094-0.36719 0.82813-0.82812 0.82813h-39.492c-0.45703 0-0.82812-0.36719-0.82812-0.82813 0-0.45703 0.37109-0.82812 0.82812-0.82812zm0 10.617h39.492c0.45703 0 0.82812 0.36719 0.82812 0.82812s-0.36719 0.82812-0.82812 0.82812h-39.492c-0.45703 0-0.82812-0.36719-0.82812-0.82812s0.37109-0.82812 0.82812-0.82812zm0 10.613h39.492c0.45703 0 0.82812 0.36719 0.82812 0.82812 0 0.46094-0.36719 0.82812-0.82812 0.82812h-39.492c-0.45703 0-0.82812-0.36719-0.82812-0.82812 0-0.46094 0.37109-0.82812 0.82812-0.82812z"/>
<path d="m74.898 14.355h-2.3984v62.258c0 2.2812-1.8555 4.1328-4.1328 4.1328h-45.746v2.4102c0 1.3672 1.1133 2.4805 2.4805 2.4805h49.793c1.3672 0 2.4805-1.1133 2.4805-2.4805l0.003906-66.32c0-1.3633-1.1133-2.4805-2.4805-2.4805z"/>
<path d="m31.352 20.508v-11.531l-14.09 14.016h11.609c1.3711 0 2.4805-1.1172 2.4805-2.4844z"/>
<path d="m29.16 87.297v2.4102c0 1.3672 1.1133 2.4805 2.4805 2.4805h49.793c1.3672 0 2.4805-1.1133 2.4805-2.4805v-66.324c0-1.3672-1.1133-2.4805-2.4805-2.4805h-2.3984v62.258c0 2.2812-1.8555 4.1328-4.1328 4.1328h-45.742z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -1,12 +1,15 @@
Disclaimer:
All icons included in this repo have been scaled and optimized as needed.
Amer Alamer
caret-right.svg (https://thenounproject.com/icon/arrow-caret-right-1143917/)
caret-down.svg (https://thenounproject.com/icon/arrow-caret-down-1143911/)
ui/caret/right.svg (https://thenounproject.com/icon/arrow-caret-right-1143917/)
ui/caret/down.svg (https://thenounproject.com/icon/arrow-caret-down-1143911/)
Alice Design:
garbage-bin.svg (https://thenounproject.com/icon/garbage-2025492/)
ui/garbage-bin.svg (https://thenounproject.com/icon/garbage-2025492/)
zapesicon:
chat-bubble.svg (https://thenounproject.com/icon/chat-6423186/)
ui/chat-bubble.svg (https://thenounproject.com/icon/chat-6423186/)
Fritz Duggan:
dice/d4.svg (https://thenounproject.com/icon/d4-4570604/)
@ -17,21 +20,19 @@ Fritz Duggan:
dice/d20.svg (https://thenounproject.com/icon/d20-4570607/)
Landan Lloyd:
create.svg (https://thenounproject.com/icon/create-1447560/)
ui/plus.svg (https://thenounproject.com/icon/create-1447560/)
Bismillah
minus.svg (https://thenounproject.com/icon/minus-1727966/)
ui/minus.svg (https://thenounproject.com/icon/minus-1727966/)
Rokhman Kharis:
close.svg (https://thenounproject.com/icon/close-4996834/)
ui/close.svg (https://thenounproject.com/icon/close-4996834/)
Athok:
sheet.svg (https://thenounproject.com/icon/sheet-5939348/)
ui/sheet.svg (https://thenounproject.com/icon/sheet-5939348/)
Icon Depot:
edit.svg (https://thenounproject.com/icon/edit-1489252/)
ui/pencil.svg (https://thenounproject.com/icon/edit-1489252/)
Oliver Akins:
chat-bubble.svg : Scaling
create.svg : Scaling, Optimization
sheet.svg : Scaling
Muhammad Ahsanu Nadia:
ui/help.svg (https://thenounproject.com/icon/help-6778522/)

1
assets/ui/caret/down.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 100 100"><path d="M50.016 82.137a9.195 9.195 0 0 1-6.844-3.066L2.692 34.91a10.286 10.286 0 0 1-2.691-6.97c0-1.472.304-2.929.898-4.276a9.404 9.404 0 0 1 8.637-5.801h80.93a9.404 9.404 0 0 1 8.637 5.8A10.424 10.424 0 0 1 97.31 34.91L56.853 79.082a9.201 9.201 0 0 1-6.836 3.055z"/></svg>

After

Width:  |  Height:  |  Size: 356 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 100 100"><path d="M82.137 50.016a9.203 9.203 0 0 1-3.066 6.848L34.91 97.309a10.306 10.306 0 0 1-6.97 2.726c-1.472 0-2.929-.308-4.276-.902a9.396 9.396 0 0 1-5.801-8.668V9.535a9.404 9.404 0 0 1 5.8-8.637A10.424 10.424 0 0 1 34.91 2.691l44.172 40.457a9.198 9.198 0 0 1 3.055 6.867z"/></svg>

After

Width:  |  Height:  |  Size: 360 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 100 100"><path d="M61.24 9H42.776C21.393 9 4.095 26.336 4.095 47.679 2.013 74.103 34.856 91.236 48.486 97.153c2.75 1.209 5.792-.834 5.792-3.834v-8.544a4.181 4.181 0 0 1 4.169-4.169h2.75C80.995 80.606 97 64.561 97 44.804 97 25.046 80.954 9 61.197 9h.043ZM32.854 54.389a5.496 5.496 0 0 1-5.5-5.501c0-3.044 2.459-5.5 5.5-5.5a5.495 5.495 0 0 1 5.504 5.5 5.497 5.497 0 0 1-5.504 5.501Zm17.673 0a5.498 5.498 0 0 1-5.502-5.501c0-3.044 2.461-5.5 5.502-5.5a5.494 5.494 0 0 1 5.503 5.5 5.496 5.496 0 0 1-5.503 5.501Zm17.675 0a5.498 5.498 0 0 1-5.505-5.501c0-3.044 2.461-5.5 5.505-5.5a5.495 5.495 0 0 1 5.501 5.5 5.497 5.497 0 0 1-5.501 5.501Z"/></svg>

After

Width:  |  Height:  |  Size: 714 B

1
assets/ui/close.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path d="M96.293 83.457a9.08 9.08 0 0 1 0 12.836 9.08 9.08 0 0 1-12.836 0L51.465 64.301a2.065 2.065 0 0 0-2.93 0L16.543 96.293a9.08 9.08 0 0 1-12.836 0 9.08 9.08 0 0 1 0-12.836L35.7 51.469a2.07 2.07 0 0 0 0-2.934L3.707 16.543a9.08 9.08 0 0 1 0-12.836 9.08 9.08 0 0 1 12.836 0l31.992 31.996a2.072 2.072 0 0 0 2.93 0L83.457 3.707a9.08 9.08 0 0 1 12.836 0 9.08 9.08 0 0 1 0 12.836L64.301 48.535a2.07 2.07 0 0 0 0 2.934z"/></svg>

After

Width:  |  Height:  |  Size: 487 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 100 100"><path d="M82.199 25.301H17.801c-1.3 0-2.3 1.102-2.2 2.398l7.5 62.398c.5 4.2 4.102 7.399 8.4 7.399h37c4.3 0 7.898-3.2 8.398-7.399l7.5-62.398a2.204 2.204 0 0 0-2.2-2.398zM36.898 83h-.2c-1.198 0-2.198-.898-2.3-2.102L30.296 42.2c-.101-1.3.801-2.398 2.102-2.5 1.3-.101 2.398.801 2.5 2.102L39 80.5c.101 1.3-.801 2.398-2.102 2.5zM52.3 80.7c0 1.3-1 2.3-2.3 2.3s-2.302-1-2.302-2.3V42c0-1.3 1-2.3 2.301-2.3s2.301 1 2.301 2.3zm13.301.3a2.296 2.296 0 0 1-2.3 2.102h-.2c-1.3-.102-2.2-1.301-2.102-2.5l4.102-38.7c.102-1.3 1.3-2.199 2.5-2.101 1.3.102 2.2 1.3 2.102 2.5zM86.602 10.801H67.301l-4.602-6.398C61.9 3.203 60.5 2.504 59 2.504L41 2.5c-1.5 0-2.8.7-3.699 1.899l-4.602 6.398-19.3.004a4.269 4.269 0 0 0-4.301 4.3c0 2.4 1.898 4.302 4.3 4.302h73.2c2.398 0 4.3-1.899 4.3-4.301S89 10.8 86.601 10.8z"/></svg>

After

Width:  |  Height:  |  Size: 873 B

1
assets/ui/help.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path d="M50 9.375a40.635 40.635 0 0 0-28.727 11.898 40.63 40.63 0 0 0 0 57.454 40.63 40.63 0 0 0 57.454 0A40.63 40.63 0 0 0 90.625 50a40.658 40.658 0 0 0-11.914-28.711A40.66 40.66 0 0 0 50 9.375zm0 75a34.39 34.39 0 0 1-24.309-10.066 34.386 34.386 0 0 1 0-48.618 34.386 34.386 0 0 1 48.618 0A34.386 34.386 0 0 1 84.375 50a34.407 34.407 0 0 1-10.082 24.293A34.41 34.41 0 0 1 50 84.375z"/><path d="M50 25a15.641 15.641 0 0 0-15.625 15.625v3.125a3.124 3.124 0 1 0 6.25 0v-3.125c0-5.176 4.2-9.375 9.375-9.375s9.375 4.2 9.375 9.375v.457a6.217 6.217 0 0 1-3.438 5.59l-2.136 1.066a12.432 12.432 0 0 0-6.926 11.18v6.707a3.124 3.124 0 1 0 6.25 0v-6.707a6.223 6.223 0 0 1 3.453-5.59l2.137-1.066a12.434 12.434 0 0 0 6.91-11.18v-.457A15.641 15.641 0 0 0 50 25zM53.125 75c0 4.168-6.25 4.168-6.25 0s6.25-4.168 6.25 0"/></svg>

After

Width:  |  Height:  |  Size: 873 B

1
assets/ui/minus.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 100 100"><path fill-rule="evenodd" d="M12.633 38.727h74.734c6.258 0 11.336 6.227 11.336 11.273 0 6.227-5.074 11.273-11.336 11.273H12.633C6.375 61.273 1.297 55.046 1.297 50c0-6.227 5.074-11.273 11.336-11.273z"/></svg>

After

Width:  |  Height:  |  Size: 289 B

1
assets/ui/pencil.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 100 100"><path d="M67.5 12.801c-3.2-3.2-8.398-3.2-11.602 0L17.101 51.602c-2.3 2.3-2.3 6.102 0 8.398l21.5 21.5c2.3 2.301 6.102 2.301 8.398 0L85.8 42.7c3.2-3.2 3.2-8.399 0-11.603zM18.602 88.102h.2l10.3-.3c3.102-.102 4.602-3.9 2.399-6.102L16.8 67c-2.199-2.199-6-.699-6.101 2.399L10.4 79.7c-.102 2.3.8 4.5 2.398 6.102 1.504 1.5 3.601 2.3 5.804 2.3z"/></svg>

After

Width:  |  Height:  |  Size: 426 B

View file

Before

Width:  |  Height:  |  Size: 536 B

After

Width:  |  Height:  |  Size: 536 B

Before After
Before After

1
assets/ui/sheet.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path d="M12.626 77.478a2.65 2.65 0 0 0 2.646 2.646h53.112a2.65 2.65 0 0 0 2.646-2.646V6.732a2.65 2.65 0 0 0-2.646-2.646H30.676v13.542a4.414 4.414 0 0 1-4.413 4.408l-13.637.004zm8.142-51.217h42.124c.488 0 .884.391.884.883a.878.878 0 0 1-.884.883H20.768a.881.881 0 0 1-.884-.883c0-.492.396-.883.884-.883zm0 11.316h42.124c.488 0 .884.392.884.883a.878.878 0 0 1-.884.884H20.768a.884.884 0 0 1 0-1.767zm0 11.325h42.124c.488 0 .884.391.884.883s-.392.883-.884.883H20.768c-.488 0-.884-.391-.884-.883s.396-.883.884-.883zm0 11.32h42.124c.488 0 .884.392.884.884a.878.878 0 0 1-.884.883H20.768a.881.881 0 0 1-.884-.883c0-.492.396-.884.884-.884z"/><path d="M75.359 11.065H72.8v66.408a4.413 4.413 0 0 1-4.408 4.409H19.597v2.57a2.65 2.65 0 0 0 2.645 2.647h53.113A2.65 2.65 0 0 0 78 84.453l.004-70.741a2.652 2.652 0 0 0-2.646-2.646zM28.91 17.628v-12.3L13.88 20.28h12.383a2.65 2.65 0 0 0 2.646-2.65z"/><path d="M26.572 88.87v2.57a2.65 2.65 0 0 0 2.646 2.646H82.33a2.65 2.65 0 0 0 2.646-2.645V20.695a2.65 2.65 0 0 0-2.646-2.646h-2.558v66.409a4.413 4.413 0 0 1-4.409 4.408H26.572z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -81,10 +81,26 @@
"send-to-chat": "Send to Chat",
"edit": "Edit",
"delete": "Delete",
"empty": "---"
"reset": "Reset",
"empty": "---",
"help": "Help",
"gm": "Server",
"view-larger": "View Larger"
},
"sheet-names": {
"UntypedDataSheet": "Data Sheet"
"*DataSheet": "Data Sheet"
},
"help-tooltips": {
"calculated-capacity": {
"title": "What is Calculated Capacity?",
"content": "<p>The calculated capacity is how much space in your inventory that the item will take up, the way it is calculated is determined by the item. Usually the main thing that affects the capacity is the item's quantity, but this can be turned off by the @dotdungeon.common.gm, which means that no matter the quantity it will only use up one capacity. The @dotdungeon.common.gm can also entirely disable capacity usage which will make the used capacity always be zero.</p>"
}
},
"delete": {
"ActiveEffect": {
"title": "Delete Effect",
"content": "<p>Are you sure you would like to delete the active effect: {name}</p>"
}
}
},
"TYPES": {
@ -105,6 +121,9 @@
"legendaryItem": "Legendary Item",
"spell": "Spell",
"untyped": "Custom"
},
"ActiveEffect": {
"base": "Effect"
}
}
}

125
module/components/icon.mjs Normal file
View file

@ -0,0 +1,125 @@
import { StyledShadowElement } from "./mixins/Styles.mjs";
/**
Attributes:
@property {string} name - The name of the icon, takes precedence over the path
@property {string} path - The path of the icon file
*/
export class DotDungeonIcon extends StyledShadowElement(HTMLElement) {
static elementName = `dd-icon`;
static formAssociated = false;
/* Stuff for the mixin to use */
static _stylePath = `v3/components/icon.css`;
static _cache = new Map();
#container;
/** @type {null | string} */
_name;
/** @type {null | string} */
_path;
/* Stored IDs for all of the hooks that are in this component */
#svgHmr;
constructor() {
super();
// this._shadow = this.attachShadow({ mode: `open`, delegatesFocus: true });
this.#container = document.createElement(`div`);
this._shadow.appendChild(this.#container);
};
_mounted = false;
async connectedCallback() {
super.connectedCallback();
if (this._mounted) return;
this._name = this.getAttribute(`name`);
this._path = this.getAttribute(`path`);
/*
This converts all of the double-dash prefixed properties on the element to
CSS variables so that they don't all need to be provided by doing style=""
*/
for (const attrVar of this.attributes) {
if (attrVar.name?.startsWith(`var:`)) {
const prop = attrVar.name.replace(`var:`, ``);
this.style.setProperty(`--` + prop, attrVar.value);
};
};
/*
Try to retrieve the icon if it isn't present, try the path then default to
the slot content, as then we can have a default per-icon usage
*/
let content;
if (this._name) {
content = await this.#getIcon(`./systems/dotdungeon/assets/${this._name}.svg`);
};
if (this._path && !content) {
content = await this.#getIcon(this._path);
};
if (content) {
this.#container.appendChild(content.cloneNode(true));
};
/*
This is so that when we get an HMR event from Foundry we can appropriately
handle it using our logic to update the component and the icon cache.
*/
if (game.settings.get(`dotdungeon`, `devMode`)) {
this.#svgHmr = Hooks.on(`dd-hmr:svg`, (iconName, data) => {
if (this._name === iconName || this._path?.endsWith(data.path)) {
const svg = this.#parseSVG(data.content);
this.constructor._cache.set(iconName, svg);
this.#container.replaceChildren(svg.cloneNode(true));
};
});
};
this._mounted = true;
};
disconnectedCallback() {
super.disconnectedCallback();
if (!this._mounted) return;
Hooks.off(`dd-hmr:svg`, this.#svgHmr);
this._mounted = false;
};
async #getIcon(path) {
// Cache hit!
if (this.constructor._cache.has(path)) {
console.debug(`.dungeon | Icon ${path} cache hit`);
return this.constructor._cache.get(path);
};
const r = await fetch(path);
switch (r.status) {
case 200:
case 201:
break;
default:
console.error(`.dungeon | Failed to fetch icon: ${path}`);
return;
};
console.debug(`.dungeon | Adding icon ${path} to the cache`);
const svg = this.#parseSVG(await r.text());
this.constructor._cache.set(path, svg);
return svg;
};
/** Takes an SVG string and returns it as a DOM node */
#parseSVG(content) {
const temp = document.createElement(`div`);
temp.innerHTML = content;
return temp.querySelector(`svg`);
};
};

View file

@ -0,0 +1,149 @@
import { DotDungeonIcon } from "./icon.mjs";
import { StyledShadowElement } from "./mixins/Styles.mjs";
/**
Attributes:
@property {string} name - The path to the value to update
@property {number} value - The actual value of the input
@property {number} min - The minimum value of the input
@property {number} max - The maximum value of the input
@property {number?} smallStep - The step size used for the buttons and arrow keys
@property {number?} largeStep - The step size used for the buttons + Ctrl and page up / down
Styling:
- `--height`: Controls the height of the element + the width of the buttons (default: 1.25rem)
- `--width`: Controls the width of the number input (default 50px)
*/
export class DotDungeonIncrementer extends StyledShadowElement(HTMLElement) {
static elementName = `dd-incrementer`;
static formAssociated = true;
static _stylePath = `v3/components/incrementer.css`;
_internals;
#input;
_min;
_max;
_smallStep;
_largeStep;
constructor() {
super();
// Form internals
this._internals = this.attachInternals();
this._internals.role = `spinbutton`;
};
get form() {
return this._internals.form;
}
get name() {
return this.getAttribute(`name`);
}
set name(value) {
this.setAttribute(`name`, value);
}
get value() {
return this.getAttribute(`value`);
};
set value(value) {
this.setAttribute(`value`, value);
};
get type() {
return `number`;
}
connectedCallback() {
super.connectedCallback();
this.replaceChildren();
// Attribute parsing / registration
const value = this.getAttribute(`value`);
this._min = parseInt(this.getAttribute(`min`) ?? 0);
this._max = parseInt(this.getAttribute(`max`) ?? 0);
this._smallStep = parseInt(this.getAttribute(`smallStep`) ?? 1);
this._largeStep = parseInt(this.getAttribute(`largeStep`) ?? 5);
this._internals.ariaValueMin = this._min;
this._internals.ariaValueMax = this._max;
const container = document.createElement(`div`);
// The input that the user can see / modify
const input = document.createElement(`input`);
this.#input = input;
input.type = `number`;
input.ariaHidden = true;
input.min = this.getAttribute(`min`);
input.max = this.getAttribute(`max`);
input.addEventListener(`change`, this.#updateValue.bind(this));
input.value = value;
// plus button
const increment = document.createElement(DotDungeonIcon.elementName);
increment.setAttribute(`name`, `ui/plus`);
increment.setAttribute(`var:size`, `0.75rem`);
increment.setAttribute(`var:fill`, `currentColor`);
increment.ariaHidden = true;
increment.classList.value = `increment`;
increment.addEventListener(`mousedown`, this.#increment.bind(this));
// minus button
const decrement = document.createElement(DotDungeonIcon.elementName);
decrement.setAttribute(`name`, `ui/minus`);
decrement.setAttribute(`var:size`, `0.75rem`);
decrement.setAttribute(`var:fill`, `currentColor`);
decrement.ariaHidden = true;
decrement.classList.value = `decrement`;
decrement.addEventListener(`mousedown`, this.#decrement.bind(this));
// Construct the DOM
container.appendChild(decrement);
container.appendChild(input);
container.appendChild(increment);
this._shadow.appendChild(container);
/*
This converts all of the namespace prefixed properties on the element to
CSS variables so that they don't all need to be provided by doing style=""
*/
for (const attrVar of this.attributes) {
if (attrVar.name?.startsWith(`var:`)) {
const prop = attrVar.name.replace(`var:`, ``);
this.style.setProperty(`--` + prop, attrVar.value);
};
};
};
#updateValue() {
let value = parseInt(this.#input.value);
if (this.getAttribute(`min`)) value = Math.max(this._min, value);
if (this.getAttribute(`max`)) value = Math.min(this._max, value);
this.#input.value = value;
this.value = value;
this.dispatchEvent(new Event(`change`, { bubbles: true }));
};
/** @param {Event} $e */
#increment($e) {
$e.preventDefault();
let value = parseInt(this.#input.value);
value += $e.ctrlKey ? this._largeStep : this._smallStep;
this.#input.value = value;
this.#updateValue();
};
/** @param {Event} $e */
#decrement($e) {
$e.preventDefault();
let value = parseInt(this.#input.value);
value -= $e.ctrlKey ? this._largeStep : this._smallStep;
this.#input.value = value;
this.#updateValue();
};
};

View file

@ -0,0 +1,23 @@
import { DotDungeonIncrementer } from "./incrementer.mjs";
import { DotDungeonIcon } from "./icon.mjs";
const components = [
DotDungeonIcon,
DotDungeonIncrementer,
];
export function registerCustomComponents() {
(CONFIG.CACHE ??= {}).componentListeners ??= [];
for (const component of components) {
if (!window.customElements.get(component.elementName)) {
console.debug(`.dungeon | Registering component "${component.elementName}"`);
window.customElements.define(
component.elementName,
component
);
if (component.formAssociated) {
CONFIG.CACHE.componentListeners.push(component.elementName);
}
};
}
};

View file

@ -0,0 +1,80 @@
/**
* @param {HTMLElement} Base
*/
export function StyledShadowElement(Base) {
return class extends Base {
/**
* The path to the CSS that is loaded
* @type {string}
*/
static _stylePath;
/**
* The stringified CSS to use
* @type {string}
*/
static _styles;
/**
* The HTML element of the stylesheet
* @type {HTMLStyleElement}
*/
_style;
/** @type {ShadowRoot} */
_shadow;
/**
* The hook ID for this element's CSS hot reload
* @type {number}
*/
#cssHmr;
constructor() {
super();
this._shadow = this.attachShadow({ mode: `open` });
this._style = document.createElement(`style`);
this._shadow.appendChild(this._style);
};
#mounted = false;
connectedCallback() {
if (this.#mounted) return;
this._getStyles();
if (game.settings.get(`dotdungeon`, `devMode`)) {
this.#cssHmr = Hooks.on(`dd-hmr:css`, (data) => {
if (data.path.endsWith(this.constructor._stylePath)) {
this._style.innerHTML = data.content;
};
});
};
this.#mounted = true;
};
disconnectedCallback() {
if (!this.#mounted) return;
if (this.#cssHmr != null) {
Hooks.off(`dd-hmr:css`, this.#cssHmr);
this.#cssHmr = null;
};
this.#mounted = false;
};
_getStyles() {
if (this.constructor._styles) {
this._style.innerHTML = this.constructor._styles;
} else {
fetch(`./systems/dotdungeon/.styles/${this.constructor._stylePath}`)
.then(r => r.text())
.then(t => {
this.constructor._styles = t;
this._style.innerHTML = t;
});
}
};
};
};

View file

@ -12,7 +12,7 @@ export class DiceList extends GenericDialog {
};
static get defaultOptions() {
const opts = mergeObject({
const opts = foundry.utils.mergeObject({
...super.defaultOptions,
template: `systems/dotdungeon/templates/dialogs/diceList.hbs`,
width: 275,

View file

@ -0,0 +1,7 @@
export class DotDungeonActiveEffect extends ActiveEffect {
// Invert the logic of the disabled property so it's easier to modify via
// embedded controls
get enabled() { return !this.disabled };
set enabled(newValue) { this.disabled = !newValue };
};

View file

@ -0,0 +1,42 @@
import { DotDungeonActiveEffect } from "./GenericActiveEffect.mjs";
const classes = {};
const defaultClass = DotDungeonActiveEffect;
export const ActiveEffectProxy = new Proxy(function () {}, {
construct(target, args) {
const [data] = args;
if (!classes.hasOwnProperty(data.type)) {
return new defaultClass(...args);
}
return new classes[data.type](...args);
},
get(target, prop, receiver) {
if (["create", "createDocuments"].includes(prop)) {
return function (data, options) {
if (data.constructor === Array) {
return data.map(i => ActiveEffectProxy.create(i, options))
}
if (!classes.hasOwnProperty(data.type)) {
return defaultClass.create(data, options);
}
return classes[data.type].create(data, options);
};
};
if (prop == Symbol.hasInstance) {
return function (instance) {
if (instance instanceof defaultClass) return true;
return Object.values(classes).some(i => instance instanceof i);
};
};
return defaultClass[prop];
},
});

View file

@ -1,4 +1,15 @@
export class DotDungeonActor extends Actor {
/*
Using this to take a "snapshot" of the system data prior to applying AE's so
that the inputs can still have the non-modified value in them, while we still
provide all that data to AE's without needing to disable any inputs.
*/
prepareEmbeddedDocuments() {
this.preAE = foundry.utils.deepClone(this.system);
super.prepareEmbeddedDocuments();
};
async createEmbeddedItem(defaults, opts = {}) {
let items = await this.createEmbeddedDocuments(`Item`, defaults);
if (!Array.isArray(items)) items = items ? [items] : [];

View file

@ -1,8 +1,22 @@
import { DotDungeonActor } from "./GenericActor.mjs";
import { DotDungeonItem } from "../Item/GenericItem.mjs";
export class Player extends DotDungeonActor {
applyActiveEffects() {
super.applyActiveEffects();
/*
These are the (groups of) fields that ActiveEffects may modify safely and
remain editable in the sheet. This needs to be done because of default
Foundry behaviour that otherwise prevents these fields from being edited.
The deletes must use optional chaining otherwise they can cause issues
during the document preparation lifecycle as an actor with no AE's affecting
anything in one of these areas will result in these paths being undefined.
*/
delete this.overrides.system?.stats;
delete this.overrides.system?.skills;
};
async createCustomPet() {
const body = new URLSearchParams({
number: 1,

View file

@ -1,4 +1,5 @@
import { DotDungeonActor } from "./GenericActor.mjs";
import { syncMilestones } from "../../config.mjs";
export class Sync extends DotDungeonActor {
async useRestDie() {

View file

@ -5,4 +5,11 @@ export class Material extends DotDungeonItem {
let affects = game.settings.get(`dotdungeon`, `materialsAffectCapacity`);
return affects ? super.usedCapacity : 0;
};
get availableLocations() {
return [
{ value: null, label: `dotdungeon.location.unknown` },
{ value: `inventory`, label: `dotdungeon.location.inventory` },
];
};
};

View file

@ -10,6 +10,7 @@ import { SyncData } from "./models/Actor/Sync.mjs";
import { MobData } from "./models/Actor/Mob.mjs";
// Main Documents
import { ActiveEffectProxy } from "./documents/ActiveEffect/_proxy.mjs";
import { ActorProxy } from "./documents/Actor/_proxy.mjs";
import { ItemProxy } from "./documents/Item/_proxy.mjs";
@ -32,6 +33,7 @@ import * as hbs from "./handlebars.mjs";
import "./hooks/hotReload.mjs";
// Misc Imports
import { registerCustomComponents } from "./components/index.mjs";
import loadSettings from "./settings/index.mjs";
import { devInit } from "./hooks/devInit.mjs";
import DOTDUNGEON from "./config.mjs";
@ -39,6 +41,7 @@ import DOTDUNGEON from "./config.mjs";
Hooks.once(`init`, async () => {
console.debug(`.dungeon | Initializing`);
CONFIG.ActiveEffect.legacyTransferral = false;
loadSettings();
@ -54,6 +57,7 @@ Hooks.once(`init`, async () => {
CONFIG.Item.dataModels.pet = PetItemData;
CONFIG.Actor.documentClass = ActorProxy;
CONFIG.Item.documentClass = ItemProxy;
CONFIG.ActiveEffect.documentClass = ActiveEffectProxy;
CONFIG.DOTDUNGEON = DOTDUNGEON;
@ -102,15 +106,13 @@ Hooks.once(`init`, async () => {
label: "dotdungeon.sheet-names.PetSheet"
});
if (game.settings.get(`dotdungeon`, `devMode`)) {
if (true || game.settings.get(`dotdungeon`, `devMode`)) {
devInit();
};
hbs.registerHandlebarsHelpers();
hbs.preloadHandlebarsTemplates();
CONFIG.CACHE = {};
CONFIG.CACHE.icons = await hbs.preloadIcons();
registerCustomComponents();
});

View file

@ -43,25 +43,6 @@ export const preAliasedPartials = {
"dotdungeon.pc.v2.foil": "actors/char-sheet/v2/partials/inventory/items/untyped.v2.pc.hbs",
};
export const icons = [
`caret-right.svg`,
`caret-down.svg`,
`garbage-bin.svg`,
`chat-bubble.svg`,
`dice/d4.svg`,
`dice/d6.svg`,
`dice/d8.svg`,
`dice/d10.svg`,
`dice/d12.svg`,
`dice/d20.svg`,
`create.svg`,
`close.svg`,
`edit.svg`,
`sheet.svg`,
`minus.svg`,
];
export async function registerHandlebarsHelpers() {
Handlebars.registerHelper(helpers);
};
@ -97,38 +78,3 @@ export async function preloadHandlebarsTemplates() {
console.groupEnd();
return loadTemplates(paths);
};
/**
* Loads all of the icons that are needed in the handlebars templating to make
* the sheet look nicer.
*
* @returns An object containing icon names to the corresponding HTML data for
* displaying the icon
*/
export async function preloadIcons() {
const pathPrefix = `systems/dotdungeon/assets/`
const parsedIcons = {};
for (const icon of icons) {
const iconName = icon.split(`/`).slice(-1)[0].slice(0, -4);
if (icon.endsWith(`.svg`)) {
try {
const response = await fetchWithTimeout(`${pathPrefix}${icon}`);
if (response.status !== 200) { continue };
const svgData = await response.text();
parsedIcons[iconName] = svgData;
} catch {
console.error(`.dungeon | Failed to fetch/parse icon: ${icon}`);
continue;
};
}
else if (icon.endsWith(`.png`)) {
parsedIcons[iconName] = `<img alt="" src="${pathPrefix}${icon}">`;
}
else {
console.warn(`.dungeon | Icon "${icon}" failed to be handled by a loader`)
};
};
return parsedIcons;
};

View file

@ -3,6 +3,7 @@ Initialization of dev-specific features for the init hook, this is primarily
used to register all of the data sheets of various entity types.
*/
import { GroupDataSheet } from "../sheets/Datasheets/GroupDataSheet.mjs";
import { UntypedDataSheet } from "../sheets/Datasheets/UntypedDataSheet.mjs";
export function devInit() {
@ -11,7 +12,16 @@ export function devInit() {
UntypedDataSheet,
{
types: [`untyped`, `foil`],
label: `dotdungeon.sheet-names.UntypedDataSheet`,
label: `dotdungeon.sheet-names.*DataSheet`,
}
);
Actors.registerSheet(
`dotdungeon`,
GroupDataSheet,
{
types: [`sync`],
label: `dotdungeon.sheet-names.*DataSheet`,
}
);
};

View file

@ -3,8 +3,8 @@ import * as hbs from "../handlebars.mjs";
const loaders = {
svg(data) {
const iconName = data.path.split(`/`).slice(-1)[0].slice(0, -4);
console.log(`.dungeon | hot-reloading icon: ${iconName}`);
CONFIG.CACHE.icons[iconName] = data.content;
console.debug(`.dungeon | hot-reloading icon: ${iconName}`);
Hooks.call(`dd-hmr:svg`, iconName, data);
},
hbs(data) {
if (!hbs.partials.some(p => data.path.endsWith(p))) {
@ -35,6 +35,10 @@ const loaders = {
},
js() {window.location.reload()},
mjs() {window.location.reload()},
css(data) {
console.debug(`.dungeon | Hot-reloading CSS: ${data.path}`);
Hooks.call(`dd-hmr:css`, data);
},
};
Hooks.on(`hotReload`, async (data) => {

View file

@ -10,7 +10,7 @@ export class AspectItemData extends DescribedItemData {
delete parentSchema.quantity_affects_used_capacity;
delete parentSchema.usage_cost;
return mergeObject(parentSchema, {
return foundry.utils.mergeObject(parentSchema, {
used: new fields.BooleanField({ initial: false }),
/** The number of seconds that the effect of the aspect stays */
deactivateAfter: new fields.NumberField({ nullable: true }),

View file

@ -3,7 +3,7 @@ import { CommonItemData } from "./CommonItemData.mjs";
export class DescribedItemData extends CommonItemData {
static defineSchema() {
const fields = foundry.data.fields;
return mergeObject(super.defineSchema(), {
return foundry.utils.mergeObject(super.defineSchema(), {
description: new fields.StringField({
initial: ``,
blank: true,

View file

@ -3,6 +3,6 @@ import { DescribedItemData } from "./DescribedItemData.mjs";
export class EquipmentItemData extends DescribedItemData {
static defineSchema() {
const fields = foundry.data.fields;
return mergeObject(super.defineSchema(), {});
return foundry.utils.mergeObject(super.defineSchema(), {});
};
};

View file

@ -9,7 +9,7 @@ export class PetItemData extends DescribedItemData {
delete parentSchema.quantity_affects_used_capacity;
delete parentSchema.usage_cost;
return mergeObject(parentSchema, {
return foundry.utils.mergeObject(parentSchema, {
upkeep: new fields.NumberField({ initial: null, nullable: true }),
pokeballd: new fields.BooleanField({ initial: true }),
});

View file

@ -4,7 +4,7 @@ import DOTDUNGEON from "../../config.mjs";
export class SpellItemData extends DescribedItemData {
static defineSchema() {
const fields = foundry.data.fields;
return mergeObject(super.defineSchema(), {
return foundry.utils.mergeObject(super.defineSchema(), {
skill: new fields.StringField({
initial: ``,
blank: true,

View file

@ -4,7 +4,7 @@ import DOTDUNGEON from "../../config.mjs";
export class WeaponItemData extends DescribedItemData {
static defineSchema() {
const fields = foundry.data.fields;
return mergeObject(super.defineSchema(), {
return foundry.utils.mergeObject(super.defineSchema(), {
damage: new fields.StringField({
initial: null,
nullable: true,

View file

@ -3,7 +3,7 @@ import { DescribedItemData } from "./DescribedItemData.mjs";
export class TemplateData extends DescribedItemData {
static defineSchema() {
const fields = foundry.data.fields;
return mergeObject(super.defineSchema(), {
return foundry.utils.mergeObject(super.defineSchema(), {
});
};
};

View file

@ -6,7 +6,7 @@ import { GenericContextMenu } from "../../../utils/GenericContextMenu.mjs";
export class PlayerSheetv2 extends GenericActorSheet {
static get defaultOptions() {
let opts = mergeObject(
let opts = foundry.utils.mergeObject(
super.defaultOptions,
{
template: `systems/dotdungeon/templates/actors/char-sheet/v2/sheet.hbs`,
@ -39,9 +39,8 @@ export class PlayerSheetv2 extends GenericActorSheet {
html.find(`.create-ae`).on(`click`, async ($e) => {
console.debug(`Creating an ActiveEffect?`);
ActiveEffect.implementation.create({
name: "Default AE",
}, { parent: this.actor, renderSheet: true });
const ae = this.actor.createEmbeddedDocuments(`ActiveEffect`, [{name: "Default AE"}]);
ae.sheet.render(true);
});
html.find(`[data-filter-toggle]`).on(`change`, ($e) => {
const target = $e.delegateTarget;
@ -74,6 +73,7 @@ export class PlayerSheetv2 extends GenericActorSheet {
/** @type {ActorHandler} */
const actor = this.actor;
ctx.preAE = actor.preAE;
ctx.system = actor.system;
ctx.flags = actor.flags;
ctx.items = this.actor.itemTypes;
@ -97,6 +97,7 @@ export class PlayerSheetv2 extends GenericActorSheet {
const stat = {
key: statName,
name: localizer(`dotdungeon.stat.${statName}`),
original: this.actor.preAE.stats[statName],
value: this.actor.system.stats[statName],
};
@ -111,7 +112,7 @@ export class PlayerSheetv2 extends GenericActorSheet {
return {
value: die,
label: localizer(`dotdungeon.die.${die}`, { stat: statName }),
disabled: usedDice.has(die) && this.actor.system.stats[statName] !== die,
disabled: usedDice.has(die) && this.actor.preAE.stats[statName] !== die,
};
})
];
@ -127,8 +128,9 @@ export class PlayerSheetv2 extends GenericActorSheet {
key: skill,
name: game.i18n.format(`dotdungeon.skills.${skill}`),
value,
original: this.actor.preAE.skills[statName][skill],
formula: `1` + stat.value + modifierToString(value, { spaces: true }),
rollDisabled: value === -1,
rollDisabled: this.actor.preAE.skills[statName][skill] === -1,
});
};
@ -167,9 +169,4 @@ export class PlayerSheetv2 extends GenericActorSheet {
max: this.actor.system.inventory_slots,
};
};
_updateObject(...args) {
console.log(args)
super._updateObject(...args);
};
}
}

View file

@ -0,0 +1,31 @@
export class GroupDataSheet extends ActorSheet {
static get defaultOptions() {
let opts = foundry.utils.mergeObject(
super.defaultOptions,
{
template: `systems/dotdungeon/templates/datasheets/actor/group.hbs`,
width: 200,
height: 275
},
);
opts.classes.push(`dotdungeon`, `style-v3`);
return opts;
};
async getData() {
const ctx = {};
ctx.actor = this.actor;
ctx.system = this.actor.system;
ctx.computed = {
milestones_hit_viewable: [...this.actor.system.milestones_hit.values()].join(`, `)
}
ctx.meta = {
idp: this.actor.uuid,
};
return ctx;
};
};

View file

@ -3,7 +3,7 @@ import DOTDUNGEON from "../config.mjs";
export class GenericActorSheet extends ActorSheet {
static get defaultOptions() {
let opts = mergeObject(
let opts = foundry.utils.mergeObject(
super.defaultOptions,
{
scrollY: [`.scrollable`],
@ -40,7 +40,7 @@ export class GenericActorSheet extends ActorSheet {
ctx.actor = this.actor;
ctx.config = DOTDUNGEON;
ctx.icons = CONFIG.CACHE.icons;
ctx.icons = {};
return ctx;
};
@ -52,6 +52,17 @@ export class GenericActorSheet extends ActorSheet {
if (!this.isEditable) return;
console.debug(`.dungeon | Generic sheet adding listeners`);
/*
Custom element event listeners because Foundry doesn't listen to them by
default.
*/
html.find(
CONFIG.CACHE.componentListeners.map(n => `${n}[name]`).join(`,`)
).on(`change`, () => this._onChangeInput.bind(this));
/*
Utility event listeners that apply
*/
html.find(`[data-collapse-id]`).on(`click`, this._handleSummaryToggle.bind(this));
html.find(`[data-roll-formula]`).on(`click`, this._handleRoll.bind(this));
html.find(`[data-embedded-update-on="change"]`)
@ -72,7 +83,6 @@ export class GenericActorSheet extends ActorSheet {
const id = $e.currentTarget.dataset.embeddedEdit;
this.openEmbeddedSheet.bind(this)(id);
})
.on(`click`, this.openEmbeddedSheet.bind(this));
html.find(`button[data-increment]`)
.on(`click`, this._incrementValue.bind(this));
html.find(`button[data-decrement]`)

View file

@ -2,7 +2,7 @@ import { GenericItemSheet } from "./GenericItemSheet.mjs";
export class AspectSheet extends GenericItemSheet {
static get defaultOptions() {
let opts = mergeObject(
let opts = foundry.utils.mergeObject(
super.defaultOptions,
{
template: `systems/dotdungeon/templates/items/aspect.hbs`,

View file

@ -1,3 +1,4 @@
import { DialogManager } from "../../utils/DialogManager.mjs";
import DOTDUNGEON from "../../config.mjs";
export class GenericItemSheet extends ItemSheet {
@ -29,9 +30,10 @@ export class GenericItemSheet extends ItemSheet {
ctx.item = this.item;
ctx.system = this.item.system;
ctx.flags = this.item.flags;
ctx.effects = this.item.effects;
ctx.config = DOTDUNGEON;
ctx.icons = CONFIG.CACHE.icons;
ctx.icons = {};
return ctx;
};
@ -45,6 +47,10 @@ export class GenericItemSheet extends ItemSheet {
.on(`click`, this._incrementValue.bind(this));
html.find(`button[data-decrement]`)
.on(`click`, this._decrementValue.bind(this));
html.find(`[data-help-id]`)
.on(`click`, this._helpPopup.bind(this));
};
async _incrementValue($e) {
@ -66,4 +72,15 @@ export class GenericItemSheet extends ItemSheet {
};
this.actor.update({ [data.decrement]: value - 1 });
};
async _helpPopup($e) {
const target = $e.currentTarget;
const data = target.dataset;
if (!data.helpId) return;
DialogManager.helpDialog(
data.helpId,
data.helpContent,
data.helpTitle
);
};
};

View file

@ -2,7 +2,7 @@ import { GenericItemSheet } from "./GenericItemSheet.mjs";
export class PetSheet extends GenericItemSheet {
static get defaultOptions() {
let opts = mergeObject(
let opts = foundry.utils.mergeObject(
super.defaultOptions,
{
template: `systems/dotdungeon/templates/items/pet.hbs`,

View file

@ -2,7 +2,7 @@ import { GenericItemSheet } from "./GenericItemSheet.mjs";
export class SpellSheet extends GenericItemSheet {
static get defaultOptions() {
let opts = mergeObject(
let opts = foundry.utils.mergeObject(
super.defaultOptions,
{
template: `systems/dotdungeon/templates/items/spell.hbs`,

View file

@ -1,9 +1,11 @@
import { GenericContextMenu } from "../../utils/GenericContextMenu.mjs";
import { DialogManager } from "../../utils/DialogManager.mjs";
import { GenericItemSheet } from "./GenericItemSheet.mjs";
import { localizer } from "../../utils/localizer.mjs";
export class UntypedItemSheet extends GenericItemSheet {
static get defaultOptions() {
let opts = mergeObject(
let opts = foundry.utils.mergeObject(
super.defaultOptions,
{
template: `systems/dotdungeon/templates/items/untyped/v2/index.hbs`,
@ -28,22 +30,78 @@ export class UntypedItemSheet extends GenericItemSheet {
new GenericContextMenu(html, `.photo.panel`, [
{
name: `View Larger`,
callback: (html) => {
console.log(`.dungeon | View Larger`);
name: localizer(`dotdungeon.common.view-larger`),
callback: () => {
(new ImagePopout(this.item.img)).render(true);
},
},
{
name: `Change Photo`,
name: localizer(`dotdungeon.common.edit`),
condition: () => this.isEditable,
callback: (html) => {
console.log(`.dungeon | Change Photo`);
callback: () => {
const fp = new FilePicker({
callback: (path) => {
this.item.update({"img": path});
},
});
fp.render(true);
},
},
{
name: localizer(`dotdungeon.common.reset`),
condition: () => this.isEditable,
callback: () => {
console.log(`.dungeon | Reset Item Image`)
},
}
]);
if (!this.isEditable) return;
console.debug(`.dungeon | Adding event listeners for Untyped Item: ${this.item.id}`);
html.find(`.create-ae`).on(`click`, async () => {
await this.item.createEmbeddedDocuments(
`ActiveEffect`,
[{name: localizer(`dotdungeon.default.name`, { document: `ActiveEffect`, type: `base` })}],
{ renderSheet: true }
);
});
new GenericContextMenu(html, `.effect.panel`, [
{
name: localizer(`dotdungeon.common.edit`),
callback: async (html) => {
(await fromUuid(html.closest(`.effect`)[0].dataset.embeddedId))?.sheet.render(true);
},
},
{
name: localizer(`dotdungeon.common.delete`),
callback: async (html) => {
const target = html.closest(`.effect`)[0];
const data = target.dataset;
const id = data.embeddedId;
const doc = await fromUuid(id);
DialogManager.createOrFocus(
`${doc.uuid}-delete`,
{
title: localizer(`dotdungeon.delete.ActiveEffect.title`, doc),
content: localizer(`dotdungeon.delete.ActiveEffect.content`, doc),
buttons: {
yes: {
label: localizer(`Yes`),
callback() {
doc.delete();
},
},
no: {
label: localizer(`No`),
}
}
}
);
},
}
]);
};
async getData() {

View file

@ -5,7 +5,7 @@ export class MVPPCSheet extends GenericActorSheet {
/** @override {ActorHandler} actor */
static get defaultOptions() {
let opts = mergeObject(
let opts = foundry.utils.mergeObject(
super.defaultOptions,
{
template: `systems/dotdungeon/templates/actors/char-sheet-mvp/sheet.hbs`

View file

@ -3,7 +3,7 @@ import { DiceList } from "../dialogs/DiceList.mjs";
export class MobSheet extends GenericActorSheet {
static get defaultOptions() {
let opts = mergeObject(
let opts = foundry.utils.mergeObject(
super.defaultOptions,
{
template: `systems/dotdungeon/templates/actors/mobs/main.hbs`,

View file

@ -2,7 +2,7 @@ import { GenericActorSheet } from "../GenericActorSheet.mjs";
export class AbstractSyncSheet extends GenericActorSheet {
static get defaultOptions() {
let opts = mergeObject(
let opts = foundry.utils.mergeObject(
super.defaultOptions,
{
width: 200,

View file

@ -0,0 +1,83 @@
import { localizer } from "./localizer.mjs";
/**
* A utility class that allows managing Dialogs that are created for various
* purposes such as deleting items, help popups, etc. This is a singleton class
* that upon instantiating after the first time will just return the first instance
*/
export class DialogManager {
/** @type {Map<string, Dialog>} */
static #dialogs = new Map();
/**
* Focuses a dialog if it already exists, or creates a new one and renders it.
*
* @param {string} dialogId The ID to associate with the dialog, should be unique
* @param {object} data The data to pass to the Dialog constructor
* @param {DialogOptions} opts The options to pass to the Dialog constructor
* @returns {Dialog} The Dialog instance
*/
static async createOrFocus(dialogId, data, opts = {}) {
if (DialogManager.#dialogs.has(dialogId)) {
const dialog = DialogManager.#dialogs.get(dialogId);
dialog.bringToTop();
return dialog;
};
/*
This makes sure that if I provide a close function as a part of the data,
that the dialog still gets removed from the set once it's closed, otherwise
it could lead to dangling references that I don't care to keep. Or if I don't
provide the close function, it just sets the function as there isn't anything
extra that's needed to be called.
*/
if (data?.close) {
const provided = data.close;
data.close = () => {
DialogManager.#dialogs.delete(dialogId);
provided();
};
}
else {
data.close = () => DialogManager.#dialogs.delete(dialogId);
};
// Create the Dialog with the modified data
const dialog = new Dialog(data, opts);
DialogManager.#dialogs.set(dialogId, dialog);
dialog.render(true);
return dialog;
};
/**
* Closes a dialog if it is rendered
*
* @param {string} dialogId The ID of the dialog to close
*/
static async close(dialogId) {
const dialog = DialogManager.#dialogs.get(dialogId);
dialog?.close();
};
static async helpDialog(
helpId,
helpContent,
helpTitle = `dotdungeon.common.help`,
localizationData = {},
) {
DialogManager.createOrFocus(
helpId,
{
title: localizer(helpTitle, localizationData),
content: localizer(helpContent, localizationData),
buttons: {},
},
{ resizable: true, }
);
};
static get size() {
return DialogManager.#dialogs.size;
}
};

View file

@ -18,12 +18,20 @@ export function localizer(key, args = {}, depth = 0) {
return localized;
};
/*
Helps prevent recursion on the same key so that we aren't doing excess work.
*/
const localizedSubkeys = new Map();
for (const match of subkeys) {
const subkey = match.groups.key;
localized =
localized.slice(0, match.index)
+ localizer(subkey, args, depth + 1)
+ localized.slice(match.index + subkey.length + 1)
if (localizedSubkeys.has(subkey)) continue;
localizedSubkeys.set(subkey, localizer(subkey, args, depth + 1));
};
return localized;
return localized.replace(
localizerConfig.subKeyPattern,
(_fullMatch, subkey) => {
return localizedSubkeys.get(subkey);
}
);
};

View file

@ -49,11 +49,11 @@
&__list {
&--material {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 8px;
}
&--untyped, &--aspect {
&--untyped, &--aspect, &--foil, &--weapon, &--pet {
display: flex;
gap: 8px;
flex-direction: column;
@ -68,7 +68,7 @@
.bytes-panel {
display: grid;
grid-template-columns: 1fr min-content 50px min-content;
grid-template-columns: 1fr auto;
gap: 8px;
align-items: center;
@ -164,8 +164,8 @@
@include material.elevate(1);
padding: 8px;
gap: 8px;
display: grid;
grid-template-columns: 1fr min-content 50px min-content;
display: flex;
justify-content: space-between;
align-items: center;
border-radius: 4px;

View file

@ -0,0 +1,7 @@
// Disclaimer: This CSS is used by a custom web component and is scoped to JUST
// the corresponding web component. This should only be imported by web component
// style files.
:host {
display: inline-block;
}

View file

@ -0,0 +1,23 @@
/*
Disclaimer: This CSS is used by a custom web component and is scoped to JUST
the corresponding web component. Importing this into other files is forbidden
*/
$default-size: 1rem;
@use "./common.scss";
div {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
}
svg {
width: var(--size, $default-size);
height: var(--size, $default-size);
fill: var(--fill);
stroke: var(--stroke);
}

View file

@ -0,0 +1,63 @@
/*
Disclaimer: This CSS is used by a custom web component and is scoped to JUST
the corresponding web component. Importing this into other files is forbidden
*/
$default-border-radius: 4px;
$default-height: 1.5rem;
@use "../mixins/material";
@use "./common.scss";
div {
display: grid;
grid-template-columns: var(--height, $default-height) var(--width, 50px) var(--height, $default-height);
grid-template-rows: var(--height, 1fr);
border-radius: var(--border-radius, $default-border-radius);
@include material.elevate(2);
&:hover {
@include material.elevate(4);
}
&:focus-within {
@include material.elevate(6);
}
}
span, input {
border: none;
outline: none;
background: none;
color: inherit;
}
input {
font-family: var(--font-family, inherit);
text-align: center;
font-size: var(--font-size, inherit);
padding: 2px 4px;
&::-webkit-inner-spin-button, &::-webkit-outer-spin-button {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
margin: 0
}
}
.increment, .decrement {
aspect-ratio: 1 / 1;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.increment {
border-radius: 0 var(--border-radius, $default-border-radius) var(--border-radius, 4px) 0;
}
.decrement {
border-radius: var(--border-radius, $default-border-radius) 0 0 var(--border-radius, $default-border-radius);
}

View file

@ -0,0 +1,24 @@
.dotdungeon.style-v3 {
input[type="checkbox"] {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
border-radius: 2px;
margin: 0;
cursor: pointer;
background: var(--elevation-8dp-bg);
position: relative;
&:checked::before {
content: "";
background: var(--checkbox-checked);
border-radius: 3px;
$margin: 4px;
top: $margin;
bottom: $margin;
left: $margin;
right: $margin;
position: absolute;
}
}
}

View file

@ -5,6 +5,7 @@
/* Element-Styling */
@use "./elements/utilities.scss";
@use "./elements/button.scss";
@use "./elements/checkbox.scss";
@use "./elements/select.scss";
@use "./elements/text-input.scss";
@use "./elements/number-input.scss";

View file

@ -44,6 +44,7 @@
%flex-col {
display: flex;
flex-direction: column;
gap: 8px;
}
@include utils.tab("details") {
@ -56,7 +57,25 @@
}
}
@include utils.tab("settings") {
@include utils.tab("effects") {
@extend %flex-col;
}
@include utils.tab("settings") {
@extend %flex-col;
.capacity-usage, .quantity-capacity, .combat-relevant {
display: flex;
align-items: center;
}
.capacity {
&--calculated {
display: flex;
flex-direction: row;
align-items: center;
gap: 8px;
}
}
}
}

View file

@ -4,4 +4,6 @@
--surface: #121212;
--on-surface: white;
--checkbox-checked: #00d300;
}

View file

@ -2,7 +2,7 @@
"id": "dotdungeon",
"title": ".dungeon",
"description": "",
"version": "0.0.7",
"version": "0.0.9",
"download": "https://github.com/Oliver-Akins/foundry.dungeon/releases/latest/download/dotdungeon.zip",
"manifest": "https://github.com/Oliver-Akins/foundry.dungeon/releases/latest/download/system.json",
"url": "https://github.com/Oliver-Akins/foundry.dungeon",

View file

@ -17,9 +17,7 @@
data-tooltip="{{filter.createLabel}}"
data-tooltip-direction="LEFT"
>
<div aria-hidden="true" class="icon icon--16">
{{{ @root.icons.create }}}
</div>
<dd-icon name="ui/plus" var:fill="currentColor"></dd-icon>
</button>
</div>
<hr>

View file

@ -13,9 +13,7 @@
tabindex="0"
aria-label="{{dd-i18n 'dotdungeon.sheet.actor.v2.toggle-item-information' item}}"
>
<div aria-hidden="true" class="icon icon--12">
{{{ icons.caret-right }}}
</div>
<dd-icon name="ui/caret/right" var:fill="currentColor" var:size="0.75rem"></dd-icon>
</button>
<h3 class="aspect__name">
{{item.name}}

View file

@ -7,52 +7,11 @@
>
{{item.name}}
</label>
{{#if (eq item.system.quantity 0)}}
<button
type="button"
class="material__button material__button--delete icon"
data-embedded-delete
data-embedded-id="{{item.uuid}}"
>
<div aria-hidden="true" class="icon icon--14">
{{{ icons.garbage-bin }}}
</div>
</button>
{{else}}
<button
type="button"
aria-hidden="true"
tabindex="-1"
class="material__button material__button--decrement icon"
data-embedded-decrement="system.quantity"
data-embedded-id="{{item.uuid}}"
>
<div aria-hidden="true" class="icon icon--14">
{{{ icons.minus }}}
</div>
</button>
{{/if}}
<input
type="number"
id="{{meta.idp}}-{{item.uuid}}-quantity-input"
class="material__input"
min="0"
<dd-incrementer
class="material__quantity"
value="{{item.system.quantity}}"
aria-label="The number of {{item.name}} you have"
data-embedded-id="{{item.uuid}}"
data-embedded-update="system.quantity"
data-embedded-update-on="blur"
>
<button
type="button"
aria-hidden="true"
tabindex="-1"
class="material__button material__button--increment icon"
data-embedded-increment="system.quantity"
data-embedded-update-on="change"
data-embedded-id="{{item.uuid}}"
>
<div aria-hidden="true" class="icon icon--14">
{{{ icons.create }}}
</div>
</button>
></dd-incrementer>
</div>

View file

@ -13,9 +13,7 @@
tabindex="0"
aria-label="{{dd-i18n 'dotdungeon.sheet.actor.v2.toggle-item-information' item}}"
>
<div aria-hidden="true" class="icon icon--12">
{{{ icons.caret-right }}}
</div>
<dd-icon name="ui/caret/right" var:fill="currentColor" var:size="0.75rem"></dd-icon>
</button>
<h3 class="pet__name">
{{item.name}}

View file

@ -13,9 +13,7 @@
tabindex="0"
aria-label="{{dd-i18n 'dotdungeon.sheet.actor.v2.toggle-item-information' item}}"
>
<div aria-hidden="true" class="icon icon--12">
{{{ icons.caret-right }}}
</div>
<dd-icon name="ui/caret/right" var:fill="currentColor" var:size="0.75rem"></dd-icon>
</button>
<h3 class="untyped__name">
{{item.name}}

View file

@ -13,9 +13,7 @@
tabindex="0"
aria-label="{{dd-i18n 'dotdungeon.sheet.actor.v2.toggle-item-information' item}}"
>
<div aria-hidden="true" class="icon icon--12">
{{{ icons.caret-right }}}
</div>
<dd-icon name="ui/caret/right" var:fill="currentColor" var:size="0.75rem"></dd-icon>
</button>
<h3 class="weapon__name">
{{item.name}}

View file

@ -11,35 +11,17 @@
</div>
<div class="e-1dp panel bytes-panel">
<label
for="{{meta.idp}}-player-inventory-supplies-input"
for="{{meta.idp}}-player-inventory-supplies"
>
Supplies
</label>
<button
type="button"
class="icon"
data-decrement="system.supplies"
aria-label="Decrease supply count by one"
>
<div aria-hidden="true" class="icon icon--14">
{{{ icons.minus }}}
</div>
</button>
<input
type="number"
id="{{meta.idp}}-player-inventory-supplies-input"
<dd-incrementer
var:height="1.5rem"
name="system.supplies"
value="{{system.supplies}}"
>
<button
type="button"
class="icon"
data-increment="system.supplies"
aria-label="Increase supply count by one"
>
<div aria-hidden="true" class="icon icon--14">
{{{ icons.create }}}
</div>
</button>
id="{{meta.idp}}-player-inventory-supplies"
min="0"
></dd-incrementer>
</div>
<div class="e-1dp panel bytes-panel">
<label
@ -47,31 +29,13 @@
>
Bytes
</label>
<button
type="button"
class="equal-padding"
data-decrement="system.bytes"
aria-label="Decrease byte count by one"
>
<div aria-hidden="true" class="icon icon--14">
{{{ icons.minus }}}
</div>
</button>
<input
type="number"
id="{{meta.idp}}-player-inventory-bytes-input"
<dd-incrementer
var:height="1.5rem"
name="system.bytes"
value="{{system.bytes}}"
>
<button
type="button"
class="equal-padding"
data-increment="system.bytes"
aria-label="Increase byte count by one"
>
<div aria-hidden="true" class="icon icon--14">
{{{ icons.create }}}
</div>
</button>
id="{{meta.idp}}-player-inventory-bytes"
min="0"
></dd-incrementer>
</div>
<div class="e-1dp panel filter-panel">
<h2>Show</h2>

View file

@ -7,7 +7,7 @@
name="system.stats.{{stat.key}}"
class="e-2dp dice-select"
>
{{{dd-options stat.value stat.dieOptions}}}
{{{dd-options stat.original stat.dieOptions}}}
</select>
<button
type="button"
@ -35,7 +35,7 @@
class="e-2dp skill__training"
>
{{{dd-options
skill.value
skill.original
@root.config.trainingLevels
localize=true
}}}

View file

@ -0,0 +1,36 @@
<form autocomplete="off" class="datasheet">
<div>
<label for="{{meta.idp}}-name" data-tooltip="name">Name</label>
<input
type="text"
name="name"
id="{{meta.idp}}-name"
value="{{actor.name}}"
>
</div>
<div>
<label for="{{meta.idp}}-sync" data-tooltip="system.value">Sync</label>
<input
type="number"
min="0"
name="system.value"
id="{{meta.idp}}-sync"
value="{{system.value}}"
>
</div>
<div>
<label for="{{meta.idp}}-restdice" data-tooltip="system.rest_dice">Rest Dice</label>
<input
type="number"
min="0"
name="system.rest_dice"
id="{{meta.idp}}-restdice"
value="{{system.rest_dice}}"
>
</div>
<div>
<span data-tooltip="system.milestones_hit">Milestones Hit</span>
<br>
{{ computed.milestones_hit_viewable }}
</div>
</form>

View file

@ -73,13 +73,14 @@
<label for="{{meta.idp}}-quantity">
Quantity
</label>
<input
<dd-incrementer value="{{system.supplies}}"></dd-incrementer>
{{!-- <input
type="number"
min="0"
name="system.quantity"
value="{{system.quantity}}"
id="{{meta.idp}}-quantity"
>
> --}}
{{else}}
Quantity
{{system.quantity}}

View file

@ -1,3 +1,34 @@
<div class="tab" data-group="page" data-tab="effects">
Effects Tab
{{#each effects as | effect |}}
<div class="effect panel" data-embedded-id="{{effect.uuid}}">
<div class="effect__name">
{{effect.name}}
</div>
<div>
{{ifThen effect.disabled "Disabled" "Enabled"}}
</div>
{{!-- TODO: For some reason this embedded update logic was failing
<label
class="effect__name"
for="{{effect.uuid}}-toggle"
>
{{ effect.name }}
</label>
<div class="effect__active">
<input
type="checkbox"
{{checked effect.enabled}}
id="{{effect.uuid}}-toggle"
data-embedded-id="{{effect.uuid}}"
data-embedded-update="disabled"
data-embedded-update-on="change"
>
</div>
--}}
</div>
{{/each}}
<button type="button" class="create-ae">
<dd-icon name="ui/plus" var:fill="currentColor"></dd-icon>
Create Effect
</button>
</div>

View file

@ -1,22 +1,61 @@
<div class="tab" data-group="page" data-tab="settings">
{{#if meta.isEmbedded}}
<div class="combat-relevant panel">
Useful in Combat?
<label for="{{meta.idp}}-{{item.uuid}}-combat-relevant">
Useful in Combat?
</label>
<div class="grow"></div>
<input
type="checkbox"
id="{{meta.idp}}-{{item.uuid}}-combat-relevant"
name="system.combat_relevant"
{{checked system.combat_relevant}}
>
</div>
{{/if}}
{{#if isGM}}
<div class="capacity-usage panel">
Uses Capacity?
<br>
(GM Only)
<label
for="{{meta.idp}}-{{item.uuid}}-uses-inventory-slot"
>
Uses Capacity?
<br>
(GM Only)
</label>
<div class="grow"></div>
<input
type="checkbox"
id="{{meta.idp}}-{{item.uuid}}-uses-inventory-slot"
name="system.uses_inventory_slot"
{{checked system.uses_inventory_slot}}
>
</div>
<div class="quantity-capacity panel">
Quantity Affects Capacity?
<br>
(GM Only)
<label for="{{meta.idp}}-{{item.uuid}}-quantity-adds-capacity">
Quantity Affects Capacity?
<br>
(GM Only)
</label>
<div class="grow"></div>
<input
type="checkbox"
id="{{meta.idp}}-{{item.uuid}}-quantity-adds-capacity"
name="system.quantity_affects_used_capacity"
{{checked system.quantity_affects_used_capacity}}
>
</div>
{{/if}}
<div class="calculated-capacity panel">
Total Capacity Used:
<div class="capacity--calculated panel">
<span>Capacity Used:</span>
<dd-icon
name="ui/help"
var:fill="red"
var:size="1.25rem"
data-help-id="calculated-capacity"
data-help-content="dotdungeon.help-tooltips.calculated-capacity.content"
data-help-title="dotdungeon.help-tooltips.calculated-capacity.title"
></dd-icon>
<div class="grow"></div>
<span>{{item.usedCapacity}}</span>
</div>
</div>