Implements inventory system, wip

This commit is contained in:
2026-05-22 11:03:17 +02:00
parent 4ff46865c2
commit dd3fe0e38e
15 changed files with 431 additions and 40 deletions
+184 -8
View File
@@ -54,6 +54,13 @@ i.prismrpg {
font-family: var(--font-primary); font-family: var(--font-primary);
font-size: calc(var(--font-size-standard) * 1); font-size: calc(var(--font-size-standard) * 1);
background-image: var(--background-image-base); background-image: var(--background-image-base);
background-size: 100% 100%;
background-repeat: no-repeat;
}
.application.dialog.prismrpg .window-content {
background-image: var(--background-image-base);
background-size: 100% 100%;
background-repeat: no-repeat;
} }
.application.dialog.prismrpg button:hover { .application.dialog.prismrpg button:hover {
background: var(--color-dark-6); background: var(--color-dark-6);
@@ -737,6 +744,76 @@ i.prismrpg {
font-size: 11px; font-size: 11px;
padding: 4px; padding: 4px;
} }
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container[data-container-id] {
border: 1px dashed transparent;
transition: border-color 0.15s, background 0.15s;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container[data-container-id].drag-over {
border-color: rgba(100, 150, 255, 0.7);
background: rgba(100, 150, 255, 0.12);
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-items {
margin: 2px 0 6px 28px;
display: flex;
flex-direction: column;
gap: 2px;
border-left: 2px solid rgba(0, 0, 0, 0.15);
padding-left: 8px;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item {
display: flex;
align-items: center;
gap: 6px;
padding: 2px 4px;
border-radius: 3px;
background: rgba(0, 0, 0, 0.06);
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item:hover {
background: rgba(0, 0, 0, 0.12);
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item .item-img {
width: 20px;
height: 20px;
cursor: pointer;
flex-shrink: 0;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item .inv-name {
flex: 1;
font-size: 11px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item .inv-enc {
font-size: 10px;
color: #555;
min-width: 24px;
text-align: center;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item .inv-container-type-badge {
font-size: 9px;
text-transform: uppercase;
letter-spacing: 0.05em;
color: rgba(0, 0, 0, 0.45);
background: rgba(0, 0, 0, 0.07);
border-radius: 3px;
padding: 1px 4px;
flex-shrink: 0;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item .controls {
display: flex;
gap: 4px;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item .controls a {
font-size: 11px;
cursor: pointer;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-empty {
margin: 2px 0 4px 36px;
font-size: 10px;
font-style: italic;
color: rgba(0, 0, 0, 0.35);
}
.prismrpg .tab.character-equipment .main-div .pack-burden-fieldset .pack-burden-display { .prismrpg .tab.character-equipment .main-div .pack-burden-fieldset .pack-burden-display {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -3775,6 +3852,105 @@ i.prismrpg {
.prismrpg .character-path-content input[type="checkbox"]:checked::after { .prismrpg .character-path-content input[type="checkbox"]:checked::after {
color: rgba(0, 0, 0, 0.1); color: rgba(0, 0, 0, 0.1);
} }
.prismrpg .container-content {
font-family: var(--font-primary);
font-size: calc(var(--font-size-standard) * 1);
color: var(--color-dark-1);
background-image: var(--background-image-base);
background-repeat: no-repeat;
background-size: 100% 100%;
overflow: auto;
}
.prismrpg .container-content nav.tabs [data-tab] {
color: #636060;
}
.prismrpg .container-content nav.tabs [data-tab].active {
color: #252424;
}
.prismrpg .container-content input:disabled,
.prismrpg .container-content select:disabled {
background-color: rgba(0, 0, 0, 0.2);
border-color: transparent;
color: var(--color-dark-3);
}
.prismrpg .container-content input,
.prismrpg .container-content select {
height: 1.5rem;
background-color: rgba(0, 0, 0, 0.1);
border-color: var(--color-dark-6);
color: var(--color-dark-2);
}
.prismrpg .container-content input[name="name"] {
height: 2.5rem;
margin-right: 4px;
font-family: var(--font-secondary);
font-size: calc(var(--font-size-standard) * 1.2);
font-weight: bold;
border: none;
}
.prismrpg .container-content fieldset {
margin-bottom: 4px;
border-radius: 4px;
}
.prismrpg .container-content .form-fields input,
.prismrpg .container-content .form-fields select {
text-align: center;
font-size: calc(var(--font-size-standard) * 1);
}
.prismrpg .container-content .form-fields select {
font-family: var(--font-secondary);
font-size: calc(var(--font-size-standard) * 1);
}
.prismrpg .container-content legend {
font-family: var(--font-secondary);
font-size: calc(var(--font-size-standard) * 1.2);
font-weight: bold;
letter-spacing: 1px;
}
.prismrpg .container-content .form-fields {
padding-top: 4px;
}
.prismrpg .container-content .form-group {
display: flex;
flex: 1;
flex-direction: row;
}
.prismrpg .container-content .form-group label {
align-content: center;
min-width: 10rem;
max-width: 10rem;
}
.prismrpg .container-content .form-group select,
.prismrpg .container-content .form-group input {
text-align: left;
min-width: 12rem;
max-width: 12rem;
}
.prismrpg .container-content .form-group input[type="checkbox"] {
min-width: 1.2rem;
max-width: 1.2rem;
margin-right: 0.5rem;
}
.prismrpg .container-content label {
font-family: var(--font-secondary);
font-size: calc(var(--font-size-standard) * 1);
flex: 50%;
}
.prismrpg .container-content .align-top {
align-self: flex-start;
padding: 0.1rem;
margin-right: 0.2rem;
}
.prismrpg .container-content .shift-right {
margin-left: 2rem;
}
.prismrpg .container-content .header {
display: flex;
}
.prismrpg .container-content .header img {
width: 50px;
height: 50px;
}
.prismrpg .container-content .item-img { .prismrpg .container-content .item-img {
width: 64px; width: 64px;
height: 64px; height: 64px;
@@ -5147,15 +5323,15 @@ i.prismrpg {
.prismrpg-roll-dialog-modern .checkbox-group .checkbox-label input[type="checkbox"]:checked ~ .checkbox-text i { .prismrpg-roll-dialog-modern .checkbox-group .checkbox-label input[type="checkbox"]:checked ~ .checkbox-text i {
color: #d4af37; color: #d4af37;
} }
.application.dialog.prismrpg .window-content { .application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .window-content {
background: linear-gradient(135deg, #f5f5f5 0%, #e0e0e0 100%); background: linear-gradient(135deg, #f5f5f5 0%, #e0e0e0 100%);
padding: 8px; padding: 8px;
} }
.application.dialog.prismrpg .dialog-buttons { .application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .dialog-buttons {
padding: 6px 8px; padding: 6px 8px;
gap: 6px; gap: 6px;
} }
.application.dialog.prismrpg .dialog-buttons button { .application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .dialog-buttons button {
background: linear-gradient(135deg, #4a4a4a 0%, #6a6a6a 100%); background: linear-gradient(135deg, #4a4a4a 0%, #6a6a6a 100%);
border: 1px solid #3a3a3a; border: 1px solid #3a3a3a;
color: white; color: white;
@@ -5164,19 +5340,19 @@ i.prismrpg {
border-radius: 4px; border-radius: 4px;
transition: all 0.2s ease; transition: all 0.2s ease;
} }
.application.dialog.prismrpg .dialog-buttons button:hover { .application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .dialog-buttons button:hover {
background: linear-gradient(135deg, #5a5a5a 0%, #7a7a7a 100%); background: linear-gradient(135deg, #5a5a5a 0%, #7a7a7a 100%);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
transform: translateY(-1px); transform: translateY(-1px);
} }
.application.dialog.prismrpg .dialog-buttons button.default, .application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .dialog-buttons button.default,
.application.dialog.prismrpg .dialog-buttons button[data-button="roll"] { .application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .dialog-buttons button[data-button="roll"] {
background: linear-gradient(135deg, #d4af37 0%, #f4cf67 100%); background: linear-gradient(135deg, #d4af37 0%, #f4cf67 100%);
border-color: #b49030; border-color: #b49030;
color: #2a2a2a; color: #2a2a2a;
} }
.application.dialog.prismrpg .dialog-buttons button.default:hover, .application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .dialog-buttons button.default:hover,
.application.dialog.prismrpg .dialog-buttons button[data-button="roll"]:hover { .application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .dialog-buttons button[data-button="roll"]:hover {
background: linear-gradient(135deg, #e4bf47 0%, #ffdf77 100%); background: linear-gradient(135deg, #e4bf47 0%, #ffdf77 100%);
} }
#token-hud .hp-loss-wrap { #token-hud .hp-loss-wrap {
+8 -3
View File
@@ -940,12 +940,16 @@
"addContainer": "Add container", "addContainer": "Add container",
"addRacialAbility": "Add racial ability", "addRacialAbility": "Add racial ability",
"addAbility": "Add ability", "addAbility": "Add ability",
"excessBurden": "Equipped burden exceeds max — excess reduces Movement Rating" "excessBurden": "Equipped burden exceeds max — excess reduces Movement Rating",
"assignToContainer": "Assign to container",
"removeFromContainer": "Remove from container",
"packBurden": "Pack Burden"
}, },
"RollSavingThrow": "Roll Saving Throw", "RollSavingThrow": "Roll Saving Throw",
"Dialog": { "Dialog": {
"useConsumable": "Use Consumable", "useConsumable": "Use Consumable",
"useConsumableContent": "Use one charge of <strong>{name}</strong>? ({uses} remaining)" "useConsumableContent": "Use one charge of <strong>{name}</strong>? ({uses} remaining)",
"assignToContainer": "Assign to Container"
}, },
"Message": { "Message": {
"selectCoreSkill": "You must select a Core Skill for your character. Each character chooses one Core Skill at creation.", "selectCoreSkill": "You must select a Core Skill for your character. Each character chooses one Core Skill at creation.",
@@ -957,7 +961,8 @@
"noWeapons": "No weapons", "noWeapons": "No weapons",
"noArmor": "No armor or shields", "noArmor": "No armor or shields",
"noKits": "No kits", "noKits": "No kits",
"noEquipment": "No equipment" "noEquipment": "No equipment",
"noStoredItems": "Nothing stored"
}, },
"Miracle": { "Miracle": {
"FIELDS": { "FIELDS": {
+103 -16
View File
@@ -32,6 +32,8 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet {
useConsumable: PrismRPGCharacterSheet.#onUseConsumable, useConsumable: PrismRPGCharacterSheet.#onUseConsumable,
toggleContainerEquipped: PrismRPGCharacterSheet.#onToggleContainerEquipped, toggleContainerEquipped: PrismRPGCharacterSheet.#onToggleContainerEquipped,
toggleEquipped: PrismRPGCharacterSheet.#onToggleEquipped, toggleEquipped: PrismRPGCharacterSheet.#onToggleEquipped,
assignToContainer: PrismRPGCharacterSheet.#onAssignToContainer,
removeFromContainer: PrismRPGCharacterSheet.#onRemoveFromContainer,
}, },
} }
@@ -162,25 +164,45 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet {
break break
case "equipment": case "equipment":
context.tab = context.tabs.equipment context.tab = context.tabs.equipment
context.weapons = doc.itemTypes.weapon // All items that can be stored in containers
context.armors = [...doc.itemTypes.armor, ...doc.itemTypes.shield] const allStorable = [
context.consumables = doc.itemTypes.consumable
context.kits = doc.itemTypes.equipment.filter(i => i.system.isKit)
context.equipmentItems = doc.itemTypes.equipment.filter(i => !i.system.isKit)
context.loots = doc.itemTypes.loot
context.containers = doc.itemTypes.container
context.packBurdenMax = doc.itemTypes.container
.filter(c => c.system.equipped)
.reduce((sum, c) => sum + (c.system.packBurden ?? 0), 0)
context.packBurdenUsed = [
...doc.itemTypes.equipment,
...doc.itemTypes.consumable,
...doc.itemTypes.loot,
...doc.itemTypes.container,
...doc.itemTypes.weapon, ...doc.itemTypes.weapon,
...doc.itemTypes.armor, ...doc.itemTypes.armor,
...doc.itemTypes.shield, ...doc.itemTypes.shield,
].reduce((sum, i) => sum + (i.system.encLoad ?? 0), 0) ...doc.itemTypes.equipment,
...doc.itemTypes.consumable,
...doc.itemTypes.loot,
]
// Build a map: containerId → items[]
const containerGroups = {}
for (const container of doc.itemTypes.container) {
containerGroups[container.id] = { container, items: [] }
}
for (const item of allStorable) {
const cid = item.system.containerId
if (cid && containerGroups[cid]) {
containerGroups[cid].items.push(item)
}
}
context.containerGroups = Object.values(containerGroups)
// Items are "uncontained" if they have no containerId, or if their container was deleted
const isUncontained = i => !i.system.containerId || !containerGroups[i.system.containerId]
context.weapons = doc.itemTypes.weapon.filter(isUncontained)
context.armors = [...doc.itemTypes.armor, ...doc.itemTypes.shield].filter(isUncontained)
context.consumables = doc.itemTypes.consumable.filter(isUncontained)
context.kits = doc.itemTypes.equipment.filter(i => i.system.isKit && isUncontained(i))
context.equipmentItems = doc.itemTypes.equipment.filter(i => !i.system.isKit && isUncontained(i))
context.loots = doc.itemTypes.loot.filter(isUncontained)
context.containers = doc.itemTypes.container
context.packBurdenMax = doc.itemTypes.container
.filter(c => c.system.equipped)
.reduce((sum, c) => sum + (c.system.packBurden ?? 0), 0)
// Pack burden = items stored in an existing container
context.packBurdenUsed = allStorable
.filter(i => i.system.containerId && containerGroups[i.system.containerId])
.reduce((sum, i) => sum + (i.system.encLoad ?? 0), 0)
break break
case "biography": case "biography":
context.tab = context.tabs.biography context.tab = context.tabs.biography
@@ -205,6 +227,18 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet {
// Handle different data types // Handle different data types
if (data.type === "Item") { if (data.type === "Item") {
const item = await fromUuid(data.uuid) const item = await fromUuid(data.uuid)
// Check if dropped onto a container row
const containerEl = event.target.closest("[data-container-id]")
if (containerEl && item?.parent === this.document) {
const containerId = containerEl.dataset.containerId
// Don't store containers inside containers
if (item.type !== "container") {
await item.update({ "system.containerId": containerId })
return
}
}
return this._onDropItem(item) return this._onDropItem(item)
} }
} }
@@ -331,6 +365,48 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet {
await item.update({ "system.equipped": !item.system.equipped }) await item.update({ "system.equipped": !item.system.equipped })
} }
static async #onAssignToContainer(event, target) {
const itemElement = target.closest("[data-item-id]")
if (!itemElement) return
const item = this.document.items.get(itemElement.dataset.itemId)
if (!item || item.type === "container") return
const containers = this.document.itemTypes.container
if (!containers.length) {
ui.notifications.warn(game.i18n.localize("PRISMRPG.Message.noContainers"))
return
}
const options = containers.map(c => {
const escapedName = foundry.utils.escapeHTML(c.name)
return `<option value="${c.id}">${escapedName}</option>`
}).join("")
const content = `<div class="form-group">
<label>${game.i18n.localize("PRISMRPG.Label.container")}</label>
<div class="form-fields">
<select name="containerId">${options}</select>
</div>
</div>`
const containerId = await foundry.applications.api.DialogV2.prompt({
window: { title: game.i18n.localize("PRISMRPG.Dialog.assignToContainer") },
classes: ["prismrpg"],
content,
ok: {
callback: (event, button) => button.form.elements.containerId.value,
},
})
if (containerId) await item.update({ "system.containerId": containerId })
}
static async #onRemoveFromContainer(event, target) {
const itemElement = target.closest("[data-item-id]")
if (!itemElement) return
const item = this.document.items.get(itemElement.dataset.itemId)
if (!item) return
await item.update({ "system.containerId": "" })
}
static async #onPostItemToChat(event, target) { static async #onPostItemToChat(event, target) {
console.log("PRISM RPG | PostItemToChat action triggered", { event: event, target: target }) console.log("PRISM RPG | PostItemToChat action triggered", { event: event, target: target })
@@ -495,6 +571,17 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet {
this.actor.update({ "system.hp.wounds": tab }); this.actor.update({ "system.hp.wounds": tab });
}) })
} }
// Container drag-over highlight
this.element.querySelectorAll("[data-container-id]").forEach(el => {
el.addEventListener("dragover", (e) => {
e.preventDefault()
el.classList.add("drag-over")
})
el.addEventListener("dragleave", () => el.classList.remove("drag-over"))
el.addEventListener("drop", () => el.classList.remove("drag-over"))
})
super._onRender(); super._onRender();
} }
+1
View File
@@ -9,6 +9,7 @@ export const defaultItemImg = {
race: "systems/fvtt-prism-rpg/assets/icons/icon_race.webp", race: "systems/fvtt-prism-rpg/assets/icons/icon_race.webp",
class: "systems/fvtt-prism-rpg/assets/icons/icon_class.webp", class: "systems/fvtt-prism-rpg/assets/icons/icon_class.webp",
"character-path": "systems/fvtt-prism-rpg/assets/icons/icon_character_path.webp", "character-path": "systems/fvtt-prism-rpg/assets/icons/icon_character_path.webp",
container: "icons/containers/bags/pack-leather-brown.webp",
} }
export default class PrismRPGItem extends Item { export default class PrismRPGItem extends Item {
+1
View File
@@ -25,6 +25,7 @@ export default class PrismRPGArmor extends foundry.abstract.TypeDataModel {
schema.cost = new fields.NumberField({ required: true, initial: 0, min: 0 }) schema.cost = new fields.NumberField({ required: true, initial: 0, min: 0 })
schema.money = new fields.StringField({ required: true, initial: "coppercoin", choices: SYSTEM.MONEY }) schema.money = new fields.StringField({ required: true, initial: "coppercoin", choices: SYSTEM.MONEY })
schema.containerId = new fields.StringField({ required: false, initial: "", nullable: false })
return schema return schema
} }
+1
View File
@@ -10,6 +10,7 @@ export default class PrismRPGConsumable extends foundry.abstract.TypeDataModel {
schema.encLoad = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }) schema.encLoad = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
schema.cost = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }) schema.cost = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
schema.notes = new fields.HTMLField({ required: true }) schema.notes = new fields.HTMLField({ required: true })
schema.containerId = new fields.StringField({ required: false, initial: "", nullable: false })
return schema return schema
} }
+1
View File
@@ -13,6 +13,7 @@ export default class PrismRPGEquipment extends foundry.abstract.TypeDataModel {
schema.cost = new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 }) schema.cost = new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 })
schema.money = new fields.StringField({ required: true, initial: "coppercoin", choices: SYSTEM.MONEY }) schema.money = new fields.StringField({ required: true, initial: "coppercoin", choices: SYSTEM.MONEY })
schema.equipped = new fields.BooleanField({ required: true, initial: false }) schema.equipped = new fields.BooleanField({ required: true, initial: false })
schema.containerId = new fields.StringField({ required: false, initial: "", nullable: false })
// Kit properties // Kit properties
schema.isKit = new fields.BooleanField({ schema.isKit = new fields.BooleanField({
+1
View File
@@ -8,6 +8,7 @@ export default class PrismRPGLoot extends foundry.abstract.TypeDataModel {
schema.encLoad = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }) schema.encLoad = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
schema.cost = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }) schema.cost = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
schema.notes = new fields.HTMLField({ required: true }) schema.notes = new fields.HTMLField({ required: true })
schema.containerId = new fields.StringField({ required: false, initial: "", nullable: false })
return schema return schema
} }
+1
View File
@@ -63,6 +63,7 @@ export default class PrismRPGShield extends foundry.abstract.TypeDataModel {
schema.cost = new fields.NumberField({ required: true, initial: 0, min: 0 }) schema.cost = new fields.NumberField({ required: true, initial: 0, min: 0 })
schema.money = new fields.StringField({ required: true, initial: "coppercoin", choices: SYSTEM.MONEY }) schema.money = new fields.StringField({ required: true, initial: "coppercoin", choices: SYSTEM.MONEY })
schema.equipped = new fields.BooleanField({ required: true, initial: false }) schema.equipped = new fields.BooleanField({ required: true, initial: false })
schema.containerId = new fields.StringField({ required: false, initial: "", nullable: false })
return schema return schema
} }
+1
View File
@@ -127,6 +127,7 @@ export default class PrismRPGWeapon extends foundry.abstract.TypeDataModel {
schema.money = new fields.StringField({ required: true, initial: "coppercoin", choices: SYSTEM.MONEY }) schema.money = new fields.StringField({ required: true, initial: "coppercoin", choices: SYSTEM.MONEY })
schema.equipped = new fields.BooleanField({ required: true, initial: false }) schema.equipped = new fields.BooleanField({ required: true, initial: false })
schema.isImplement = new fields.BooleanField({ required: true, initial: false }) schema.isImplement = new fields.BooleanField({ required: true, initial: false })
schema.containerId = new fields.StringField({ required: false, initial: "", nullable: false })
return schema return schema
} }
+71
View File
@@ -668,6 +668,77 @@
font-size: 11px; font-size: 11px;
padding: 4px; padding: 4px;
} }
// Container drag-drop highlight
.inv-container[data-container-id] {
border: 1px dashed transparent;
transition: border-color 0.15s, background 0.15s;
&.drag-over {
border-color: rgba(100, 150, 255, 0.7);
background: rgba(100, 150, 255, 0.12);
}
}
// Items nested inside a container
.inv-container-items {
margin: 2px 0 6px 28px;
display: flex;
flex-direction: column;
gap: 2px;
border-left: 2px solid rgba(0,0,0,0.15);
padding-left: 8px;
}
.inv-container-item {
display: flex;
align-items: center;
gap: 6px;
padding: 2px 4px;
border-radius: 3px;
background: rgba(0,0,0,0.06);
&:hover { background: rgba(0,0,0,0.12); }
.item-img {
width: 20px;
height: 20px;
cursor: pointer;
flex-shrink: 0;
}
.inv-name {
flex: 1;
font-size: 11px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.inv-enc {
font-size: 10px;
color: #555;
min-width: 24px;
text-align: center;
}
.inv-container-type-badge {
font-size: 9px;
text-transform: uppercase;
letter-spacing: 0.05em;
color: rgba(0,0,0,0.45);
background: rgba(0,0,0,0.07);
border-radius: 3px;
padding: 1px 4px;
flex-shrink: 0;
}
.controls {
display: flex;
gap: 4px;
a { font-size: 11px; cursor: pointer; }
}
}
.inv-container-empty {
margin: 2px 0 4px 36px;
font-size: 10px;
font-style: italic;
color: rgba(0,0,0,0.35);
}
} }
.pack-burden-fieldset { .pack-burden-fieldset {
+11
View File
@@ -1,4 +1,15 @@
.container-content { .container-content {
.sheet-common();
.item-sheet-common();
.header {
display: flex;
img {
width: 50px;
height: 50px;
}
}
.item-img { .item-img {
width: 64px; width: 64px;
height: 64px; height: 64px;
+9
View File
@@ -53,6 +53,15 @@ i.prismrpg {
font-family: var(--font-primary); font-family: var(--font-primary);
font-size: calc(var(--font-size-standard) * 1); font-size: calc(var(--font-size-standard) * 1);
background-image: var(--background-image-base); background-image: var(--background-image-base);
background-size: 100% 100%;
background-repeat: no-repeat;
.window-content {
background-image: var(--background-image-base);
background-size: 100% 100%;
background-repeat: no-repeat;
}
button:hover { button:hover {
background: var(--color-dark-6); background: var(--color-dark-6);
} }
+2 -2
View File
@@ -263,8 +263,8 @@
} }
} }
// Dialog application styling // Dialog application styling — only apply grey gradient when roll dialog content is present
.application.dialog.prismrpg { .application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) {
.window-content { .window-content {
background: linear-gradient(135deg, #f5f5f5 0%, #e0e0e0 100%); background: linear-gradient(135deg, #f5f5f5 0%, #e0e0e0 100%);
padding: 8px; padding: 8px;
+32 -7
View File
@@ -35,6 +35,7 @@
<div class="inv-name">{{item.name}}</div> <div class="inv-name">{{item.name}}</div>
<div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{item.system.encLoad}}</div> <div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{item.system.encLoad}}</div>
<div class="controls"> <div class="controls">
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.assignToContainer'}}" data-action="assignToContainer" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-bag-shopping"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.toggleEquipped'}}" data-action="toggleEquipped" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"> <a data-tooltip="{{localize 'PRISMRPG.Tooltip.toggleEquipped'}}" data-action="toggleEquipped" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
{{#if item.system.equipped}}<i class="fas fa-shield-check equipped-icon"></i>{{else}}<i class="far fa-circle unequipped-icon"></i>{{/if}} {{#if item.system.equipped}}<i class="fas fa-shield-check equipped-icon"></i>{{else}}<i class="far fa-circle unequipped-icon"></i>{{/if}}
</a> </a>
@@ -61,6 +62,7 @@
<div class="inv-name">{{item.name}}</div> <div class="inv-name">{{item.name}}</div>
<div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{item.system.encLoad}}</div> <div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{item.system.encLoad}}</div>
<div class="controls"> <div class="controls">
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.assignToContainer'}}" data-action="assignToContainer" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-bag-shopping"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.toggleEquipped'}}" data-action="toggleEquipped" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"> <a data-tooltip="{{localize 'PRISMRPG.Tooltip.toggleEquipped'}}" data-action="toggleEquipped" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
{{#if item.system.equipped}}<i class="fas fa-shield-check equipped-icon"></i>{{else}}<i class="far fa-circle unequipped-icon"></i>{{/if}} {{#if item.system.equipped}}<i class="fas fa-shield-check equipped-icon"></i>{{else}}<i class="far fa-circle unequipped-icon"></i>{{/if}}
</a> </a>
@@ -87,6 +89,7 @@
<div class="inv-uses" data-tooltip="{{localize 'PRISMRPG.Tooltip.uses'}}">{{item.system.uses}}/{{item.system.usesMax}}</div> <div class="inv-uses" data-tooltip="{{localize 'PRISMRPG.Tooltip.uses'}}">{{item.system.uses}}/{{item.system.usesMax}}</div>
<div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{item.system.encLoad}}</div> <div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{item.system.encLoad}}</div>
<div class="controls"> <div class="controls">
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.assignToContainer'}}" data-action="assignToContainer" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-bag-shopping"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.useConsumable'}}" data-action="useConsumable" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" {{#unless item.system.uses}}aria-disabled="true" class="disabled"{{/unless}}><i class="fas fa-flask"></i></a> <a data-tooltip="{{localize 'PRISMRPG.Tooltip.useConsumable'}}" data-action="useConsumable" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" {{#unless item.system.uses}}aria-disabled="true" class="disabled"{{/unless}}><i class="fas fa-flask"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Edit'}}" data-action="edit" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a> <a data-tooltip="{{localize 'PRISMRPG.Edit'}}" data-action="edit" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Delete'}}" data-action="delete" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a> <a data-tooltip="{{localize 'PRISMRPG.Delete'}}" data-action="delete" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
@@ -110,6 +113,7 @@
<div class="inv-name">{{item.name}}</div> <div class="inv-name">{{item.name}}</div>
<div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{item.system.encLoad}}</div> <div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{item.system.encLoad}}</div>
<div class="controls"> <div class="controls">
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.assignToContainer'}}" data-action="assignToContainer" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-bag-shopping"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.toggleEquipped'}}" data-action="toggleEquipped" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"> <a data-tooltip="{{localize 'PRISMRPG.Tooltip.toggleEquipped'}}" data-action="toggleEquipped" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
{{#if item.system.equipped}}<i class="fas fa-shield-check equipped-icon"></i>{{else}}<i class="far fa-circle unequipped-icon"></i>{{/if}} {{#if item.system.equipped}}<i class="fas fa-shield-check equipped-icon"></i>{{else}}<i class="far fa-circle unequipped-icon"></i>{{/if}}
</a> </a>
@@ -135,6 +139,7 @@
<div class="inv-name" data-tooltip="{{{item.system.description}}}">{{item.name}}</div> <div class="inv-name" data-tooltip="{{{item.system.description}}}">{{item.name}}</div>
<div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{item.system.encLoad}}</div> <div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{item.system.encLoad}}</div>
<div class="controls"> <div class="controls">
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.assignToContainer'}}" data-action="assignToContainer" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-bag-shopping"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.toggleEquipped'}}" data-action="toggleEquipped" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"> <a data-tooltip="{{localize 'PRISMRPG.Tooltip.toggleEquipped'}}" data-action="toggleEquipped" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
{{#if item.system.equipped}}<i class="fas fa-shield-check equipped-icon"></i>{{else}}<i class="far fa-circle unequipped-icon"></i>{{/if}} {{#if item.system.equipped}}<i class="fas fa-shield-check equipped-icon"></i>{{else}}<i class="far fa-circle unequipped-icon"></i>{{/if}}
</a> </a>
@@ -160,6 +165,7 @@
<div class="inv-name">{{item.name}}</div> <div class="inv-name">{{item.name}}</div>
<div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{item.system.encLoad}}</div> <div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{item.system.encLoad}}</div>
<div class="controls"> <div class="controls">
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.assignToContainer'}}" data-action="assignToContainer" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-bag-shopping"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Edit'}}" data-action="edit" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a> <a data-tooltip="{{localize 'PRISMRPG.Edit'}}" data-action="edit" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Delete'}}" data-action="delete" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a> <a data-tooltip="{{localize 'PRISMRPG.Delete'}}" data-action="delete" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div> </div>
@@ -176,22 +182,41 @@
<a data-action="createEquipment" data-item-type="container" data-tooltip="{{localize 'PRISMRPG.Tooltip.addContainer'}}"><i class="fas fa-plus"></i></a> <a data-action="createEquipment" data-item-type="container" data-tooltip="{{localize 'PRISMRPG.Tooltip.addContainer'}}"><i class="fas fa-plus"></i></a>
</legend> </legend>
<div class="inv-items"> <div class="inv-items">
{{#each containers as |item|}} {{#each containerGroups as |group|}}
<div class="inv-item inv-container" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"> <div class="inv-item inv-container" data-item-id="{{group.container.id}}" data-item-uuid="{{group.container.uuid}}" data-container-id="{{group.container.id}}">
<img class="item-img" src="{{group.container.img}}" data-tooltip="{{group.container.name}}" data-action="postItemToChat" />
<div class="inv-name">{{group.container.name}}</div>
<div class="inv-capacity" data-tooltip="{{localize 'PRISMRPG.Tooltip.packBurden'}}">{{group.container.system.packBurden}}</div>
<div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{group.container.system.encLoad}}</div>
<div class="controls">
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.toggleEquipped'}}" data-action="toggleContainerEquipped" data-item-id="{{group.container.id}}" data-item-uuid="{{group.container.uuid}}">
{{#if group.container.system.equipped}}<i class="fas fa-backpack"></i>{{else}}<i class="fas fa-box"></i>{{/if}}
</a>
<a data-tooltip="{{localize 'PRISMRPG.Edit'}}" data-action="edit" data-item-id="{{group.container.id}}" data-item-uuid="{{group.container.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Delete'}}" data-action="delete" data-item-id="{{group.container.id}}" data-item-uuid="{{group.container.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{#if group.items.length}}
<div class="inv-container-items">
{{#each group.items as |item|}}
<div class="inv-item inv-container-item" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
<span class="inv-container-type-badge">{{item.type}}</span>
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" data-action="postItemToChat" /> <img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" data-action="postItemToChat" />
<div class="inv-name">{{item.name}}</div> <div class="inv-name">{{item.name}}</div>
<div class="inv-capacity" data-tooltip="{{localize 'PRISMRPG.Tooltip.packBurden'}}">{{item.system.packBurden}}</div>
<div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{item.system.encLoad}}</div> <div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{item.system.encLoad}}</div>
<div class="controls"> <div class="controls">
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.toggleEquipped'}}" data-action="toggleContainerEquipped" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"> <a data-tooltip="{{localize 'PRISMRPG.Tooltip.removeFromContainer'}}" data-action="removeFromContainer" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-arrow-up-from-bracket"></i></a>
{{#if item.system.equipped}}<i class="fas fa-backpack"></i>{{else}}<i class="fas fa-box"></i>{{/if}}
</a>
<a data-tooltip="{{localize 'PRISMRPG.Edit'}}" data-action="edit" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a> <a data-tooltip="{{localize 'PRISMRPG.Edit'}}" data-action="edit" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Delete'}}" data-action="delete" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a> <a data-tooltip="{{localize 'PRISMRPG.Delete'}}" data-action="delete" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div> </div>
</div> </div>
{{/each}} {{/each}}
{{#unless containers.length}}<p class="inv-empty">{{localize "PRISMRPG.Message.noContainers"}}</p>{{/unless}} </div>
{{else}}
<div class="inv-container-empty">{{localize "PRISMRPG.Message.noStoredItems"}}</div>
{{/if}}
{{/each}}
{{#unless containerGroups.length}}<p class="inv-empty">{{localize "PRISMRPG.Message.noContainers"}}</p>{{/unless}}
</div> </div>
</fieldset> </fieldset>