Compare commits

...
Sign in to create a new pull request.

61 commits

Author SHA1 Message Date
d7b8834481
fix: select option visibility in dark mode with proper background colors 2025-07-30 18:37:42 +02:00
bdfba8cacc
Fix actor image editing by removing static modifier from _onEditImage method 2025-07-29 20:28:09 +02:00
f643999573
Fix tab jumping on form input changes by preventing sheet re-rendering 2025-07-29 20:20:50 +02:00
d020822012
style: improve tab navigation height and spacing for icons
- Increase tab navigation height from 2x to 2.5x line-height
- Add proper flexbox centering for tab items with icons
- Add gap between icon and text (0.25rem)
- Add padding (0.5rem vertical, 0.75rem horizontal) for better touch targets
- Reduce icon size to 0.875rem for better visual balance
- Remove fixed line-height to allow proper vertical centering
- Maintain text shadow effect for active tabs

The tab navigation now properly accommodates FontAwesome icons while
maintaining good visual hierarchy and touch accessibility.
2025-07-29 19:08:06 +02:00
40e14d1196
feat: implement clean Foundry V13 compliant tab system
- Remove custom tab implementation in favor of official ApplicationV2 tabs
- Implement ApplicationTab typedef structure for Actor and Item sheets
- Add memory-safe event listener management with proper cleanup
- Update all sheet templates to use standard Foundry tab structure
- Add template safety checks to prevent undefined access errors
- Optimize performance with DOM updates instead of full re-renders
- Maintain backward CSS compatibility during transition
- Add dynamic tab configuration based on item types

Key improvements:
- ~200 lines of custom tab code removed
- Memory leak prevention with proper event cleanup
- Performance optimization (no re-render on tab switch)
- Standards-compliant with Foundry V13 ApplicationV2 API
- Consistent implementation across Actor and Item sheets
- Template safety with Handlebars guards
- Dynamic icon and localization support

All 31 modified files now use the official Foundry VTT v13 tab system.
2025-07-29 19:03:58 +02:00
2c4dbb2620
fix: remove unused parameter in weapon callback
- Remove unused _dialog parameter from weapon attack type selection callback
- Resolves ESLint error: '_dialog' is defined but never used
- Maintains functionality while improving code quality

This fixes the npm run lint:fix error and ensures clean ESLint compliance.
2025-07-28 22:20:29 +02:00
e021fedcdf
style: fix code formatting inconsistencies
- Remove excessive blank lines (triple+ newlines reduced to double)
- Fix EditorConfig indent_size from 4 to 2 spaces to match Prettier
- Ensure consistent whitespace formatting across JavaScript/TypeScript files
- Clean up formatting in templates (HBS files)

Files affected:
- src/apps/actor/base-sheet.js: Remove 6 instances of triple+ blank lines
- src/apps/item-sheet.js: Remove 4 instances of triple+ blank lines
- src/apps/ruler/token-ruler.js: Remove 1 instance of triple+ blank lines
- src/hooks/hooks.ts: Remove 1 instance of triple+ blank lines
- templates/sheets/actor/*.hbs: Remove excessive blank lines
- .editorconfig: Fix indent_size to match Prettier tabWidth (2 spaces)
2025-07-28 22:18:44 +02:00
7fcdcf8a5c
fix: correct effects display in item sheet template
- Fix item sheet effects template to use enrichedEffects instead of data.effects
- Ensures effects are properly displayed in the item sheet effects tab
- Aligns with actor sheet implementation for consistency

The template was referencing data.effects but the context preparation creates
enrichedEffects array with additional metadata (id, uuid, sourceName).
2025-07-28 22:14:41 +02:00
f807b59c9a
fix: add missing localization keys for sheet titles
- Add DS4.ActorSheet localization key ("Aktorbogen" / "Actor Sheet")
- Add DS4.ItemSheet localization key ("Itembogen" / "Item Sheet")

These keys are used in the get title() methods of DS4ActorSheet and DS4ItemSheet
to display properly localized sheet window titles instead of showing the raw
localization key strings.

Both keys are placed logically near other Actor/Item-related localization entries
for consistency.
2025-07-28 22:01:00 +02:00
3eaf69f558
fix: remove duplicate action handlers and improve template action generation
- Remove duplicate action handlers (edititem, deleteitem, createitem, etc.) from DS4ActorSheet and DS4ItemSheet
- Fix editImage method reference from static to prototype in DS4ActorSheet
- Add capitalize helper to handlebars-helpers.ts for dynamic action name generation
- Update control-button-group.hbs and add-button.hbs templates to use concat and capitalize helpers
- Ensure consistent camelCase naming for all action handlers (editItem, deleteItem, createItem, etc.)

This resolves action handler conflicts and improves maintainability by using dynamic template generation
instead of hardcoded conditional logic.
2025-07-28 21:55:06 +02:00
1358bfad93
style(ui): apply Wood Stamp font only to sheets 2025-07-17 20:34:35 +02:00
3c5e24a646
style(fonts): use readable font for window titles while keeping Wood
Stamp for content headings
2025-07-17 20:26:54 +02:00
bcf43f1bd6
style(headings): replace FoundryVTT header fonts with DS4 heading font 2025-07-17 20:17:25 +02:00
dfb2a4a781
feat(ui): use CSS container queries for precise header font scaling 2025-07-17 19:40:25 +02:00
9ea6bfac84
style(ui): adjust header font size automatically 2025-07-17 19:31:44 +02:00
651310446d
style(ui): apply lighter font weight to labels 2025-07-17 19:25:07 +02:00
a1cda785e9
style(ui): widen experience points field
needs to fit 5+ digits
2025-07-17 19:22:21 +02:00
796cbd4d53
style(ui): increase default item sheet width to 560px 2025-07-17 19:18:33 +02:00
a0c77ef7b8
style(ui): improve sheet name readability with lighter font weight 2025-07-17 19:16:59 +02:00
76d223db0f
fix(ui): remove duplicate data-action attributes in item sheet tabs 2025-07-17 18:40:45 +02:00
6037a8dcd4
style(ui): increase default actor sheet 2025-07-17 18:35:55 +02:00
590045405b
refactor(styles): extract shared ProseMirror styles to reduce
duplication
2025-07-17 18:23:07 +02:00
970f69be53
fix(editor): prevent double scrollbars in biography tab 2025-07-17 18:19:06 +02:00
07fa1487f1
fix(ui): use consistent height variable for select and input elements 2025-07-17 17:50:20 +02:00
686dc6b1f5
style: Remove debug log in item image editor 2025-07-16 22:40:25 +02:00
e9c223731d
fix(item-sheet): enable image editing via file picker 2025-07-16 22:33:34 +02:00
e30ce8947e
style: add dark mode inversion filter for embedded document list images
Apply the same brightness/invert filter used for combat values to
ds4-embedded-document-list__image class to ensure proper visibility of
combat value icons in dark theme.
2025-07-14 20:04:43 +02:00
f6ccd63e78
fix: update system version and Foundry compatibility 2025-07-13 16:52:34 +02:00
4479cdc4de
feat: enhance movement waypoint styling with semantic colors and
animations
2025-07-13 16:49:21 +02:00
7faadf6583
feat: add color-coded movement ruler for tactical gameplay 2025-07-13 16:12:04 +02:00
9e4dcee3c3
fix: add copyright attribution for v13 migration 2025-07-13 15:41:56 +02:00
916dc096df
fix: restore copyright notice for additional contributors 2025-07-13 15:41:56 +02:00
97ea5e8cc4
fix: update _onEditImage to proper V2 static method pattern
- Convert _onEditImage from instance to static method
2025-07-13 15:41:56 +02:00
e40c201dce
feat: update compatibility info in system.json 2025-07-13 15:41:56 +02:00
792f15dc57
fix: dragging of items onto the macro bar 2025-07-13 15:41:55 +02:00
6e1b043e4f
feat: update base sheet and item sheet classes 2025-07-13 15:41:55 +02:00
251cfa100b
feat: add minimal V13 CSS layer compatibility 2025-07-13 15:41:55 +02:00
27f40b1d96
feat: update Dialog implementation to use DialogV2 2025-07-13 15:41:55 +02:00
0f464f6081
fix: migrate Dialog.prompt to DialogV2 and fix deprecation warnings 2025-07-13 15:41:54 +02:00
c1f9db6095
fix: remove console.log statements from item sheet 2025-07-13 15:41:54 +02:00
3efbac9e84
feat: complete migration from {{editor}} to <prose-mirror> elements 2025-07-13 15:41:54 +02:00
372a2f718c
fix: update TextEditor references to use V13+ namespaced API 2025-07-13 15:41:54 +02:00
3284b132b4
fix: replace {{editor}} handlebars helper with <prose-mirror> custom element 2025-07-13 15:41:53 +02:00
093c94961d
feat: add dark mode styling for combat values and text strokes
Use CSS filters and light-dark() function for theme-adaptive icons and
text styling with proper contrast in both light and dark modes.
2025-07-13 15:41:53 +02:00
f46a89f470
feat: add dark mode styling for combat values 2025-07-13 15:41:53 +02:00
e001102278
feat: update Core Value trait label text stroke with light-dark color 2025-07-13 15:41:53 +02:00
8252a354cb
feat: implement V2-compatible portrait image editing
- Add editImage action to actor sheet actions - Use
foundry.applications.apps.FilePicker for V2 compatibility - Enable
portrait editing via click action in actor headers

Restores portrait editing functionality using proper V2 patterns.
2025-07-13 15:41:52 +02:00
aa9cbee8b4
feat: add Edit Image Handler to Actor Sheet 2025-07-13 15:41:52 +02:00
6c72605156
feat: complete ApplicationV1 to V2 migration cleanup
- Remove jQuery dependency from render hooks - Update
selectTargetInputOnFocus to use modern DOM methods - Remove legacy appv1
sheet unregistration calls - Eliminate all remaining V1 compatibility
code
2025-07-13 15:41:52 +02:00
76a0df49e8
feat: add method to handle form changes for items and effects 2025-07-13 15:41:52 +02:00
c363295e0f
feat: complete DS4 ApplicationV2 migration with item and effect sheets
Port remaining DS4ItemSheet and DS4ActiveEffectConfig to ApplicationV2.
2025-07-13 15:41:52 +02:00
4821eba0a9
feat!: complete ApplicationV2 migration with item sheet port
Convert DS4ItemSheet and all item sheet templates from ApplicationV1 to
ItemSheetV2. Add V2 action handlers, tab navigation, and form
processing. Update effect management to use DialogV2. Preserve all
functionality including tab state and override handling.
2025-07-13 15:41:51 +02:00
f0c5fa07dd
feat: update localization keys for delete dialogs 2025-07-13 15:41:51 +02:00
1b7b9f1e8e
refactor: port DS4 dialogs to ApplicationV2
Convert DialogWithListeners and check-factory.js from deprecated Dialog
V1 to DialogV2. Replace jQuery with native DOM methods and update button
format. Fixes all remaining V1 Application framework deprecation
warnings.
2025-07-13 15:41:51 +02:00
bcc263cc5e
feat: add persistent active tab tracking to actor sheet 2025-07-13 15:41:51 +02:00
df8c94a21f
refactor: refactor Check Roll to custom DS4 Actor Method 2025-07-13 15:41:51 +02:00
9ed959337d
feat: update Roll evaluation methods 2025-07-13 15:41:50 +02:00
bfbd327e51
refactor: refactor form submission logic in actor sheet 2025-07-13 15:41:50 +02:00
cd44db079f
feat!: port DS4 actor sheets to ApplicationV2
Convert DS4ActorSheet, DS4CharacterActorSheet, and DS4CreatureActorSheet
from ApplicationV1 to ApplicationV2 architecture. Update all templates
to use data-action attributes. Implement manual tab system and preserve
all existing functionality including item management, effects, and
rolling system.

BREAKING CHANGE: Requires FoundryVTT ApplicationV2 system
2025-07-12 20:44:03 +02:00
2a797ed8ed
Update class imports to use fully qualified Foundry paths 2025-05-02 11:53:38 +02:00
c26574d2d1
Fix expand rolls in chat in v13 2025-05-02 11:21:09 +02:00
79 changed files with 2199 additions and 1013 deletions

View file

@ -8,6 +8,6 @@ root = true
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true

View file

@ -3,9 +3,11 @@
"DS4.UserInteractionAddItemTitle": "Item Erstellen",
"DS4.UserInteractionEditItemTitle": "Item Bearbeiten",
"DS4.UserInteractionDeleteItemTitle": "Item Löschen",
"DS4.UserInteractionDeleteItemContent": "Sind Sie sicher, dass Sie {item} löschen möchten?",
"DS4.UserInteractionAddEffectTitle": "Effekt Erstellen",
"DS4.UserInteractionEditEffectTitle": "Effekt Bearbeiten",
"DS4.UserInteractionDeleteEffectTitle": "Effekt Löschen",
"DS4.UserInteractionDeleteEffectContent": "Sind Sie sicher, dass Sie {effect} löschen möchten?",
"DS4.DocumentImageAltText": "Bild von {name}",
"DS4.RollableImageRollableTitle": "Für {name} würfeln",
"DS4.DiceOverlayImageAltText": "Bild eines W20",
@ -182,7 +184,9 @@
"DS4.EffectFactor": "Faktor (wie oft der Effekt angewendet wird)",
"DS4.EffectFactorAbbr": "F",
"DS4.ActorName": "Name",
"DS4.ActorSheet": "Aktorbogen",
"DS4.ActorImageAltText": "Bild des Aktors",
"DS4.ItemSheet": "Itembogen",
"DS4.ActorTypeCharacter": "Charakter",
"DS4.ActorTypeCreature": "Kreatur",
"DS4.Attribute": "Attribut",

View file

@ -3,9 +3,11 @@
"DS4.UserInteractionAddItemTitle": "Create Item",
"DS4.UserInteractionEditItemTitle": "Edit Item",
"DS4.UserInteractionDeleteItemTitle": "Delete Item",
"DS4.UserInteractionDeleteItemContent": "Are you sure you want to delete {item}?",
"DS4.UserInteractionAddEffectTitle": "Create Effect",
"DS4.UserInteractionEditEffectTitle": "Edit Effect",
"DS4.UserInteractionDeleteEffectTitle": "Delete Effect",
"DS4.UserInteractionDeleteEffectContent": "Are you sure you want to delete {effect}?",
"DS4.DocumentImageAltText": "Image of {name}",
"DS4.RollableImageRollableTitle": "Roll for {name}",
"DS4.DiceOverlayImageAltText": "Image of a d20",
@ -182,7 +184,9 @@
"DS4.EffectFactor": "Factor (the number of times the effect is being applied)",
"DS4.EffectFactorAbbr": "F",
"DS4.ActorName": "Name",
"DS4.ActorSheet": "Actor Sheet",
"DS4.ActorImageAltText": "Image of the Actor",
"DS4.ItemSheet": "Item Sheet",
"DS4.ActorTypeCharacter": "Character",
"DS4.ActorTypeCreature": "Creature",
"DS4.Attribute": "Attribute",

View file

@ -42,6 +42,7 @@
align-items: center;
border-bottom: 0;
margin: 0;
container-type: inline-size;
}
&__name-input[type="text"] {
@ -49,7 +50,10 @@
background-color: transparent;
border: none;
flex: 1;
font-size: 1.25em;
font-size: clamp(0.75em, 8cqi, 1.25em);
height: auto;
// Use lighter font weight for better readability
font-weight: 300;
}
}

View file

@ -29,10 +29,11 @@
margin: 0;
padding: 0;
text-align: right;
font-weight: 300;
}
&__input {
flex: 0 0 5ch;
flex: 0 0 8ch;
&--slayer-points {
&::-webkit-inner-spin-button,

View file

@ -26,7 +26,7 @@
&__property-select {
width: 100%;
height: var(--form-field-height);
height: var(--input-height);
}
&__property-multi-input {

View file

@ -8,4 +8,10 @@
display: grid;
grid-template-columns: 1fr 3fr;
column-gap: 1em;
height: 100%;
}
.ds4-biography {
height: 100%;
overflow: hidden;
}

View file

@ -71,3 +71,13 @@
flex: 1 1 4em;
}
}
// Dark mode filter for combat value backgrounds when in dark theme
.theme-dark .ds4-combat-value__value {
filter: brightness(0) invert(1) brightness(0.8);
// Counter-invert the text to keep it normal
.ds4-combat-value__text {
filter: brightness(1.25) invert(1) brightness(0.8);
}
}

View file

@ -35,7 +35,7 @@
&--trait {
.ds4-core-value__label {
-webkit-text-stroke: 1px colors.$c-black;
-webkit-text-stroke: 1px light-dark(colors.$c-black, colors.$c-white);
color: transparent;
}
}

View file

@ -33,6 +33,7 @@
&__name {
border: none;
margin: 0;
container-type: inline-size;
}
&__name-label {
@ -43,9 +44,10 @@
@include mixins.font-heading-upper;
background-color: transparent;
border: none;
font-size: 1.25em;
font-size: clamp(0.75em, 8cqi, 1.25em);
height: auto;
padding-left: 0;
padding-right: 0;
font-weight: 300;
}
}

View file

@ -16,3 +16,38 @@
}
}
}
// General ProseMirror editor styles
prose-mirror {
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
// Edit mode with editor container
&.active {
.editor-container {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
.editor-content {
flex: 1;
overflow-y: auto;
min-height: 0;
}
}
}
// View mode - direct editor-content
&.inactive {
.editor-content {
position: relative;
flex: 1;
overflow-y: auto;
min-height: 0;
inset: auto;
}
}
}

View file

@ -150,3 +150,8 @@
margin-top: 1em;
padding-left: 1em;
}
// Dark mode filter for embedded document list images when in dark theme
.theme-dark .ds4-embedded-document-list__image {
filter: brightness(0) invert(1) brightness(0.8);
}

View file

@ -4,12 +4,13 @@
* SPDX-License-Identifier: MIT
*/
.ds4-form-group {
.ds4-form-group,
.ds4-item-sheet .form-group {
clear: both;
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin: 3px 0;
margin: 8px 0;
align-items: center;
&--start {
@ -22,6 +23,107 @@
&__label {
flex: 2;
line-height: var(--form-field-height);
line-height: var(--input-height);
}
// Add spacing between form groups
& + & {
margin-top: 12px;
}
// Style for slim form groups (input + select combinations)
&.slim {
margin: 6px 0;
.form-fields {
display: flex;
align-items: center;
gap: 4px;
input {
flex: 1;
min-width: 60px;
}
select {
flex: 0 0 auto;
min-width: 120px;
width: auto !important;
}
label {
flex: 0 0 auto;
margin-right: 8px;
font-weight: bold;
}
}
}
}
// Style standard Foundry form-fields containers
.ds4-item-sheet .form-fields {
display: flex;
align-items: center;
gap: 6px;
flex: 1;
input, select, textarea {
background: rgba(255, 255, 255, 0.05);
border: 1px solid var(--color-border);
border-radius: 3px;
padding: 4px 8px;
color: var(--color-text-primary);
&:focus {
border-color: var(--color-text-accent);
box-shadow: 0 0 3px var(--color-text-accent);
}
}
select {
background: rgba(255, 255, 255, 0.05);
appearance: none;
background-image: url("data:image/svg+xml;charset=US-ASCII,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'><path fill='%23efe6d8' d='M2 0L0 2h4zm0 5L0 3h4z'/></svg>");
background-repeat: no-repeat;
background-position: right 8px center;
background-size: 8px;
padding-right: 24px;
width: auto !important;
}
}
// Dark mode: try to achieve dark background for select options
.theme-dark .ds4-item-sheet .form-fields select {
color-scheme: dark;
option {
background-color: var(--color-cool-4) !important;
background: var(--color-cool-4) !important;
color: var(--color-light-2) !important;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
option:checked {
background-color: var(--color-cool-3) !important;
background: var(--color-cool-3) !important;
color: var(--color-light-1) !important;
}
option:hover {
background-color: var(--color-cool-3) !important;
background: var(--color-cool-3) !important;
}
}
// Improve label styling
.ds4-item-sheet .form-group > label {
flex: 0 0 160px;
font-weight: bold;
color: var(--color-form-label);
line-height: var(--input-height);
margin-right: 12px;
}

View file

@ -0,0 +1,63 @@
/*
* SPDX-FileCopyrightText: 2025 Alexander Minges
*
* SPDX-License-Identifier: MIT
*/
/* Token Ruler Waypoint Styling with Color-Coded Movement Ranges */
.system-ds4 .waypoint-label {
font-size: 1.5em;
// Main icon styling for movement types
&.move-range > i.fa-person-walking {
color: var(--color-level-success);
}
&.dash-range > i.fa-person-running {
color: var(--color-level-warning);
}
&.out-of-range > i.fa-person-rays {
color: var(--color-level-error);
animation: pulse 2s infinite;
}
.distance {
&.move-range {
color: var(--color-level-success);
}
&.dash-range {
color: var(--color-level-warning);
font-weight: bold;
}
&.out-of-range {
color: var(--color-level-error);
font-weight: bold;
animation: pulse 2s infinite;
}
}
.delta {
opacity: 0.8;
font-size: 0.9em;
}
.elevation {
font-style: italic;
opacity: 0.9;
}
}
/* Icon animations */
@keyframes pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.6;
}
}

View file

@ -4,7 +4,14 @@
* SPDX-License-Identifier: MIT
*/
.ds4-sheet-body {
.ds4-sheet-body,
.sheet-body {
height: 100%;
overflow-y: auto;
// Prevent double scrollbars on biography tab
.ds4-sheet-tab.tab.biography.active,
.tab[data-tab="biography"].active {
overflow: hidden;
}
}

View file

@ -4,7 +4,8 @@
* SPDX-License-Identifier: MIT
*/
.ds4-sheet-tab {
.ds4-sheet-tab,
.tab {
flex-direction: column;
flex-wrap: nowrap;
height: 100%;

View file

@ -6,20 +6,31 @@
@use "../../utils/variables";
.ds4-sheet-tab-nav {
.ds4-sheet-tab-nav,
nav.tabs {
border-bottom: variables.$border-groove;
border-top: variables.$border-groove;
display: flex;
flex-wrap: nowrap;
height: calc(2 * var(--line-height-16));
height: calc(2.5 * var(--line-height-16));
justify-content: space-around;
line-height: calc(2 * var(--line-height-16));
margin: variables.$margin-sm 0;
&__item {
.ds4-sheet-tab-nav__item,
.item {
flex: 0 1 auto !important; // necessary to override the styling from lang-de, see https://gitlab.com/henry4k/foundryvtt-lang-de/-/issues/9
font-weight: bold;
white-space: nowrap;
display: flex;
align-items: center;
justify-content: center;
gap: 0.25rem;
padding: 0.5rem 0.75rem;
line-height: 1;
i {
font-size: 0.875rem;
}
&.active {
text-shadow: 0 0 variables.$padding-md var(--color-shadow-primary);

View file

@ -19,6 +19,7 @@
@import "components/shared/embedded_document_list";
@import "components/shared/form_group";
@import "components/shared/rollable_image";
@import "components/shared/ruler";
@import "components/shared/sheet_body";
@import "components/shared/sheet_form";
@import "components/shared/sheet_tab_nav";

View file

@ -58,3 +58,27 @@
--ds4-font-primary: Lora, serif;
--ds4-font-heading: "Wood Stamp", sans-serif;
}
// Apply Wood Stamp font only to DS4 sheet-specific elements (excluding window titles)
.ds4-actor-sheet h2,
.ds4-actor-sheet h4,
.ds4-actor-sheet h5,
.ds4-actor-sheet h6,
.ds4-item-sheet h2,
.ds4-item-sheet h4,
.ds4-item-sheet h5,
.ds4-item-sheet h6,
.ds4-currency-title,
.ds4-embedded-document-list-title {
font-family: var(--ds4-font-heading) !important;
text-transform: uppercase;
font-weight: 100 !important;
}
// Keep window titles readable with standard font
.ds4-actor-sheet .window-title,
.ds4-item-sheet .window-title {
font-family: var(--font-sans) !important;
text-transform: none !important;
font-weight: normal !important;
}

View file

@ -2,31 +2,55 @@
//
// SPDX-License-Identifier: MIT
export class DS4ActiveEffectConfig extends ActiveEffectConfig {
/**
* DS4 Active Effect Configuration Sheet
*/
export class DS4ActiveEffectConfig extends foundry.applications.sheets.ActiveEffectConfig {
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: ["sheet", "ds4-active-effect-config", "themed"],
};
/** @override */
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
template: "systems/ds4/templates/sheets/active-effect/active-effect-config.hbs",
});
get template() {
return "systems/ds4/templates/sheets/active-effect/active-effect-config.hbs";
}
/**
* @override
* @param {JQuery} html
*/
activateListeners(html) {
super.activateListeners(html);
const checkbox = html[0]?.querySelector('input[name="flags.ds4.itemEffectConfig.applyToItems"]');
checkbox?.addEventListener("change", () => this.#toggleItemEffectConfig(checkbox.checked));
/** @override */
async _prepareContext(options) {
const context = await super._prepareContext(options);
// Add DS4-specific context
context.itemEffectConfig = this.document.flags?.ds4?.itemEffectConfig || {};
context.applyToItems = context.itemEffectConfig.applyToItems || false;
return context;
}
/** @override */
async _onRender(context, options) {
await super._onRender(context, options);
// Set up initial visibility of item effect config section
const applyToItems = this.document.flags?.ds4?.itemEffectConfig?.applyToItems || false;
this._toggleItemEffectConfigVisibility(applyToItems);
// Add event listener for the checkbox
const checkbox = this.element.querySelector('input[name="flags.ds4.itemEffectConfig.applyToItems"]');
if (checkbox) {
checkbox.addEventListener("change", (event) => {
this._toggleItemEffectConfigVisibility(event.target.checked);
});
}
}
/**
* Toggle the visibility of the item effect config section
* @param {boolean} active The target state
* @param {boolean} active - The target state
*/
#toggleItemEffectConfig(active) {
const elements = this.element[0]?.querySelectorAll(".ds4-item-effect-config");
elements?.forEach((element) => {
_toggleItemEffectConfigVisibility(active) {
const elements = this.element.querySelectorAll(".ds4-item-effect-config");
elements.forEach((element) => {
if (active) {
element.classList.remove("ds4-hidden");
} else {

File diff suppressed because it is too large Load diff

View file

@ -1,25 +1,34 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher
// SPDX-FileCopyrightText: 2025 Alexander Minges
//
// SPDX-License-Identifier: MIT
import { DS4ActorSheet } from "./base-sheet";
import { DS4ActorSheet } from "./base-sheet.js";
/**
* The Sheet class for DS4 Character Actors
*/
export class DS4CharacterActorSheet extends DS4ActorSheet {
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["sheet", "ds4-actor-sheet", "ds4-character-sheet"],
});
}
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: ["sheet", "ds4-actor-sheet", "ds4-character-sheet", "themed"],
};
/** @override */
async getData(options = {}) {
const context = await super.getData(options);
context.data.system.profile.biography = await TextEditor.enrichHTML(context.data.system.profile.biography, {
async: true,
});
async _prepareContext(options) {
const context = await super._prepareContext(options);
// Enrich biography HTML content
if (context.data.system.profile.biography) {
context.data.system.profile.biography = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
context.data.system.profile.biography,
{
async: true,
relativeTo: this.document,
},
);
}
return context;
}
}

View file

@ -1,25 +1,51 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher
// SPDX-FileCopyrightText: 2025 Alexander Minges
//
// SPDX-License-Identifier: MIT
import { DS4ActorSheet } from "./base-sheet";
import { DS4ActorSheet } from "./base-sheet.js";
/**
* The Sheet class for DS4 Creature Actors
*/
export class DS4CreatureActorSheet extends DS4ActorSheet {
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["sheet", "ds4-actor-sheet", "ds4-creature-sheet"],
});
}
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: ["sheet", "ds4-actor-sheet", "ds4-creature-sheet", "themed"],
};
static TABS = {
primary: {
initial: "values",
tabs: [
{ id: "values", label: "DS4.HeadingValues", icon: "fas fa-chart-bar" },
{ id: "inventory", label: "DS4.HeadingInventory", icon: "fas fa-backpack" },
{ id: "spells", label: "DS4.HeadingSpells", icon: "fas fa-magic" },
{ id: "abilities", label: "DS4.HeadingAbilities", icon: "fas fa-fist-raised" },
{ id: "effects", label: "DS4.HeadingEffects", icon: "fas fa-sparkles" },
{ id: "description", label: "DS4.HeadingDescription", icon: "fas fa-file-text" }
]
}
};
/** @override */
async getData(options = {}) {
const context = await super.getData(options);
context.data.system.baseInfo.description = await TextEditor.enrichHTML(context.data.system.baseInfo.description, {
async: true,
});
async _prepareContext(options) {
const context = await super._prepareContext(options);
// Enrich description HTML content
if (context.data.system.baseInfo.description) {
context.data.system.baseInfo.description = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
context.data.system.baseInfo.description,
{
async: true,
relativeTo: this.document,
},
);
}
// Add tabs configuration using ApplicationTab typedef
context.tabs = this._prepareTabs("primary");
return context;
}
}

View file

@ -3,19 +3,129 @@
// SPDX-License-Identifier: MIT
/**
* @typedef {DialogOptions} DialogWithListenersOptions
* @property {(html: JQuery, app: DialogWithListeners) => void} [activateAdditionalListeners] An optional function to attach additional listeners to the dialog
* A simple extension to the DialogV2 class that allows attaching additional listeners.
*/
export class DialogWithListeners extends foundry.applications.api.DialogV2 {
constructor(options = {}) {
super(options);
this.activateAdditionalListeners = options.activateAdditionalListeners;
}
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: ["dialog", "dialog-with-listeners"],
tag: "dialog",
window: {
resizable: true,
},
};
/**
* A simple extension to the {@link Dialog} class that allows attaching additional listeners.
*/
export class DialogWithListeners extends Dialog {
/** @override */
activateListeners(html) {
super.activateListeners(html);
if (this.options.activateAdditionalListeners !== undefined) {
this.options.activateAdditionalListeners(html, this);
async _onRender(context, options) {
await super._onRender(context, options);
// Attach additional listeners if provided
if (this.activateAdditionalListeners && typeof this.activateAdditionalListeners === "function") {
this.activateAdditionalListeners(this.element, this);
}
}
/**
* Create a confirmation dialog using the V2 framework with additional listeners support
* @param {object} options - Dialog options
* @param {string} options.title - Dialog title (deprecated, use window.title)
* @param {object} options.window - Window configuration
* @param {string} options.window.title - Dialog title
* @param {string} options.content - Dialog content HTML
* @param {boolean} options.defaultYes - Whether "Yes" is the default button
* @param {Function} options.activateAdditionalListeners - Function to attach additional listeners
* @returns {Promise<boolean>} True if confirmed, false if cancelled
*/
static async confirm(options = {}) {
const { title, window = {}, content, defaultYes = true, activateAdditionalListeners, ...rest } = options;
// Handle backward compatibility with title parameter
if (title && !window.title) {
window.title = title;
}
return new Promise((resolve) => {
const dialog = new DialogWithListeners({
window: {
title: window.title || "Confirm",
...window,
},
content,
activateAdditionalListeners,
buttons: [
{
action: "yes",
label: game.i18n.localize("Yes"),
icon: "fas fa-check",
default: defaultYes,
callback: () => resolve(true),
},
{
action: "no",
label: game.i18n.localize("No"),
icon: "fas fa-times",
default: !defaultYes,
callback: () => resolve(false),
},
],
close: () => resolve(false),
...rest,
});
dialog.render(true);
});
}
/**
* Create a prompt dialog using the V2 framework with additional listeners support
* @param {object} options - Dialog options
* @param {string} options.title - Dialog title (deprecated, use window.title)
* @param {object} options.window - Window configuration
* @param {string} options.window.title - Dialog title
* @param {string} options.content - Dialog content HTML
* @param {object} options.buttons - Button configuration
* @param {Function} options.activateAdditionalListeners - Function to attach additional listeners
* @returns {Promise} Promise that resolves with the result
*/
static async prompt(options = {}) {
const { title, window = {}, content, buttons = {}, activateAdditionalListeners, ...rest } = options;
// Handle backward compatibility with title parameter
if (title && !window.title) {
window.title = title;
}
return new Promise((resolve) => {
// Convert V1 button format to V2 format
const v2Buttons = Object.entries(buttons).map(([key, button]) => ({
action: key,
label: button.label || key,
icon: button.icon || "",
default: button.default || false,
callback: (event) => {
const result = button.callback ? button.callback(event) : key;
resolve(result);
},
}));
const dialog = new DialogWithListeners({
window: {
title: window.title || "Dialog",
...window,
},
content,
activateAdditionalListeners,
buttons: v2Buttons,
close: () => resolve(null),
...rest,
});
dialog.render(true);
});
}
}

View file

@ -1,27 +1,63 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher
// SPDX-FileCopyrightText: 2021 Oliver Rümpelein
// SPDX-FileCopyrightText: 2021 Gesina Schwalbe
// SPDX-FileCopyrightText: 2025 Alexander Minges
//
// SPDX-License-Identifier: MIT
import { DS4 } from "../config";
import { DS4ActiveEffect } from "../documents/active-effect";
import { enforce, getGame } from "../utils/utils";
import { disableOverriddenFields } from "./sheet-helpers";
/**
* The Sheet class for DS4 Items
*/
export class DS4ItemSheet extends ItemSheet {
/** @override */
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["sheet", "ds4-item-sheet"],
export class DS4ItemSheet extends foundry.applications.api.HandlebarsApplicationMixin(
foundry.applications.sheets.ItemSheetV2,
) {
static DEFAULT_OPTIONS = {
classes: ["sheet", "ds4-item-sheet", "themed"],
tag: "form",
form: {
submitOnChange: true,
closeOnSubmit: false,
},
position: {
width: 560,
height: 400,
scrollY: [".ds4-sheet-body"],
tabs: [{ navSelector: ".ds4-sheet-tab-nav", contentSelector: ".ds4-sheet-body", initial: "description" }],
width: 540,
});
},
window: {
resizable: true,
},
actions: {
controlEffect: DS4ItemSheet.prototype._onControlEffect,
createEffect: DS4ItemSheet.prototype._onCreateEffect,
editEffect: DS4ItemSheet.prototype._onEditEffect,
deleteEffect: DS4ItemSheet.prototype._onDeleteEffect,
editImage: DS4ItemSheet.prototype._onEditImage,
},
};
static TABS = {
primary: {
initial: "description",
tabs: [
{ id: "description", label: "DS4.HeadingDescription", icon: "fas fa-book" },
{ id: "effects", label: "DS4.HeadingEffects", icon: "fas fa-sparkles" }
]
}
};
constructor(options = {}) {
super(options);
// Initialize tabGroups with default values
if (!this.tabGroups) {
this.tabGroups = {};
}
// Set default tab for primary group
if (!this.tabGroups.primary) {
this.tabGroups.primary = this.constructor.TABS.primary?.initial || "description";
}
}
get title() {
return `${this.item.name} [${game.i18n.localize("DS4.ItemSheet")}]`;
}
/** @override */
@ -31,120 +67,358 @@ export class DS4ItemSheet extends ItemSheet {
}
/** @override */
async getData(options = {}) {
const superContext = await super.getData(options);
superContext.data.system.description = await TextEditor.enrichHTML(superContext.data.system.description, {
async: true,
});
const context = {
...superContext,
config: DS4,
isOwned: this.item.isOwned,
actor: this.item.actor,
};
async _renderHTML(context) {
return await foundry.applications.handlebars.renderTemplate(this.template, context);
}
/** @override */
_replaceHTML(result, content) {
content.innerHTML = result;
}
/** @override */
async _prepareContext(options) {
const context = await super._prepareContext(options);
// Validate document exists
if (!this.item) {
throw new Error("Item not available for sheet rendering");
}
// Add document data
context.data = this.item;
context.system = this.item.system;
context.source = this.item.toObject();
context.cssClass = this.item.constructor.name.toLowerCase();
context.editable = this.isEditable;
context.owner = this.item.isOwner;
context.isOwned = this.item.isOwned;
context.actor = this.actor;
// Add configuration
context.config = CONFIG.DS4;
// Add tabs configuration using ApplicationTab typedef
context.tabs = this._prepareTabs("primary");
// Add enriched effects
context.enrichedEffects = [];
if (this.item.effects && this.item.effects.size > 0) {
for (const effect of this.item.effects) {
const enrichedEffect = effect.toObject();
enrichedEffect.id = effect.id;
enrichedEffect.uuid = effect.uuid;
enrichedEffect.sourceName = effect.sourceName;
context.enrichedEffects.push(enrichedEffect);
}
}
// Enrich description content for display
if (this.item.system.description) {
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
this.item.system.description,
{
secrets: this.item.isOwner,
relativeTo: this.item,
},
);
} else {
context.enrichedDescription = "";
}
return context;
}
/** @override */
_getSubmitData(updateData = {}) {
const data = super._getSubmitData(updateData);
/**
* Process form data for submission
* @param {Event} event - The form submission event
* @param {HTMLFormElement} form - The form element
* @param {FormDataExtended} formData - The form data
* @returns {object} The processed form data
*/
_processFormData(event, form, formData) {
const submitData = foundry.utils.expandObject(formData.object);
// Prevent submitting overridden values
const overrides = foundry.utils.flattenObject(this.item.overrides);
for (const k of Object.keys(overrides)) {
delete data[k];
foundry.utils.setProperty(submitData, k, undefined);
delete submitData[k];
}
return data;
return submitData;
}
/**
* Handle effect control actions
* @param {Event} event - The triggering event
* @param {HTMLElement} target - The target element
*/
async _onControlEffect(event, target) {
const action = target.dataset.action;
const effectId = target.closest("[data-effect-id]")?.dataset.effectId;
if (!effectId) return;
const effect = this.item.effects.get(effectId);
if (!effect) return;
switch (action) {
case "edit":
await this._onEditEffect(event, target);
break;
case "delete":
await this._onDeleteEffect(event, target);
break;
}
}
/**
* Handle creating a new effect
*/
async _onCreateEffect() {
const effectData = {
name: game.i18n.localize("DS4.NewEffectName"),
icon: "icons/svg/aura.svg",
};
await this.item.createEmbeddedDocuments("ActiveEffect", [effectData]);
}
/**
* Handle editing an effect
* @param {Event} event - The triggering event
* @param {HTMLElement} target - The target element
*/
async _onEditEffect(event, target) {
const effectId = target.closest("[data-effect-id]")?.dataset.effectId;
if (!effectId) return;
const effect = this.item.effects.get(effectId);
if (!effect) {
throw new Error(
game.i18n.format("DS4.ErrorItemDoesNotHaveEffect", {
id: effectId,
item: this.item.name,
}),
);
}
await effect.sheet.render(true);
}
/**
* Handle deleting an effect
* @param {Event} event - The triggering event
* @param {HTMLElement} target - The target element
*/
async _onDeleteEffect(event, target) {
const effectId = target.closest("[data-effect-id]")?.dataset.effectId;
if (!effectId) return;
const effect = this.item.effects.get(effectId);
if (!effect) return;
const confirmed = await foundry.applications.api.DialogV2.confirm({
window: { title: game.i18n.localize("DS4.UserInteractionDeleteEffectTitle") },
content: game.i18n.format("DS4.UserInteractionDeleteEffectContent", { effect: effect.name }),
defaultYes: false,
});
if (confirmed) {
await effect.delete();
}
}
/**
* Handle editing the items's image
* @param {Event} event - The triggering event
* @param {HTMLElement} target - The target element
*/
async _onEditImage(event, target) {
const field = target.dataset.field || "img";
const current = foundry.utils.getProperty(this.item, field);
const fp = new foundry.applications.apps.FilePicker({
type: "image",
current: current,
callback: (path) => this.item.update({ [field]: path }),
});
return fp.browse();
}
/** @override */
setPosition(options = {}) {
const position = super.setPosition(options);
if (position) {
const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - 192;
sheetBody.css("height", bodyHeight);
async _onRender(context, options) {
await super._onRender(context, options);
this._initializeTabHandlers();
}
/**
* Initialize tab event handlers manually since ApplicationV2 doesn't do this automatically
*/
_initializeTabHandlers() {
const tabNavigation = this.element.querySelector('.tabs[data-group="primary"]');
if (!tabNavigation) {
return;
}
return position;
// Remove existing event listeners to prevent memory leaks
this._removeTabHandlers();
// Store tab navigation reference for cleanup
this._tabNavigation = tabNavigation;
// Create bound handler function for later removal
this._tabClickHandler = (event) => {
event.preventDefault();
const item = event.target.closest('.item[data-tab]');
if (!item) {
return;
}
const tabId = item.dataset.tab;
const groupId = item.dataset.group;
if (tabId && groupId) {
this.changeTab(tabId, groupId);
}
};
// Add single delegated event listener to the navigation container
tabNavigation.addEventListener('click', this._tabClickHandler);
}
/**
* @override
* @param {JQuery} html
* Override form submission to prevent re-rendering
*/
activateListeners(html) {
super.activateListeners(html);
if (!this.options.editable) return;
html.find(".control-effect").on("click", this.onControlEffect.bind(this));
disableOverriddenFields(this.form, this.item.overrides, (key) => `[name="${key}"]`);
async _processSubmitData(event, form, submitData, options = {}) {
// Always prevent re-rendering on form updates
options.render = false;
return super._processSubmitData(event, form, submitData, options);
}
/**
* Handles a click on an element of this sheet to control an embedded effect of the item corresponding to this
* sheet.
*
* @param {JQuery.ClickEvent} event The originating click event
* @protected
* Remove tab event handlers to prevent memory leaks
*/
onControlEffect(event) {
event.preventDefault();
const a = event.currentTarget;
switch (a.dataset["action"]) {
case "create":
return this.onCreateEffect();
case "edit":
return this.onEditEffect(event);
case "delete":
return this.onDeleteEffect(event);
_removeTabHandlers() {
if (this._tabNavigation && this._tabClickHandler) {
this._tabNavigation.removeEventListener('click', this._tabClickHandler);
}
}
/**
* Creates a new embedded effect.
* @protected
* Override changeTab to ensure proper tab switching without forced re-render
*/
onCreateEffect() {
DS4ActiveEffect.createDefault(this.item);
changeTab(tab, group, options = {}) {
// Call parent changeTab method
const result = super.changeTab(tab, group, options);
// Update tab display without full re-render
this._updateTabDisplay(tab, group);
return result;
}
/**
* Opens the sheet of the embedded effect corresponding to the clicked element.
*
* @param {JQuery.ClickEvent} event The originating click event
* @porotected
* Update tab display without full re-render for better performance
*/
onEditEffect(event) {
const id = $(event.currentTarget)
.parents(embeddedDocumentListEntryProperties.ActiveEffect.selector)
.data(embeddedDocumentListEntryProperties.ActiveEffect.idDataAttribute);
const effect = this.item.effects.get(id);
enforce(effect, getGame().i18n.format("DS4.ErrorItemDoesNotHaveEffect", { id, item: this.item.name }));
effect.sheet?.render(true);
_updateTabDisplay(activeTab, group) {
const tabNavigation = this.element.querySelector(`.tabs[data-group="${group}"]`);
const tabContent = this.element.querySelector('.sheet-body');
if (!tabNavigation || !tabContent) return;
// Update navigation active states
const navItems = tabNavigation.querySelectorAll('.item[data-tab]');
navItems.forEach(item => {
if (item.dataset.tab === activeTab) {
item.classList.add('active');
} else {
item.classList.remove('active');
}
});
// Update content tab visibility
const contentTabs = tabContent.querySelectorAll('.tab[data-tab]');
contentTabs.forEach(tab => {
if (tab.dataset.tab === activeTab) {
tab.classList.add('active');
} else {
tab.classList.remove('active');
}
});
}
/**
* Deletes the embedded item corresponding to the clicked element.
*
* @param {JQuery.ClickEvent} event The originating click event
* @protected
* Override _onClose to cleanup event listeners
*/
onDeleteEffect(event) {
const li = $(event.currentTarget).parents(embeddedDocumentListEntryProperties.ActiveEffect.selector);
const id = li.data(embeddedDocumentListEntryProperties.ActiveEffect.idDataAttribute);
this.item.deleteEmbeddedDocuments("ActiveEffect", [id]);
li.slideUp(200, () => this.render(false));
async _onClose(options) {
this._removeTabHandlers();
return super._onClose(options);
}
/**
* Prepare tabs for a given group using ApplicationTab typedef
* @param {string} group - The tab group identifier
* @returns {Record<string, ApplicationTab>} Prepared tab data
*/
_prepareTabs(group) {
const config = this._getTabsConfigForItemType();
if (!config) return {};
// Ensure tabGroups is initialized
if (!this.tabGroups[group]) {
this.tabGroups[group] = config.initial || "description";
}
const tabs = {};
for (const tabConfig of config.tabs) {
const isActive = this.tabGroups[group] === tabConfig.id;
tabs[tabConfig.id] = {
id: tabConfig.id,
group: group,
icon: tabConfig.icon,
label: game.i18n.localize(tabConfig.label),
active: isActive,
cssClass: isActive ? "active" : ""
};
}
return tabs;
}
/**
* Get tab configuration based on item type
* @returns {Object} Tab configuration for this item type
*/
_getTabsConfigForItemType() {
const tabs = [
{ id: "description", label: "DS4.HeadingDescription", icon: "fas fa-book" }
];
// Item types that have properties tabs
const itemsWithProperties = [
"weapon", "armor", "shield", "equipment", "loot",
"spell", "talent", "specialCreatureAbility"
];
if (itemsWithProperties.includes(this.item.type)) {
tabs.push({
id: "properties",
label: "DS4.HeadingProperties",
icon: "fas fa-cogs"
});
}
// All items can have effects
tabs.push({
id: "effects",
label: "DS4.HeadingEffects",
icon: "fas fa-sparkles"
});
return { tabs, initial: "description" };
}
}
/**
* This object contains information about specific properties embedded document list entries for each different type.
*/
const embeddedDocumentListEntryProperties = Object.freeze({
ActiveEffect: {
selector: ".effect",
idDataAttribute: "effectId",
},
});

View file

@ -0,0 +1,44 @@
// SPDX-FileCopyrightText: 2025 Alexander Minges
//
// SPDX-License-Identifier: MIT
/**
* DS4 Token Ruler implementation with color-coded movement ranges
* Based on actor movement combat value
*/
export class DS4TokenRuler extends foundry.canvas.placeables.tokens.TokenRuler {
static WAYPOINT_LABEL_TEMPLATE = "systems/ds4/templates/partials/waypoint-label.hbs";
/**
* Enhance waypoint label context with movement range information
* @param {object} waypoint - The waypoint data
* @param {object} state - The current ruler state
* @returns {object} Enhanced context with range class
*/
_getWaypointLabelContext(waypoint, state) {
const context = super._getWaypointLabelContext(waypoint, state);
// Only apply movement coloring for distance measurements in meters
if (context?.cost?.units === "m" || context?.distance?.units === "m") {
const movement = this.token?.actor?.system?.combatValues?.movement?.total;
if (movement) {
const total = Number(context.cost?.total || context.distance?.total || 0);
// DS4 movement rules:
// - Normal movement: up to movement value
// - Dash: up to 2x movement value (requires action)
// - Beyond 2x: impossible in single turn
if (total > 2 * movement) {
context.rangeClass = "out-of-range";
} else if (total <= movement) {
context.rangeClass = "move-range";
} else {
context.rangeClass = "dash-range";
}
}
}
return context;
}
}

View file

@ -111,6 +111,11 @@ export async function createCheckRoll(checkTargetNumber, options = {}) {
// Ask for additional required data;
const interactiveRollData = await askForInteractiveRollData(checkTargetNumber, options);
// Handle cancelled dialog
if (!interactiveRollData) {
return undefined;
}
const newTargetValue = interactiveRollData.checkTargetNumber ?? checkTargetNumber;
const checkModifier = interactiveRollData.checkModifier ?? 0;
/** @type {Partial<DS4CheckFactoryOptions>} */
@ -166,63 +171,69 @@ async function askForInteractiveRollData(checkTargetNumber, options = {}, { temp
}),
id,
};
const renderedHtml = await renderTemplate(usedTemplate, templateData);
const renderedHtml = await foundry.applications.handlebars.renderTemplate(usedTemplate, templateData);
const dialogPromise = new Promise((resolve) => {
new DialogWithListeners(
{
new DialogWithListeners({
window: {
title: usedTitle,
content: renderedHtml,
buttons: {
ok: {
icon: '<i class="fas fa-check"></i>',
label: getGame().i18n.localize("DS4.GenericOkButton"),
callback: (html) => {
if (!("jquery" in html)) {
throw new Error(
getGame().i18n.format("DS4.ErrorUnexpectedHtmlType", {
exType: "JQuery",
realType: "HTMLElement",
}),
);
} else {
const innerForm = html[0]?.querySelector("form");
if (!innerForm) {
throw new Error(
getGame().i18n.format("DS4.ErrorCouldNotFindHtmlElement", {
htmlElement: "form",
}),
);
}
resolve(innerForm);
}
},
},
cancel: {
icon: '<i class="fas fa-times"></i>',
label: getGame().i18n.localize("DS4.GenericCancelButton"),
},
content: renderedHtml,
buttons: [
{
action: "ok",
icon: "fas fa-check",
label: getGame().i18n.localize("DS4.GenericOkButton"),
default: true,
callback: (event) => {
const dialog = event.target.closest("dialog");
const innerForm = dialog?.querySelector("form");
if (!innerForm) {
throw new Error(
getGame().i18n.format("DS4.ErrorCouldNotFindHtmlElement", {
htmlElement: "form",
}),
);
}
resolve(innerForm);
},
},
default: "ok",
},
{
activateAdditionalListeners: (html, app) => {
const checkModifierCustomFormGroup = html.find(`#check-modifier-custom-${id}`).parent(".form-group");
html.find(`#check-modifier-${id}`).on("change", (event) => {
if (event.currentTarget.value === "custom" && checkModifierCustomFormGroup.hasClass("ds4-hidden")) {
checkModifierCustomFormGroup.removeClass("ds4-hidden");
{
action: "cancel",
icon: "fas fa-times",
label: getGame().i18n.localize("DS4.GenericCancelButton"),
callback: () => resolve(null),
},
],
close: () => resolve(null),
activateAdditionalListeners: (html, app) => {
const checkModifierCustomFormGroup = html.querySelector(`#check-modifier-custom-${id}`)?.closest(".form-group");
const checkModifierSelect = html.querySelector(`#check-modifier-${id}`);
if (checkModifierSelect) {
checkModifierSelect.addEventListener("change", (event) => {
if (
event.currentTarget.value === "custom" &&
checkModifierCustomFormGroup?.classList.contains("ds4-hidden")
) {
checkModifierCustomFormGroup.classList.remove("ds4-hidden");
app.setPosition({ height: "auto" });
} else if (!checkModifierCustomFormGroup.hasClass("ds4-hidden")) {
checkModifierCustomFormGroup.addClass("ds4-hidden");
} else if (checkModifierCustomFormGroup && !checkModifierCustomFormGroup.classList.contains("ds4-hidden")) {
checkModifierCustomFormGroup.classList.add("ds4-hidden");
app.setPosition({ height: "auto" });
}
});
},
id,
}
},
).render(true);
}).render(true);
});
const dialogForm = await dialogPromise;
// Handle cancelled dialog
if (!dialogForm) {
return null;
}
return parseDialogFormData(dialogForm);
}
@ -232,6 +243,11 @@ async function askForInteractiveRollData(checkTargetNumber, options = {}, { temp
* @returns {Partial<IntermediateInteractiveRollData>}
*/
function parseDialogFormData(formData) {
// Handle cancelled dialog
if (!formData) {
return {};
}
const chosenCheckTargetNumber = parseInt(formData["check-target-number"]?.value);
const chosenCheckModifier = formData["check-modifier"]?.value;

View file

@ -29,6 +29,6 @@ export class DS4Roll extends Roll {
isCoup: isPrivate ? null : isCoup,
isFumble: isPrivate ? null : isFumble,
};
return renderTemplate(template, chatData);
return foundry.applications.handlebars.renderTemplate(template, chatData);
}
}

View file

@ -1,5 +1,6 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher
// SPDX-FileCopyrightText: 2021 Oliver RÜmpelein
// SPDX-FileCopyrightText: 2025 Alexander Minges
//
// SPDX-License-Identifier: MIT
@ -463,60 +464,65 @@ export class DS4Actor extends Actor {
async selectAttributeAndTrait() {
const attributeIdentifier = "attribute-trait-selection-attribute";
const traitIdentifier = "attribute-trait-selection-trait";
return Dialog.prompt({
title: getGame().i18n.localize("DS4.DialogAttributeTraitSelection"),
content: await renderTemplate("systems/ds4/templates/dialogs/simple-select-form.hbs", {
selects: [
{
label: getGame().i18n.localize("DS4.Attribute"),
identifier: attributeIdentifier,
options: Object.fromEntries(
Object.entries(DS4.i18n.attributes).map(([attribute, translation]) => [
attribute,
`${translation} (${this.system.attributes[attribute].total})`,
]),
),
},
{
label: getGame().i18n.localize("DS4.Trait"),
identifier: traitIdentifier,
options: Object.fromEntries(
Object.entries(DS4.i18n.traits).map(([trait, translation]) => [
trait,
`${translation} (${this.system.traits[trait].total})`,
]),
),
},
],
}),
label: getGame().i18n.localize("DS4.GenericOkButton"),
callback: (html) => {
const selectedAttribute = html.find(`#${attributeIdentifier}`).val();
if (!isAttribute(selectedAttribute)) {
throw new Error(
getGame().i18n.format("DS4.ErrorUnexpectedAttribute", {
actualAttribute: selectedAttribute,
expectedTypes: Object.keys(DS4.i18n.attributes)
.map((attribute) => `'${attribute}'`)
.join(", "),
}),
);
}
const selectedTrait = html.find(`#${traitIdentifier}`).val();
if (!isTrait(selectedTrait)) {
throw new Error(
getGame().i18n.format("DS4.ErrorUnexpectedTrait", {
actualTrait: selectedTrait,
expectedTypes: Object.keys(DS4.i18n.traits)
.map((attribute) => `'${attribute}'`)
.join(", "),
}),
);
}
return {
attribute: selectedAttribute,
trait: selectedTrait,
};
return foundry.applications.api.DialogV2.prompt({
window: { title: getGame().i18n.localize("DS4.DialogAttributeTraitSelection") },
content: await foundry.applications.handlebars.renderTemplate(
"systems/ds4/templates/dialogs/simple-select-form.hbs",
{
selects: [
{
label: getGame().i18n.localize("DS4.Attribute"),
identifier: attributeIdentifier,
options: Object.fromEntries(
Object.entries(DS4.i18n.attributes).map(([attribute, translation]) => [
attribute,
`${translation} (${this.system.attributes[attribute].total})`,
]),
),
},
{
label: getGame().i18n.localize("DS4.Trait"),
identifier: traitIdentifier,
options: Object.fromEntries(
Object.entries(DS4.i18n.traits).map(([trait, translation]) => [
trait,
`${translation} (${this.system.traits[trait].total})`,
]),
),
},
],
},
),
ok: {
label: getGame().i18n.localize("DS4.GenericOkButton"),
callback: (_event, button) => {
const selectedAttribute = button.form.elements[attributeIdentifier].value;
if (!isAttribute(selectedAttribute)) {
throw new Error(
getGame().i18n.format("DS4.ErrorUnexpectedAttribute", {
actualAttribute: selectedAttribute,
expectedTypes: Object.keys(DS4.i18n.attributes)
.map((attribute) => `'${attribute}'`)
.join(", "),
}),
);
}
const selectedTrait = button.form.elements[traitIdentifier].value;
if (!isTrait(selectedTrait)) {
throw new Error(
getGame().i18n.format("DS4.ErrorUnexpectedTrait", {
actualTrait: selectedTrait,
expectedTypes: Object.keys(DS4.i18n.traits)
.map((attribute) => `'${attribute}'`)
.join(", "),
}),
);
}
return {
attribute: selectedAttribute,
trait: selectedTrait,
};
},
},
rejectClose: false,
});

View file

@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: 2022 Johannes Loher
// SPDX-FileCopyrightText: 2025 Alexander Minges
//
// SPDX-License-Identifier: MIT
@ -83,29 +84,34 @@ export class DS4Weapon extends DS4Item {
const { melee, ranged } = { ...DS4.i18n.attackTypes };
const identifier = `attack-type-selection-${foundry.utils.randomID()}`;
return Dialog.prompt({
title: getGame().i18n.localize("DS4.DialogAttackTypeSelection"),
content: await renderTemplate("systems/ds4/templates/dialogs/simple-select-form.hbs", {
selects: [
{
label: getGame().i18n.localize("DS4.AttackType"),
identifier,
options: { melee, ranged },
},
],
}),
label: getGame().i18n.localize("DS4.GenericOkButton"),
callback: (html) => {
const selectedAttackType = html.find(`#${identifier}`).val();
if (selectedAttackType !== "melee" && selectedAttackType !== "ranged") {
throw new Error(
getGame().i18n.format("DS4.ErrorUnexpectedAttackType", {
actualType: selectedAttackType,
expectedTypes: "'melee', 'ranged'",
}),
);
}
return selectedAttackType;
return foundry.applications.api.DialogV2.prompt({
window: { title: getGame().i18n.localize("DS4.DialogAttackTypeSelection") },
content: await foundry.applications.handlebars.renderTemplate(
"systems/ds4/templates/dialogs/simple-select-form.hbs",
{
selects: [
{
label: getGame().i18n.localize("DS4.AttackType"),
identifier,
options: { melee, ranged },
},
],
},
),
ok: {
label: getGame().i18n.localize("DS4.GenericOkButton"),
callback: (_event, button) => {
const selectedAttackType = button.form.elements[identifier].value;
if (selectedAttackType !== "melee" && selectedAttackType !== "ranged") {
throw new Error(
getGame().i18n.format("DS4.ErrorUnexpectedAttackType", {
actualType: selectedAttackType,
expectedTypes: "'melee', 'ranged'",
}),
);
}
return selectedAttackType;
},
},
});
}

View file

@ -14,6 +14,11 @@ const helpers = {
isEmpty: (input: Array<unknown> | null | undefined): boolean => (input?.length ?? 0) === 0,
capitalize: (str: string): string => {
if (typeof str !== "string") return "";
return str.charAt(0).toUpperCase() + str.slice(1);
},
toRomanNumerals,
};

View file

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher
// SPDX-FileCopyrightText: 2021 Oliver Rümpelein
// SPDX-FileCopyrightText: 2021 Gesina Schwalbe
// SPDX-FileCopyrightText: 2025 Alexander Minges
//
// SPDX-License-Identifier: MIT
@ -55,6 +56,7 @@ export async function registerHandlebarsPartials() {
"systems/ds4/templates/sheets/shared/components/add-button.hbs",
"systems/ds4/templates/sheets/shared/components/control-button-group.hbs",
"systems/ds4/templates/sheets/shared/components/rollable-image.hbs",
"systems/ds4/templates/partials/waypoint-label.hbs",
];
await loadTemplates(templatePaths);
await foundry.applications.handlebars.loadTemplates(templatePaths);
}

View file

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher
// SPDX-FileCopyrightText: 2021 Oliver Rümpelein
// SPDX-FileCopyrightText: 2021 Gesina Schwalbe
// SPDX-FileCopyrightText: 2025 Alexander Minges
//
// SPDX-License-Identifier: MIT
@ -8,6 +9,7 @@ import { DS4ActiveEffectConfig } from "../apps/active-effect-config";
import { DS4CharacterActorSheet } from "../apps/actor/character-sheet";
import { DS4CreatureActorSheet } from "../apps/actor/creature-sheet";
import { DS4ItemSheet } from "../apps/item-sheet";
import { DS4TokenRuler } from "../apps/ruler/token-ruler";
import { DS4 } from "../config";
import { DS4Check } from "../dice/check";
import { createCheckRoll } from "../dice/check-factory";
@ -51,6 +53,8 @@ async function init() {
CONFIG.ChatMessage.documentClass = DS4ChatMessage;
CONFIG.Token.documentClass = DS4TokenDocument;
CONFIG.Token.rulerClass = DS4TokenRuler;
CONFIG.ActiveEffect.legacyTransferral = false;
CONFIG.Actor.typeLabels = DS4.i18n.actorTypes;
@ -65,16 +69,23 @@ async function init() {
registerSystemSettings();
DocumentSheetConfig.unregisterSheet(Actor, "core", ActorSheet);
DocumentSheetConfig.registerSheet(Actor, "ds4", DS4CharacterActorSheet, {
foundry.applications.apps.DocumentSheetConfig.registerSheet(Actor, "ds4", DS4CharacterActorSheet, {
types: ["character"],
makeDefault: true,
});
DocumentSheetConfig.registerSheet(Actor, "ds4", DS4CreatureActorSheet, { types: ["creature"], makeDefault: true });
DocumentSheetConfig.unregisterSheet(Item, "core", ItemSheet);
DocumentSheetConfig.registerSheet(Item, "ds4", DS4ItemSheet, { makeDefault: true });
DocumentSheetConfig.unregisterSheet(ActiveEffect, "core", ActiveEffectConfig);
DocumentSheetConfig.registerSheet(ActiveEffect, "ds4", DS4ActiveEffectConfig, { makeDefault: true });
foundry.applications.apps.DocumentSheetConfig.registerSheet(Actor, "ds4", DS4CreatureActorSheet, {
types: ["creature"],
makeDefault: true,
});
foundry.applications.apps.DocumentSheetConfig.registerSheet(Item, "ds4", DS4ItemSheet, { makeDefault: true });
foundry.applications.apps.DocumentSheetConfig.unregisterSheet(
ActiveEffect,
"core",
foundry.applications.sheets.ActiveEffectConfig,
);
foundry.applications.apps.DocumentSheetConfig.registerSheet(ActiveEffect, "ds4", DS4ActiveEffectConfig, {
makeDefault: true,
});
preloadFonts();
await registerHandlebarsPartials();

View file

@ -17,10 +17,18 @@ export function registerForRenderHooks() {
* Select the text of input elements in given application when focused via an on focus listener.
*
* @param {Application} app The application in which to activate the listener.
* @param {JQuery} html The {@link JQuery} representing the HTML of the application.
* @param {HTMLElement} element The HTML element representing the HTML of the application.
*/
function selectTargetInputOnFocus(app, html) {
html.find("input").on("focus", (ev) => {
ev.currentTarget.select();
function selectTargetInputOnFocus(app, element) {
// V13: element is always a plain DOM element
if (!element || typeof element.querySelectorAll !== "function") {
return;
}
const inputs = element.querySelectorAll("input");
inputs.forEach((input) => {
input.addEventListener("focus", (ev) => {
ev.currentTarget.select();
});
});
}

View file

@ -30,7 +30,10 @@ export function enforce(value, message) {
* @returns {Canvas}
*/
export function getCanvas() {
enforce(canvas instanceof Canvas && canvas.ready, getGame().i18n.localize("DS4.ErrorCanvasIsNotInitialized"));
enforce(
canvas instanceof foundry.canvas.Canvas && canvas.ready,
getGame().i18n.localize("DS4.ErrorCanvasIsNotInitialized"),
);
return canvas;
}
@ -40,7 +43,7 @@ export function getCanvas() {
* @returns {Game}
*/
export function getGame() {
enforce(game instanceof Game, "Game is not initialized yet.");
enforce(game instanceof foundry.Game, "Game is not initialized yet.");
return game;
}

View file

@ -32,7 +32,7 @@
"readme": "https://git.f3l.de/dungeonslayers/ds4/raw/tag/2.0.5/README.md",
"bugs": "https://git.f3l.de/dungeonslayers/ds4/issues",
"changelog": "https://git.f3l.de/dungeonslayers/ds4/releases/tag/2.0.5",
"version": "2.0.5",
"version": "3.0.0",
"flags": {
"hotReload": {
"extensions": ["css", "hbs", "json"],
@ -40,8 +40,8 @@
}
},
"compatibility": {
"minimum": "12.331",
"verified": "12"
"minimum": "13",
"verified": "13.346"
},
"esmodules": ["ds4.js"],
"styles": ["css/ds4.css"],

View file

@ -4,7 +4,7 @@ SPDX-FileCopyrightText: 2021 Johannes Loher
SPDX-License-Identifier: MIT
--}}
<div class="dice-roll">
<div class="dice-roll" data-action="expandRoll">
{{#if flavor}}
<div class="dice-flavor">{{flavor}}</div>
{{/if}}

View file

@ -0,0 +1,43 @@
{{!--
SPDX-FileCopyrightText: 2025 Alexander Minges
SPDX-License-Identifier: MIT
--}}
{{!--
!-- Waypoint label template with color-coded movement ranges
!-- Based on DS4 movement combat values
--}}
<div class="waypoint-label {{rangeClass}}">
{{#if (eq rangeClass "dash-range")}}
<i class="fas fa-person-running"></i>
{{else if (eq rangeClass "out-of-range")}}
<i class="fas fa-person-rays"></i>
{{else if action.icon}}
<i class="{{action.icon}}"></i>
{{else if action.label}}
{{localize action.label}}
{{/if}}
{{#if cost}}
<span class="distance {{rangeClass}}">{{cost.total}} {{cost.units}}</span>
{{#if cost.delta}}
<span class="delta">({{cost.delta}})</span>
{{/if}}
{{else}}
<span class="distance {{rangeClass}}">{{distance.total}} {{units}}</span>
{{#if distance.delta}}
<span class="delta">({{distance.delta}})</span>
{{/if}}
{{/if}}
{{#if (and elevation (not elevation.hidden))}}
<span class="elevation">
{{elevation.total}} {{units}}
{{#if elevation.delta}}
({{elevation.delta}})
{{/if}}
</span>
{{/if}}
{{#if secret}}
<i class="fas fa-eye-slash"></i>
{{/if}}
</div>

View file

@ -32,8 +32,18 @@ SPDX-License-Identifier: MIT
<div class="form-group stacked">
<label>{{ localize "EFFECT.Description" }}</label>
{{editor descriptionHTML target="description" button=false editable=editable engine="prosemirror"
collaborate=false}}
{{#if editable}}
<prose-mirror
name="description"
button="false"
editable="{{editable}}"
toggled="false"
value="{{data.description}}">
{{{descriptionHTML}}}
</prose-mirror>
{{else}}
{{{descriptionHTML}}}
{{/if}}
</div>
<div class="form-group">

View file

@ -13,38 +13,47 @@ SPDX-License-Identifier: MIT
{{/systems/ds4/templates/sheets/actor/components/actor-header.hbs}}
{{!-- Sheet Tab Navigation --}}
<nav class="ds4-sheet-tab-nav tabs" data-group="primary">
<a class="ds4-sheet-tab-nav__item" data-tab="values">{{localize 'DS4.HeadingValues'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="inventory">{{localize 'DS4.HeadingInventory'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="spells">{{localize 'DS4.HeadingSpells'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="abilities">{{localize 'DS4.HeadingAbilities'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="effects">{{localize 'DS4.HeadingEffects'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="biography">{{localize 'DS4.HeadingBiography'}}</a>
<nav class="tabs" data-group="primary">
{{#each tabs}}
<a class="item {{cssClass}}" data-tab="{{id}}" data-group="{{group}}">
{{#if icon}}<i class="{{icon}}"></i>{{/if}}
{{label}}
</a>
{{/each}}
</nav>
<!-- beautify ignore:start -->
<!-- prettier-ignore-start -->
{{!-- Sheet Body (remove indentation to avoid annoying Handlebars auto-indent) --}}
<section class="ds4-sheet-body">
{{!-- Values Tab --}}
{{> systems/ds4/templates/sheets/actor/tabs/values.hbs}}
{{!-- Sheet Body --}}
<section class="sheet-body">
{{!-- Values Tab --}}
<div class="tab {{#if tabs.values}}{{tabs.values.cssClass}}{{/if}}" data-tab="values" data-group="primary">
{{> systems/ds4/templates/sheets/actor/components/core-values.hbs}}
{{> systems/ds4/templates/sheets/actor/components/combat-values.hbs}}
{{> systems/ds4/templates/sheets/actor/components/checks.hbs}}
</div>
{{!-- Inventory Tab --}}
{{> systems/ds4/templates/sheets/actor/tabs/character-inventory.hbs}}
{{!-- Inventory Tab --}}
<div class="tab {{#if tabs.inventory}}{{tabs.inventory.cssClass}}{{/if}}" data-tab="inventory" data-group="primary">
{{> systems/ds4/templates/sheets/actor/tabs/character-inventory.hbs}}
</div>
{{!-- Spells Tab --}}
{{> systems/ds4/templates/sheets/actor/tabs/spells.hbs}}
{{!-- Spells Tab --}}
<div class="tab {{#if tabs.spells}}{{tabs.spells.cssClass}}{{/if}}" data-tab="spells" data-group="primary">
{{> systems/ds4/templates/sheets/actor/tabs/spells.hbs}}
</div>
{{!-- Abilities Tab --}}
{{> systems/ds4/templates/sheets/actor/tabs/character-abilities.hbs}}
{{!-- Abilities Tab --}}
<div class="tab {{#if tabs.abilities}}{{tabs.abilities.cssClass}}{{/if}}" data-tab="abilities" data-group="primary">
{{> systems/ds4/templates/sheets/actor/tabs/character-abilities.hbs}}
</div>
{{!-- Effects Tab --}}
{{> systems/ds4/templates/sheets/actor/tabs/effects.hbs}}
{{!-- Effects Tab --}}
<div class="tab {{#if tabs.effects}}{{tabs.effects.cssClass}}{{/if}}" data-tab="effects" data-group="primary">
{{> systems/ds4/templates/sheets/actor/tabs/effects.hbs}}
</div>
{{!-- Biography Tab --}}
{{> systems/ds4/templates/sheets/actor/tabs/biography.hbs}}
</section>
<!-- prettier-ignore-end -->
<!-- beautify ignore:end -->
{{!-- Biography Tab --}}
<div class="tab {{#if tabs.biography}}{{tabs.biography.cssClass}}{{/if}}" data-tab="biography" data-group="primary">
{{> systems/ds4/templates/sheets/actor/tabs/biography.hbs}}
</div>
</section>
</form>

View file

@ -11,7 +11,7 @@ SPDX-License-Identifier: MIT
!-- @param @partial-block: Properties to render in the second header row.
--}}
<header class="ds4-actor-header">
<img class="ds4-actor-header__img{{#if editable}} ds4-actor-header__img--editable{{/if}}" src="{{data.img}}" data-edit="img" alt="{{localize 'DS4.ActorImageAltText'}}"
<img class="ds4-actor-header__img{{#if editable}} ds4-actor-header__img--editable{{/if}}" src="{{data.img}}" data-action="editImage" alt="{{localize 'DS4.ActorImageAltText'}}"
title="{{data.name}}" height="100" width="100" />
<div class="ds4-actor-header__data">
<div class="ds4-actor-header__data-row">

View file

@ -5,6 +5,16 @@ SPDX-License-Identifier: MIT
--}}
<div class="ds4-biography">
{{editor data.system.profile.biography target="system.profile.biography" button=true owner=owner
editable=editable engine="prosemirror"}}
{{#if editable}}
<prose-mirror
name="system.profile.biography"
button="true"
editable="{{editable}}"
toggled="false"
value="{{data.system.profile.biography}}">
{{{data.system.profile.biography}}}
</prose-mirror>
{{else}}
{{{data.system.profile.biography}}}
{{/if}}
</div>

View file

@ -12,7 +12,7 @@ SPDX-License-Identifier: MIT
!-- @param check-label: The label for the check
--}}
<button class="ds4-check rollable-check" data-check="{{check-key}}"
<button class="ds4-check" data-action="rollCheck" data-check="{{check-key}}"
title="{{localize 'DS4.CheckTooltip' check=check-label}}">
<span>{{check-label}}</span>
<span>{{check-target-number}}</span>

View file

@ -17,7 +17,7 @@ SPDX-License-Identifier: MIT
<div class="ds4-combat-value">
<div class="ds4-combat-value__value ds4-combat-value__value--{{combat-value-key}}"
title="{{combat-value-title}}: {{combat-value-data.tooltip}}">
{{combat-value-data.total}}
<span class="ds4-combat-value__text">{{combat-value-data.total}}</span>
</div>
<span title="{{combat-value-title}}" class="ds4-combat-value__label">{{combat-value-label}}</span>
<div class="ds4-combat-value__formula">

View file

@ -5,6 +5,16 @@ SPDX-License-Identifier: MIT
--}}
<div class="ds4-description">
{{editor data.system.baseInfo.description target="system.baseInfo.description" button=true owner=owner
editable=editable engine="prosemirror"}}
{{#if editable}}
<prose-mirror
name="system.baseInfo.description"
button="true"
editable="{{editable}}"
toggled="false"
value="{{data.system.baseInfo.description}}">
{{{data.system.baseInfo.description}}}
</prose-mirror>
{{else}}
{{{data.system.baseInfo.description}}}
{{/if}}
</div>

View file

@ -9,11 +9,11 @@ SPDX-License-Identifier: MIT
!-- Render an effect list entry row.
!-- @param effectData: The data of the item.
--}}
<li class="ds4-embedded-document-list__row effect" data-effect-uuid="{{effectData.uuid}}" data-effect-id="{{effectData.id}}">
<li class="ds4-embedded-document-list__row effect draggable" data-effect-uuid="{{effectData.uuid}}" data-effect-id="{{effectData.id}}">
{{!-- enabled --}}
<input class="ds4-embedded-document-list__editable ds4-embedded-document-list__editable--checkbox change-effect"
<input class="ds4-embedded-document-list__editable ds4-embedded-document-list__editable--checkbox"
type="checkbox" {{checked (ne effectData.disabled true)}} data-dtype="Boolean" data-property="disabled"
data-inverted="true" title="{{localize 'DS4.EffectEnabled'}}">
data-inverted="true" data-action="changeEffect" title="{{localize 'DS4.EffectEnabled'}}">
{{!-- active --}}
{{#if effectData.active}}<i class="fas fa-check"></i>{{else}}<i class="fas fa-ban"></i>{{/if}}

View file

@ -15,30 +15,30 @@ SPDX-License-Identifier: MIT
!-- @param hideDescription: A flag to disable the description column.
!-- @param @partial-block: Custom column headers can be passed using the partial block.
--}}
<li class="ds4-embedded-document-list__row item" data-item-uuid="{{item.uuid}}" data-item-id="{{item.id}}">
<li class="ds4-embedded-document-list__row item draggable" data-item-uuid="{{item.uuid}}" data-item-id="{{item.id}}">
{{!-- equipped --}}
{{#if isEquipable}}
<input class="ds4-embedded-document-list__editable ds4-embedded-document-list__editable--checkbox change-item"
<input class="ds4-embedded-document-list__editable ds4-embedded-document-list__editable--checkbox"
type="checkbox" {{checked item.system.equipped}} data-dtype="Boolean" data-property="system.equipped"
title="{{localize 'DS4.ItemEquipped'}}">
data-action="changeItem" title="{{localize 'DS4.ItemEquipped'}}">
{{/if}}
{{!-- image --}}
{{> systems/ds4/templates/sheets/shared/components/rollable-image.hbs rollable=(and item.system.rollable
@root/editable)
src=item.img alt=(localize "DS4.DocumentImageAltText" name=item.name) title=item.name
rollableTitle=(localize "DS4.RollableImageRollableTitle" name=item.name) rollableClass="rollable-item"}}
rollableTitle=(localize "DS4.RollableImageRollableTitle" name=item.name) rollableAction="rollItem"}}
{{!-- amount --}}
{{#if hasQuantity}}
<input class="ds4-embedded-document-list__editable change-item" type="number" min="0" step="1"
<input class="ds4-embedded-document-list__editable" type="number" min="0" step="1"
value="{{item.system.quantity}}" data-dtype="Number" data-property="system.quantity"
title="{{localize 'DS4.Quantity'}}" />
data-action="changeItem" title="{{localize 'DS4.Quantity'}}" />
{{/if}}
{{!-- name --}}
<input class="ds4-embedded-document-list__editable change-item" type="text" value="{{item.name}}"
data-dtype="String" data-property="name" title="{{htmlToPlainText item.system.description}}" />
<input class="ds4-embedded-document-list__editable" type="text" value="{{item.name}}"
data-dtype="String" data-property="name" data-action="changeItem" title="{{htmlToPlainText item.system.description}}" />
{{!-- item type specifics --}}
{{#if @partial-block }}

View file

@ -18,7 +18,7 @@ SPDX-License-Identifier: MIT
<li class="ds4-embedded-document-list__row ds4-embedded-document-list__row--header" data-type={{type}}>
{{!-- equipped --}}
{{#if isEquipable}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.equipped"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.equipped"
title="{{localize 'DS4.SortByItemEquipped'}}">
{{localize 'DS4.ItemEquippedAbbr'}}</div>
{{/if}}
@ -28,12 +28,12 @@ SPDX-License-Identifier: MIT
{{!-- amount --}}
{{#if hasQuantity}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.quantity"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.quantity"
title="{{localize 'DS4.SortByQuantity'}}">#</div>
{{/if}}
{{!-- name --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="name"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="name"
title="{{localize 'DS4.SortByItemName'}}">{{localize 'DS4.ItemName'}}
</div>
@ -44,7 +44,7 @@ SPDX-License-Identifier: MIT
{{!-- description --}}
{{#unless hideDescription}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.description"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.description"
title="{{localize 'DS4.SortByDescription'}}">{{localize
'DS4.Description'}}</div>
{{/unless}}

View file

@ -13,19 +13,19 @@ SPDX-License-Identifier: MIT
{{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true
type='weapon'}}
{{!-- attack type --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.attackType"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.attackType"
title="{{localize 'DS4.SortByAttackType'}}">
{{localize
'DS4.AttackTypeAbbr'}}</div>
{{!-- weapon bonus --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.weaponBonus"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.weaponBonus"
title="{{localize 'DS4.SortByWeaponBonus'}}">
{{localize 'DS4.WeaponBonusAbbr'}}
</div>
{{!-- opponent defense --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.opponentDefense"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.opponentDefense"
title="{{localize 'DS4.SortByOpponentDefense'}}">
{{localize 'DS4.OpponentDefenseAbbr'}}
</div>
@ -70,15 +70,15 @@ documentType='item' type='weapon'}}
{{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true
type="armor"}}
{{!-- armor material type --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.armorMaterialType"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.armorMaterialType"
title="{{localize 'DS4.SortByArmorMaterialType'}}">{{localize 'DS4.ArmorMaterialTypeAbbr'}}</div>
{{!-- armor type --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.armorType"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.armorType"
title="{{localize 'DS4.SortByArmorType'}}">{{localize 'DS4.ArmorTypeAbbr'}}</div>
{{!-- armor value --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.armorValue"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.armorValue"
title="{{localize 'DS4.SortByArmorValue'}}">
{{localize 'DS4.ArmorValueAbbr'}}
</div>
@ -113,7 +113,7 @@ documentType='item' type='armor'}}
{{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true
type='shield'}}
{{!-- armor value --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.armorValue"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.armorValue"
title="{{localize 'DS4.SortByArmorValue'}}">
{{localize 'DS4.ArmorValueAbbr'}}
</div>
@ -137,15 +137,15 @@ documentType='item' type='shield'}}
{{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true
type='equipment'}}
{{!-- storage location --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.storageLocation"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.storageLocation"
title="{{localize 'DS4.SortByStorageLocation'}}">{{localize 'DS4.StorageLocation'}}</div>
{{/systems/ds4/templates/sheets/actor/components/item-list-header.hbs}}
{{#each itemsByType.equipment as |item id|}}
{{#> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs item=item isEquipable=true
hasQuantity=true}}
{{!-- storage location --}}
<input class="ds4-embedded-document-list__editable change-item" type="text" value="{{item.system.storageLocation}}"
data-dtype="String" data-property="system.storageLocation" title="{{localize 'DS4.StorageLocation'}}">
<input class="ds4-embedded-document-list__editable" type="text" value="{{item.system.storageLocation}}"
data-dtype="String" data-property="system.storageLocation" data-action="changeItem" title="{{localize 'DS4.StorageLocation'}}">
{{/systems/ds4/templates/sheets/actor/components/item-list-entry.hbs}}
{{/each}}
</ol>
@ -159,14 +159,14 @@ documentType='item' type='equipment'}}
<ol class="ds4-embedded-document-list ds4-embedded-document-list--loot item-list">
{{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs hasQuantity=true type='loot'}}
{{!-- storage location --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.storageLocation"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.storageLocation"
title="{{localize 'DS4.SortByStorageLocation'}}">{{localize 'DS4.StorageLocation'}}</div>
{{/systems/ds4/templates/sheets/actor/components/item-list-header.hbs}}
{{#each itemsByType.loot as |item id|}}
{{#> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs item=item hasQuantity=true}}
{{!-- storage location --}}
<input class="ds4-embedded-document-list__editable change-item" type="text" value="{{item.system.storageLocation}}"
data-dtype="String" data-property="system.storageLocation" title="{{localize 'DS4.StorageLocation'}}">
<input class="ds4-embedded-document-list__editable" type="text" value="{{item.system.storageLocation}}"
data-dtype="String" data-property="system.storageLocation" data-action="changeItem" title="{{localize 'DS4.StorageLocation'}}">
{{/systems/ds4/templates/sheets/actor/components/item-list-entry.hbs}}
{{/each}}
</ol>

View file

@ -12,35 +12,46 @@ SPDX-License-Identifier: MIT
{{> systems/ds4/templates/sheets/actor/components/creature-properties.hbs}}
{{/systems/ds4/templates/sheets/actor/components/actor-header.hbs}}
{{!-- Sheet Tab Navigation --}}
<nav class="ds4-sheet-tab-nav" data-group="primary">
<a class="ds4-sheet-tab-nav__item" data-tab="values">{{localize 'DS4.HeadingValues'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="inventory">{{localize 'DS4.HeadingInventory'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="spells">{{localize 'DS4.HeadingSpells'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="abilities">{{localize 'DS4.HeadingAbilities'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="effects">{{localize 'DS4.HeadingEffects'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="description">{{localize 'DS4.HeadingDescription'}}</a>
<nav class="tabs" data-group="primary">
{{#each tabs}}
<a class="item {{cssClass}}" data-tab="{{id}}" data-group="{{group}}">
{{#if icon}}<i class="{{icon}}"></i>{{/if}}
{{label}}
</a>
{{/each}}
</nav>
{{!-- Sheet Body --}}
<section class="ds4-sheet-body">
<section class="sheet-body">
{{!-- Values Tab --}}
{{> systems/ds4/templates/sheets/actor/tabs/values.hbs}}
<div class="tab {{#if tabs.values}}{{tabs.values.cssClass}}{{/if}}" data-tab="values" data-group="primary">
{{> systems/ds4/templates/sheets/actor/tabs/values.hbs}}
</div>
{{!-- Inventory Tab --}}
{{> systems/ds4/templates/sheets/actor/tabs/creature-inventory.hbs}}
<div class="tab {{#if tabs.inventory}}{{tabs.inventory.cssClass}}{{/if}}" data-tab="inventory" data-group="primary">
{{> systems/ds4/templates/sheets/actor/tabs/creature-inventory.hbs}}
</div>
{{!-- Spells Tab --}}
{{> systems/ds4/templates/sheets/actor/tabs/spells.hbs}}
<div class="tab {{#if tabs.spells}}{{tabs.spells.cssClass}}{{/if}}" data-tab="spells" data-group="primary">
{{> systems/ds4/templates/sheets/actor/tabs/spells.hbs}}
</div>
{{!-- Abilities Tab --}}
{{> systems/ds4/templates/sheets/actor/tabs/creature-abilities.hbs}}
<div class="tab {{#if tabs.abilities}}{{tabs.abilities.cssClass}}{{/if}}" data-tab="abilities" data-group="primary">
{{> systems/ds4/templates/sheets/actor/tabs/creature-abilities.hbs}}
</div>
{{!-- Effects Tab --}}
{{> systems/ds4/templates/sheets/actor/tabs/effects.hbs}}
<div class="tab {{#if tabs.effects}}{{tabs.effects.cssClass}}{{/if}}" data-tab="effects" data-group="primary">
{{> systems/ds4/templates/sheets/actor/tabs/effects.hbs}}
</div>
{{!-- Description Tab --}}
{{> systems/ds4/templates/sheets/actor/tabs/description.hbs}}
<div class="tab {{#if tabs.description}}{{tabs.description.cssClass}}{{/if}}" data-tab="description" data-group="primary">
{{> systems/ds4/templates/sheets/actor/tabs/description.hbs}}
</div>
</section>
</form>

View file

@ -9,7 +9,6 @@ SPDX-License-Identifier: MIT
{{#> systems/ds4/templates/sheets/actor/components/actor-header.hbs}}
{{/systems/ds4/templates/sheets/actor/components/actor-header.hbs}}
{{!-- Sheet Body --}}
<section class="ds4-sheet-body">
{{#if (eq data.type 'character')}}

View file

@ -4,14 +4,12 @@ SPDX-FileCopyrightText: 2021 Johannes Loher
SPDX-License-Identifier: MIT
--}}
<div class="ds4-sheet-tab tab biography" data-group="primary" data-tab="biography">
<div class="ds4-biography-tab-content">
<!-- beautify ignore:start -->
<!-- prettier-ignore-start -->
{{!-- remove indentation to avoid annoying Handlebars auto-indent --}}
<div class="ds4-biography-tab-content">
<!-- beautify ignore:start -->
<!-- prettier-ignore-start -->
{{!-- remove indentation to avoid annoying Handlebars auto-indent --}}
{{> systems/ds4/templates/sheets/actor/components/profile.hbs}}
{{> systems/ds4/templates/sheets/actor/components/biography.hbs}}
<!-- beautify ignore:end -->
<!-- prettier-ignore-end -->
</div>
<!-- beautify ignore:end -->
<!-- prettier-ignore-end -->
</div>

View file

@ -5,14 +5,14 @@ SPDX-FileCopyrightText: 2021 Gesina Schwalbe
SPDX-License-Identifier: MIT
--}}
<div class="ds4-sheet-tab tab abilities" data-group="primary" data-tab="abilities">
{{!-- TALENT --}}
<h4 class="ds4-embedded-document-list-title">{{localize 'DS4.ItemTypeTalentPlural'}}</h4>
{{#unless (isEmpty itemsByType.talent)}}
<ol class="ds4-embedded-document-list ds4-embedded-document-list--talent item-list">
{{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs type='talent'}}
{{!-- rank --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.rank.total"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.rank.total"
title="{{localize 'DS4.SortByTalentRank'}}">{{localize 'DS4.TalentRank'}}</div>
{{/systems/ds4/templates/sheets/actor/components/item-list-header.hbs}}
{{#each itemsByType.talent as |item id|}}
@ -64,4 +64,3 @@ SPDX-License-Identifier: MIT
{{/unless}}
{{> systems/ds4/templates/sheets/shared/components/add-button.hbs title='DS4.UserInteractionAddItemTitle'
documentType='item' type='alphabet'}}
</div>

View file

@ -5,7 +5,5 @@ SPDX-FileCopyrightText: 2021 Gesina Schwalbe
SPDX-License-Identifier: MIT
--}}
<div class="ds4-sheet-tab tab inventory" data-group="primary" data-tab="inventory">
{{> systems/ds4/templates/sheets/actor/components/currency.hbs}}
{{> systems/ds4/templates/sheets/actor/components/items-overview.hbs}}
</div>
{{> systems/ds4/templates/sheets/actor/components/currency.hbs}}
{{> systems/ds4/templates/sheets/actor/components/items-overview.hbs}}

View file

@ -5,15 +5,13 @@ SPDX-FileCopyrightText: 2021 Gesina Schwalbe
SPDX-License-Identifier: MIT
--}}
<div class="ds4-sheet-tab tab abilities" data-group="primary" data-tab="abilities">
{{#unless (isEmpty itemsByType.specialCreatureAbility)}}
<ol class="ds4-embedded-document-list ds4-embedded-document-list--special-creature-ability item-list">
{{> systems/ds4/templates/sheets/actor/components/item-list-header.hbs type='specialCreatureAbility'}}
{{#each itemsByType.specialCreatureAbility as |item id|}}
{{> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs item=item}}
{{/each}}
</ol>
{{/unless}}
{{> systems/ds4/templates/sheets/shared/components/add-button.hbs title='DS4.UserInteractionAddItemTitle'
documentType='item' type='specialCreatureAbility'}}
</div>
{{#unless (isEmpty itemsByType.specialCreatureAbility)}}
<ol class="ds4-embedded-document-list ds4-embedded-document-list--special-creature-ability item-list">
{{> systems/ds4/templates/sheets/actor/components/item-list-header.hbs type='specialCreatureAbility'}}
{{#each itemsByType.specialCreatureAbility as |item id|}}
{{> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs item=item}}
{{/each}}
</ol>
{{/unless}}
{{> systems/ds4/templates/sheets/shared/components/add-button.hbs title='DS4.UserInteractionAddItemTitle'
documentType='item' type='specialCreatureAbility'}}

View file

@ -5,6 +5,4 @@ SPDX-FileCopyrightText: 2021 Gesina Schwalbe
SPDX-License-Identifier: MIT
--}}
<div class="ds4-sheet-tab tab inventory" data-group="primary" data-tab="inventory">
{{> systems/ds4/templates/sheets/actor/components/items-overview.hbs}}
</div>
{{> systems/ds4/templates/sheets/actor/components/items-overview.hbs}}

View file

@ -4,6 +4,4 @@ SPDX-FileCopyrightText: 2021 Johannes Loher
SPDX-License-Identifier: MIT
--}}
<div class="ds4-sheet-tab tab description" data-group="primary" data-tab="description">
{{> systems/ds4/templates/sheets/actor/components/description.hbs}}
</div>
{{> systems/ds4/templates/sheets/actor/components/description.hbs}}

View file

@ -5,15 +5,13 @@ SPDX-FileCopyrightText: 2021 Gesina Schwalbe
SPDX-License-Identifier: MIT
--}}
<div class="ds4-sheet-tab tab effects" data-group="primary" data-tab="effects">
{{#unless (isEmpty enrichedEffects)}}
<ol class="ds4-embedded-document-list ds4-embedded-document-list--effect effect-list">
{{> systems/ds4/templates/sheets/actor/components/effect-list-header.hbs}}
{{#each enrichedEffects as |effectData id| }}
{{> systems/ds4/templates/sheets/actor/components/effect-list-entry.hbs effectData=effectData}}
{{/each}}
</ol>
{{/unless}}
{{> systems/ds4/templates/sheets/shared/components/add-button.hbs title='DS4.UserInteractionAddEffectTitle'
documentType='effect'}}
</div>
{{#unless (isEmpty enrichedEffects)}}
<ol class="ds4-embedded-document-list ds4-embedded-document-list--effect effect-list">
{{> systems/ds4/templates/sheets/actor/components/effect-list-header.hbs}}
{{#each enrichedEffects as |effectData id| }}
{{> systems/ds4/templates/sheets/actor/components/effect-list-entry.hbs effectData=effectData}}
{{/each}}
</ol>
{{/unless}}
{{> systems/ds4/templates/sheets/shared/components/add-button.hbs title='DS4.UserInteractionAddEffectTitle'
documentType='effect'}}

View file

@ -40,21 +40,19 @@ titleKey=titleKey}}
titleKey=titleKey}}
{{/inline}}
{{!-- ======================================================================== --}}
<div class="ds4-sheet-tab tab spells" data-group="primary" data-tab="spells">
{{#unless (isEmpty itemsByType.spell)}}
<ol class="ds4-embedded-document-list ds4-embedded-document-list--spell item-list">
{{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hideDescription=true
type='spell'}}
{{!-- spell type --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.spellType"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.spellType"
title="{{localize 'DS4.SortBySpellType'}}">{{localize 'DS4.SpellTypeAbbr'}}</div>
{{!-- spell modifier --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.spellModifier.complex"
<div class="ds4-embedded-document-list__clickable" data-action="sortItems" data-data-path="system.spellModifier.complex"
data-data-path2="system.spellModifier.numerical" title="{{localize 'DS4.SortBySpellModifier'}}">{{localize
'DS4.SpellModifierAbbr'}}</div>
@ -81,6 +79,7 @@ titleKey=titleKey}}
'')}}{{item.system.spellModifier.numerical}}{{else}}{{item.system.spellModifier.complex}}{{/if}}
</div>
{{!-- max. distance --}}
{{> distanceUnit titleKey='DS4.SpellDistance' unitDatum=item.system.maxDistance
config=@root/config}}
@ -98,4 +97,3 @@ titleKey=titleKey}}
{{/unless}}
{{> systems/ds4/templates/sheets/shared/components/add-button.hbs title='DS4.UserInteractionAddItemTitle'
documentType='item' type='spell'}}
</div>

View file

@ -4,8 +4,6 @@ SPDX-FileCopyrightText: 2021 Johannes Loher
SPDX-License-Identifier: MIT
--}}
<div class="ds4-sheet-tab tab values" data-group="primary" data-tab="values">
{{> systems/ds4/templates/sheets/actor/components/core-values.hbs}}
{{> systems/ds4/templates/sheets/actor/components/combat-values.hbs}}
{{> systems/ds4/templates/sheets/actor/components/checks.hbs}}
</div>
{{> systems/ds4/templates/sheets/actor/components/core-values.hbs}}
{{> systems/ds4/templates/sheets/actor/components/combat-values.hbs}}
{{> systems/ds4/templates/sheets/actor/components/checks.hbs}}

View file

@ -9,17 +9,25 @@ SPDX-License-Identifier: MIT
{{> systems/ds4/templates/sheets/item/components/item-header.hbs}}
{{!-- Sheet Tab Navigation --}}
<nav class="ds4-sheet-tab-nav tabs" data-group="primary">
<a class="ds4-sheet-tab-nav__item" data-tab="description">{{localize 'DS4.HeadingDescription'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="effects">{{localize 'DS4.HeadingEffects'}}</a>
<nav class="tabs" data-group="primary">
{{#each tabs}}
<a class="item {{cssClass}}" data-tab="{{id}}" data-group="{{group}}">
{{#if icon}}<i class="{{icon}}"></i>{{/if}}
{{label}}
</a>
{{/each}}
</nav>
{{!-- Sheet Body --}}
<section class="ds4-sheet-body">
<section class="sheet-body">
{{!-- Description Tab --}}
{{> systems/ds4/templates/sheets/item/tabs/description.hbs}}
<div class="tab {{tabs.description.cssClass}}" data-tab="description" data-group="primary">
{{> systems/ds4/templates/sheets/item/tabs/description.hbs}}
</div>
{{!-- Effects Tab --}}
{{> systems/ds4/templates/sheets/item/tabs/effects.hbs}}
<div class="tab {{tabs.effects.cssClass}}" data-tab="effects" data-group="primary">
{{> systems/ds4/templates/sheets/item/tabs/effects.hbs}}
</div>
</section>
</form>

View file

@ -9,28 +9,35 @@ SPDX-License-Identifier: MIT
{{> systems/ds4/templates/sheets/item/components/item-header.hbs}}
{{!-- Sheet Tab Navigation --}}
<nav class="ds4-sheet-tab-nav tabs" data-group="primary">
<a class="ds4-sheet-tab-nav__item" data-tab="description">{{localize 'DS4.HeadingDescription'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="properties">{{localize 'DS4.HeadingProperties'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="effects">{{localize 'DS4.HeadingEffects'}}</a>
<nav class="tabs" data-group="primary">
{{#each tabs}}
<a class="item {{cssClass}}" data-tab="{{id}}" data-group="{{group}}">
{{#if icon}}<i class="{{icon}}"></i>{{/if}}
{{label}}
</a>
{{/each}}
</nav>
{{!-- Sheet Body --}}
<section class="ds4-sheet-body">
<section class="sheet-body">
{{!-- Description Tab --}}
{{> systems/ds4/templates/sheets/item/tabs/description.hbs}}
<div class="tab {{#if tabs.description}}{{tabs.description.cssClass}}{{/if}}" data-tab="description" data-group="primary">
{{> systems/ds4/templates/sheets/item/tabs/description.hbs}}
</div>
{{!-- Properties Tab --}}
{{#> systems/ds4/templates/sheets/item/tabs/properties.hbs}}
{{> systems/ds4/templates/sheets/item/components/properties/armor.hbs}}
{{> systems/ds4/templates/sheets/item/components/properties/protective.hbs}}
{{#if isOwned}}
{{> systems/ds4/templates/sheets/item/components/properties/equipable.hbs}}
{{/if}}
{{> systems/ds4/templates/sheets/item/components/properties/physical.hbs}}
{{/systems/ds4/templates/sheets/item/tabs/properties.hbs}}
<div class="tab {{#if tabs.properties}}{{tabs.properties.cssClass}}{{/if}}" data-tab="properties" data-group="primary">
{{> systems/ds4/templates/sheets/item/components/properties/armor.hbs}}
{{> systems/ds4/templates/sheets/item/components/properties/protective.hbs}}
{{#if isOwned}}
{{> systems/ds4/templates/sheets/item/components/properties/equipable.hbs}}
{{/if}}
{{> systems/ds4/templates/sheets/item/components/properties/physical.hbs}}
</div>
{{!-- Effects Tab --}}
{{> systems/ds4/templates/sheets/item/tabs/effects.hbs}}
<div class="tab {{#if tabs.effects}}{{tabs.effects.cssClass}}{{/if}}" data-tab="effects" data-group="primary">
{{> systems/ds4/templates/sheets/item/tabs/effects.hbs}}
</div>
</section>
</form>

View file

@ -5,7 +5,7 @@ SPDX-License-Identifier: MIT
--}}
<header class="ds4-item-header">
<img class="ds4-item-header__img" src="{{data.img}}" data-edit="img" alt="{{localize 'DS4.ItemImageAltText'}}"
<img class="ds4-item-header__img" src="{{data.img}}" data-action="editImage" alt="{{localize 'DS4.ItemImageAltText'}}"
title="{{data.name}}" />
<div class="ds4-item-header__data">
<h2 class="ds4-item-header__type">{{lookup config.i18n.itemTypes item.type}}</h2>

View file

@ -88,10 +88,8 @@ SPDX-License-Identifier: MIT
<div class="form-group">
<label for="system.allowsDefense-{{data._id}}" title="{{localize 'DS4.SpellAllowsDefenseDescription'}}">{{localize
"DS4.SpellAllowsDefense"}}</label>
<div class="form-fields">
<input id="system.allowsDefense-{{data._id}}" data-dtype="Boolean" type="checkbox" name="system.allowsDefense"
{{checked data.system.allowsDefense}} />
</div>
<input id="system.allowsDefense-{{data._id}}" data-dtype="Boolean" type="checkbox" name="system.allowsDefense"
{{checked data.system.allowsDefense}} />
</div>
<div class="form-group slim">
<label title="{{localize 'DS4.SpellMinimumLevelDescription'}}">{{localize "DS4.SpellMinimumLevel"}}</label>

View file

@ -9,26 +9,33 @@ SPDX-License-Identifier: MIT
{{> systems/ds4/templates/sheets/item/components/item-header.hbs}}
{{!-- Sheet Tab Navigation --}}
<nav class="ds4-sheet-tab-nav tabs" data-group="primary">
<a class="ds4-sheet-tab-nav__item" data-tab="description">{{localize 'DS4.HeadingDescription'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="properties">{{localize 'DS4.HeadingProperties'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="effects">{{localize 'DS4.HeadingEffects'}}</a>
<nav class="tabs" data-group="primary">
{{#each tabs}}
<a class="item {{cssClass}}" data-tab="{{id}}" data-group="{{group}}">
{{#if icon}}<i class="{{icon}}"></i>{{/if}}
{{label}}
</a>
{{/each}}
</nav>
{{!-- Sheet Body --}}
<section class="ds4-sheet-body">
<section class="sheet-body">
{{!-- Description Tab --}}
{{> systems/ds4/templates/sheets/item/tabs/description.hbs}}
<div class="tab {{#if tabs.description}}{{tabs.description.cssClass}}{{/if}}" data-tab="description" data-group="primary">
{{> systems/ds4/templates/sheets/item/tabs/description.hbs}}
</div>
{{!-- Properties Tab --}}
{{#> systems/ds4/templates/sheets/item/tabs/properties.hbs}}
{{#if isOwned}}
{{> systems/ds4/templates/sheets/item/components/properties/equipable.hbs}}
{{/if}}
{{> systems/ds4/templates/sheets/item/components/properties/physical.hbs}}
{{/systems/ds4/templates/sheets/item/tabs/properties.hbs}}
<div class="tab {{#if tabs.properties}}{{tabs.properties.cssClass}}{{/if}}" data-tab="properties" data-group="primary">
{{#if isOwned}}
{{> systems/ds4/templates/sheets/item/components/properties/equipable.hbs}}
{{/if}}
{{> systems/ds4/templates/sheets/item/components/properties/physical.hbs}}
</div>
{{!-- Effects Tab --}}
{{> systems/ds4/templates/sheets/item/tabs/effects.hbs}}
<div class="tab {{#if tabs.effects}}{{tabs.effects.cssClass}}{{/if}}" data-tab="effects" data-group="primary">
{{> systems/ds4/templates/sheets/item/tabs/effects.hbs}}
</div>
</section>
</form>

View file

@ -9,17 +9,25 @@ SPDX-License-Identifier: MIT
{{> systems/ds4/templates/sheets/item/components/item-header.hbs}}
{{!-- Sheet Tab Navigation --}}
<nav class="ds4-sheet-tab-nav tabs" data-group="primary">
<a class="ds4-sheet-tab-nav__item" data-tab="description">{{localize 'DS4.HeadingDescription'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="effects">{{localize 'DS4.HeadingEffects'}}</a>
<nav class="tabs" data-group="primary">
{{#each tabs}}
<a class="item {{cssClass}}" data-tab="{{id}}" data-group="{{group}}">
{{#if icon}}<i class="{{icon}}"></i>{{/if}}
{{label}}
</a>
{{/each}}
</nav>
{{!-- Sheet Body --}}
<section class="ds4-sheet-body">
<section class="sheet-body">
{{!-- Description Tab --}}
{{> systems/ds4/templates/sheets/item/tabs/description.hbs}}
<div class="tab {{#if tabs.description}}{{tabs.description.cssClass}}{{/if}}" data-tab="description" data-group="primary">
{{> systems/ds4/templates/sheets/item/tabs/description.hbs}}
</div>
{{!-- Effects Tab --}}
{{> systems/ds4/templates/sheets/item/tabs/effects.hbs}}
<div class="tab {{#if tabs.effects}}{{tabs.effects.cssClass}}{{/if}}" data-tab="effects" data-group="primary">
{{> systems/ds4/templates/sheets/item/tabs/effects.hbs}}
</div>
</section>
</form>

View file

@ -9,23 +9,30 @@ SPDX-License-Identifier: MIT
{{> systems/ds4/templates/sheets/item/components/item-header.hbs}}
{{!-- Sheet Tab Navigation --}}
<nav class="ds4-sheet-tab-nav tabs" data-group="primary">
<a class="ds4-sheet-tab-nav__item" data-tab="description">{{localize 'DS4.HeadingDescription'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="properties">{{localize 'DS4.HeadingProperties'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="effects">{{localize 'DS4.HeadingEffects'}}</a>
<nav class="tabs" data-group="primary">
{{#each tabs}}
<a class="item {{cssClass}}" data-tab="{{id}}" data-group="{{group}}">
{{#if icon}}<i class="{{icon}}"></i>{{/if}}
{{label}}
</a>
{{/each}}
</nav>
{{!-- Sheet Body --}}
<section class="ds4-sheet-body">
<section class="sheet-body">
{{!-- Description Tab --}}
{{> systems/ds4/templates/sheets/item/tabs/description.hbs}}
<div class="tab {{#if tabs.description}}{{tabs.description.cssClass}}{{/if}}" data-tab="description" data-group="primary">
{{> systems/ds4/templates/sheets/item/tabs/description.hbs}}
</div>
{{!-- Properties Tab --}}
{{#> systems/ds4/templates/sheets/item/tabs/properties.hbs}}
{{> systems/ds4/templates/sheets/item/components/properties/physical.hbs}}
{{/systems/ds4/templates/sheets/item/tabs/properties.hbs}}
<div class="tab {{#if tabs.properties}}{{tabs.properties.cssClass}}{{/if}}" data-tab="properties" data-group="primary">
{{> systems/ds4/templates/sheets/item/components/properties/physical.hbs}}
</div>
{{!-- Effects Tab --}}
{{> systems/ds4/templates/sheets/item/tabs/effects.hbs}}
<div class="tab {{#if tabs.effects}}{{tabs.effects.cssClass}}{{/if}}" data-tab="effects" data-group="primary">
{{> systems/ds4/templates/sheets/item/tabs/effects.hbs}}
</div>
</section>
</form>

View file

@ -9,17 +9,25 @@ SPDX-License-Identifier: MIT
{{> systems/ds4/templates/sheets/item/components/item-header.hbs}}
{{!-- Sheet Tab Navigation --}}
<nav class="ds4-sheet-tab-nav tabs" data-group="primary">
<a class="ds4-sheet-tab-nav__item" data-tab="description">{{localize 'DS4.HeadingDescription'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="effects">{{localize 'DS4.HeadingEffects'}}</a>
<nav class="tabs" data-group="primary">
{{#each tabs}}
<a class="item {{cssClass}}" data-tab="{{id}}" data-group="{{group}}">
{{#if icon}}<i class="{{icon}}"></i>{{/if}}
{{label}}
</a>
{{/each}}
</nav>
{{!-- Sheet Body --}}
<section class="ds4-sheet-body">
<section class="sheet-body">
{{!-- Description Tab --}}
{{> systems/ds4/templates/sheets/item/tabs/description.hbs}}
<div class="tab {{#if tabs.description}}{{tabs.description.cssClass}}{{/if}}" data-tab="description" data-group="primary">
{{> systems/ds4/templates/sheets/item/tabs/description.hbs}}
</div>
{{!-- Effects Tab --}}
{{> systems/ds4/templates/sheets/item/tabs/effects.hbs}}
<div class="tab {{#if tabs.effects}}{{tabs.effects.cssClass}}{{/if}}" data-tab="effects" data-group="primary">
{{> systems/ds4/templates/sheets/item/tabs/effects.hbs}}
</div>
</section>
</form>

View file

@ -9,27 +9,34 @@ SPDX-License-Identifier: MIT
{{> systems/ds4/templates/sheets/item/components/item-header.hbs}}
{{!-- Sheet Tab Navigation --}}
<nav class="ds4-sheet-tab-nav tabs" data-group="primary">
<a class="ds4-sheet-tab-nav__item" data-tab="description">{{localize 'DS4.HeadingDescription'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="properties">{{localize 'DS4.HeadingProperties'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="effects">{{localize 'DS4.HeadingEffects'}}</a>
<nav class="tabs" data-group="primary">
{{#each tabs}}
<a class="item {{cssClass}}" data-tab="{{id}}" data-group="{{group}}">
{{#if icon}}<i class="{{icon}}"></i>{{/if}}
{{label}}
</a>
{{/each}}
</nav>
{{!-- Sheet Body --}}
<section class="ds4-sheet-body">
<section class="sheet-body">
{{!-- Description Tab --}}
{{> systems/ds4/templates/sheets/item/tabs/description.hbs}}
<div class="tab {{#if tabs.description}}{{tabs.description.cssClass}}{{/if}}" data-tab="description" data-group="primary">
{{> systems/ds4/templates/sheets/item/tabs/description.hbs}}
</div>
{{!-- Properties Tab --}}
{{#> systems/ds4/templates/sheets/item/tabs/properties.hbs}}
{{> systems/ds4/templates/sheets/item/components/properties/protective.hbs}}
{{#if isOwned}}
{{> systems/ds4/templates/sheets/item/components/properties/equipable.hbs}}
{{/if}}
{{> systems/ds4/templates/sheets/item/components/properties/physical.hbs}}
{{/systems/ds4/templates/sheets/item/tabs/properties.hbs}}
<div class="tab {{#if tabs.properties}}{{tabs.properties.cssClass}}{{/if}}" data-tab="properties" data-group="primary">
{{> systems/ds4/templates/sheets/item/components/properties/protective.hbs}}
{{#if isOwned}}
{{> systems/ds4/templates/sheets/item/components/properties/equipable.hbs}}
{{/if}}
{{> systems/ds4/templates/sheets/item/components/properties/physical.hbs}}
</div>
{{!-- Effects Tab --}}
{{> systems/ds4/templates/sheets/item/tabs/effects.hbs}}
<div class="tab {{#if tabs.effects}}{{tabs.effects.cssClass}}{{/if}}" data-tab="effects" data-group="primary">
{{> systems/ds4/templates/sheets/item/tabs/effects.hbs}}
</div>
</section>
</form>

View file

@ -9,23 +9,30 @@ SPDX-License-Identifier: MIT
{{> systems/ds4/templates/sheets/item/components/item-header.hbs}}
{{!-- Sheet Tab Navigation --}}
<nav class="ds4-sheet-tab-nav tabs" data-group="primary">
<a class="ds4-sheet-tab-nav__item" data-tab="description">{{localize 'DS4.HeadingDescription'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="properties">{{localize 'DS4.HeadingProperties'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="effects">{{localize 'DS4.HeadingEffects'}}</a>
<nav class="tabs" data-group="primary">
{{#each tabs}}
<a class="item {{cssClass}}" data-tab="{{id}}" data-group="{{group}}">
{{#if icon}}<i class="{{icon}}"></i>{{/if}}
{{label}}
</a>
{{/each}}
</nav>
{{!-- Sheet Body --}}
<section class="ds4-sheet-body">
<section class="sheet-body">
{{!-- Description Tab --}}
{{> systems/ds4/templates/sheets/item/tabs/description.hbs}}
<div class="tab {{#if tabs.description}}{{tabs.description.cssClass}}{{/if}}" data-tab="description" data-group="primary">
{{> systems/ds4/templates/sheets/item/tabs/description.hbs}}
</div>
{{!-- Properties Tab --}}
{{#> systems/ds4/templates/sheets/item/tabs/properties.hbs}}
{{> systems/ds4/templates/sheets/item/components/properties/special-creature-ability.hbs}}
{{/systems/ds4/templates/sheets/item/tabs/properties.hbs}}
<div class="tab {{#if tabs.properties}}{{tabs.properties.cssClass}}{{/if}}" data-tab="properties" data-group="primary">
{{> systems/ds4/templates/sheets/item/components/properties/special-creature-ability.hbs}}
</div>
{{!-- Effects Tab --}}
{{> systems/ds4/templates/sheets/item/tabs/effects.hbs}}
<div class="tab {{#if tabs.effects}}{{tabs.effects.cssClass}}{{/if}}" data-tab="effects" data-group="primary">
{{> systems/ds4/templates/sheets/item/tabs/effects.hbs}}
</div>
</section>
</form>

View file

@ -9,26 +9,33 @@ SPDX-License-Identifier: MIT
{{> systems/ds4/templates/sheets/item/components/item-header.hbs}}
{{!-- Sheet Tab Navigation --}}
<nav class="ds4-sheet-tab-nav tabs" data-group="primary">
<a class="ds4-sheet-tab-nav__item" data-tab="description">{{localize 'DS4.HeadingDescription'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="properties">{{localize 'DS4.HeadingProperties'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="effects">{{localize 'DS4.HeadingEffects'}}</a>
<nav class="tabs" data-group="primary">
{{#each tabs}}
<a class="item {{cssClass}}" data-tab="{{id}}" data-group="{{group}}">
{{#if icon}}<i class="{{icon}}"></i>{{/if}}
{{label}}
</a>
{{/each}}
</nav>
{{!-- Sheet Body --}}
<section class="ds4-sheet-body">
<section class="sheet-body">
{{!-- Description Tab --}}
{{> systems/ds4/templates/sheets/item/tabs/description.hbs}}
<div class="tab {{tabs.description.cssClass}}" data-tab="description" data-group="primary">
{{> systems/ds4/templates/sheets/item/tabs/description.hbs}}
</div>
{{!-- Properties Tab --}}
{{#> systems/ds4/templates/sheets/item/tabs/properties.hbs}}
{{> systems/ds4/templates/sheets/item/components/properties/spell.hbs}}
{{#if isOwned}}
{{> systems/ds4/templates/sheets/item/components/properties/equipable.hbs}}
{{/if}}
{{/systems/ds4/templates/sheets/item/tabs/properties.hbs}}
<div class="tab {{tabs.properties.cssClass}}" data-tab="properties" data-group="primary">
{{> systems/ds4/templates/sheets/item/components/properties/spell.hbs}}
{{#if isOwned}}
{{> systems/ds4/templates/sheets/item/components/properties/equipable.hbs}}
{{/if}}
</div>
{{!-- Effects Tab --}}
{{> systems/ds4/templates/sheets/item/tabs/effects.hbs}}
<div class="tab {{tabs.effects.cssClass}}" data-tab="effects" data-group="primary">
{{> systems/ds4/templates/sheets/item/tabs/effects.hbs}}
</div>
</section>
</form>

View file

@ -4,7 +4,15 @@ SPDX-FileCopyrightText: 2021 Johannes Loher
SPDX-License-Identifier: MIT
--}}
<div class="ds4-sheet-tab tab description" data-group="primary" data-tab="description">
{{editor data.system.description target="system.description" button=true owner=owner
editable=editable engine="prosemirror"}}
</div>
{{#if editable}}
<prose-mirror
name="system.description"
button="true"
editable="{{editable}}"
toggled="false"
value="{{data.system.description}}">
{{{enrichedDescription}}}
</prose-mirror>
{{else}}
{{{enrichedDescription}}}
{{/if}}

View file

@ -4,15 +4,13 @@ SPDX-FileCopyrightText: 2021 Johannes Loher
SPDX-License-Identifier: MIT
--}}
<div class="ds4-sheet-tab tab effects" data-group="primary" data-tab="effects">
{{#unless (isEmpty data.effects)}}
<ol class="ds4-embedded-document-list ds4-embedded-document-list--item-effect effect-list">
{{> systems/ds4/templates/sheets/item/components/effect-list-header.hbs}}
{{#each data.effects as |effectData id| }}
{{> systems/ds4/templates/sheets/item/components/effect-list-entry.hbs effectData=effectData}}
{{/each}}
</ol>
{{/unless}}
{{> systems/ds4/templates/sheets/shared/components/add-button.hbs title='DS4.UserInteractionAddEffectTitle'
documentType='effect'}}
</div>
{{#unless (isEmpty enrichedEffects)}}
<ol class="ds4-embedded-document-list ds4-embedded-document-list--item-effect effect-list">
{{> systems/ds4/templates/sheets/item/components/effect-list-header.hbs}}
{{#each enrichedEffects as |effectData id| }}
{{> systems/ds4/templates/sheets/item/components/effect-list-entry.hbs effectData=effectData}}
{{/each}}
</ol>
{{/unless}}
{{> systems/ds4/templates/sheets/shared/components/add-button.hbs title='DS4.UserInteractionAddEffectTitle'
documentType='effect'}}

View file

@ -4,6 +4,4 @@ SPDX-FileCopyrightText: 2021 Johannes Loher
SPDX-License-Identifier: MIT
--}}
<div class="ds4-sheet-tab tab properties" data-group="primary" data-tab="properties">
{{> @partial-block}}
</div>
{{> @partial-block}}

View file

@ -9,23 +9,30 @@ SPDX-License-Identifier: MIT
{{> systems/ds4/templates/sheets/item/components/item-header.hbs}}
{{!-- Sheet Tab Navigation --}}
<nav class="ds4-sheet-tab-nav tabs" data-group="primary">
<a class="ds4-sheet-tab-nav__item" data-tab="description">{{localize 'DS4.HeadingDescription'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="properties">{{localize 'DS4.HeadingProperties'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="effects">{{localize 'DS4.HeadingEffects'}}</a>
<nav class="tabs" data-group="primary">
{{#each tabs}}
<a class="item {{cssClass}}" data-tab="{{id}}" data-group="{{group}}">
{{#if icon}}<i class="{{icon}}"></i>{{/if}}
{{label}}
</a>
{{/each}}
</nav>
{{!-- Sheet Body --}}
<section class="ds4-sheet-body">
<section class="sheet-body">
{{!-- Description Tab --}}
{{> systems/ds4/templates/sheets/item/tabs/description.hbs}}
<div class="tab {{#if tabs.description}}{{tabs.description.cssClass}}{{/if}}" data-tab="description" data-group="primary">
{{> systems/ds4/templates/sheets/item/tabs/description.hbs}}
</div>
{{!-- Properties Tab --}}
{{#> systems/ds4/templates/sheets/item/tabs/properties.hbs}}
{{> systems/ds4/templates/sheets/item/components/properties/talent.hbs}}
{{/systems/ds4/templates/sheets/item/tabs/properties.hbs}}
<div class="tab {{#if tabs.properties}}{{tabs.properties.cssClass}}{{/if}}" data-tab="properties" data-group="primary">
{{> systems/ds4/templates/sheets/item/components/properties/talent.hbs}}
</div>
{{!-- Effects Tab --}}
{{> systems/ds4/templates/sheets/item/tabs/effects.hbs}}
<div class="tab {{#if tabs.effects}}{{tabs.effects.cssClass}}{{/if}}" data-tab="effects" data-group="primary">
{{> systems/ds4/templates/sheets/item/tabs/effects.hbs}}
</div>
</section>
</form>

View file

@ -9,27 +9,34 @@ SPDX-License-Identifier: MIT
{{> systems/ds4/templates/sheets/item/components/item-header.hbs}}
{{!-- Sheet Tab Navigation --}}
<nav class="ds4-sheet-tab-nav tabs" data-group="primary">
<a class="ds4-sheet-tab-nav__item" data-tab="description">{{localize 'DS4.HeadingDescription'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="properties">{{localize 'DS4.HeadingProperties'}}</a>
<a class="ds4-sheet-tab-nav__item" data-tab="effects">{{localize 'DS4.HeadingEffects'}}</a>
<nav class="tabs" data-group="primary">
{{#each tabs}}
<a class="item {{cssClass}}" data-tab="{{id}}" data-group="{{group}}">
{{#if icon}}<i class="{{icon}}"></i>{{/if}}
{{label}}
</a>
{{/each}}
</nav>
{{!-- Sheet Body --}}
<section class="ds4-sheet-body">
<section class="sheet-body">
{{!-- Description Tab --}}
{{> systems/ds4/templates/sheets/item/tabs/description.hbs}}
<div class="tab {{#if tabs.description}}{{tabs.description.cssClass}}{{/if}}" data-tab="description" data-group="primary">
{{> systems/ds4/templates/sheets/item/tabs/description.hbs}}
</div>
{{!-- Properties Tab --}}
{{#> systems/ds4/templates/sheets/item/tabs/properties.hbs}}
{{> systems/ds4/templates/sheets/item/components/properties/weapon.hbs}}
{{#if isOwned}}
{{> systems/ds4/templates/sheets/item/components/properties/equipable.hbs}}
{{/if}}
{{> systems/ds4/templates/sheets/item/components/properties/physical.hbs}}
{{/systems/ds4/templates/sheets/item/tabs/properties.hbs}}
<div class="tab {{#if tabs.properties}}{{tabs.properties.cssClass}}{{/if}}" data-tab="properties" data-group="primary">
{{> systems/ds4/templates/sheets/item/components/properties/weapon.hbs}}
{{#if isOwned}}
{{> systems/ds4/templates/sheets/item/components/properties/equipable.hbs}}
{{/if}}
{{> systems/ds4/templates/sheets/item/components/properties/physical.hbs}}
</div>
{{!-- Effects Tab --}}
{{> systems/ds4/templates/sheets/item/tabs/effects.hbs}}
<div class="tab {{#if tabs.effects}}{{tabs.effects.cssClass}}{{/if}}" data-tab="effects" data-group="primary">
{{> systems/ds4/templates/sheets/item/tabs/effects.hbs}}
</div>
</section>
</form>

View file

@ -13,7 +13,7 @@ SPDX-License-Identifier: MIT
}}
{{#if @root/editable}}
<div class="ds4-add-button">
<a class="control-{{documentType}}" title="{{localize title}}" data-action="create" {{#if type}}data-type="{{type}}"
<a class="ds4-add-button__link" title="{{localize title}}" data-action="{{concat 'create' (capitalize documentType)}}" {{#if type}}data-type="{{type}}"
{{/if}}>
<i class="fas fa-plus"></i>
{{localize "DS4.UserInteractionAdd"}}

View file

@ -14,9 +14,9 @@ SPDX-License-Identifier: MIT
--}}
<div class="ds4-control-button-group">
{{#if @root/editable}}
<a class="ds4-control-button-group__button control-{{documentType}}" data-action="edit"
<a class="ds4-control-button-group__button" data-action="{{concat 'edit' (capitalize documentType)}}" data-document-type="{{documentType}}"
title="{{localize editTitle}}"><i class="fas fa-edit"></i></a>
<a class="ds4-control-button-group__button control-{{documentType}}" data-action="delete"
<a class="ds4-control-button-group__button" data-action="{{concat 'delete' (capitalize documentType)}}" data-document-type="{{documentType}}"
title="{{localize deleteTitle}}"><i class="fas fa-trash"></i></a>
{{/if}}
</div>

View file

@ -7,13 +7,14 @@ SPDX-License-Identifier: MIT
{{!--
!-- Render an image that has a dice overlay image.
!-- @param rollable: A flag indicating whether or not the image is actually rollable.
!-- @param rollableClass: The CSS class(es) to add if the image is rollable.
!-- @param rollableAction: The action to trigger when the image is clicked (e.g. "rollItem").
!-- @param title: The title for the rollable image if it is not actually rollable.
!-- @param rollableTitle: The title for the rollable image if it is rollable.
!-- @param src: The path to the image.
!-- @param alt: An alternate text for the image.
--}}
<div class="ds4-rollable-image{{#if rollable}} ds4-rollable-image--rollable {{rollableClass}}{{/if}}"
<div class="ds4-rollable-image{{#if rollable}} ds4-rollable-image--rollable{{/if}}"
{{#if rollable}}data-action="{{rollableAction}}"{{/if}}
title="{{#if rollable}}{{rollableTitle}}{{else}}{{title}}{{/if}}">
{{#if src}}
<img class="ds4-rollable-image__image" alt="{{alt}}" src="{{src}}" />