mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-18 07:59:03 +01:00
Item Browser v0.5
This commit is contained in:
parent
8cfa88b1e3
commit
845d72e20c
16 changed files with 880 additions and 30 deletions
|
|
@ -5,6 +5,7 @@ import DhCharacterlevelUp from '../../levelup/characterLevelup.mjs';
|
||||||
import DhCharacterCreation from '../../characterCreation/characterCreation.mjs';
|
import DhCharacterCreation from '../../characterCreation/characterCreation.mjs';
|
||||||
import FilterMenu from '../../ux/filter-menu.mjs';
|
import FilterMenu from '../../ux/filter-menu.mjs';
|
||||||
import { getDocFromElement, getDocFromElementSync } from '../../../helpers/utils.mjs';
|
import { getDocFromElement, getDocFromElementSync } from '../../../helpers/utils.mjs';
|
||||||
|
import { ItemBrowser } from '../../ui/itemBrowser.mjs';
|
||||||
|
|
||||||
/**@typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction */
|
/**@typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction */
|
||||||
|
|
||||||
|
|
@ -25,7 +26,8 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
||||||
toggleEquipItem: CharacterSheet.#toggleEquipItem,
|
toggleEquipItem: CharacterSheet.#toggleEquipItem,
|
||||||
toggleResourceDice: CharacterSheet.#toggleResourceDice,
|
toggleResourceDice: CharacterSheet.#toggleResourceDice,
|
||||||
handleResourceDice: CharacterSheet.#handleResourceDice,
|
handleResourceDice: CharacterSheet.#handleResourceDice,
|
||||||
useDowntime: this.useDowntime
|
useDowntime: this.useDowntime,
|
||||||
|
tempBrowser: CharacterSheet.#tempBrowser,
|
||||||
},
|
},
|
||||||
window: {
|
window: {
|
||||||
resizable: true
|
resizable: true
|
||||||
|
|
@ -707,6 +709,13 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Temp
|
||||||
|
*/
|
||||||
|
static async #tempBrowser(_, target) {
|
||||||
|
new ItemBrowser().render({ force: true });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the roll values of resource dice.
|
* Handle the roll values of resource dice.
|
||||||
* @type {ApplicationClickAction}
|
* @type {ApplicationClickAction}
|
||||||
|
|
|
||||||
|
|
@ -9,49 +9,350 @@ const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||||
* @mixes HandlebarsApplication
|
* @mixes HandlebarsApplication
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
super(options);
|
super(options);
|
||||||
|
this.items = [];
|
||||||
|
this.fieldFilter = [];
|
||||||
|
this.selectedMenu = { path: [], data: null };
|
||||||
|
this.config = CONFIG.DH.ITEMBROWSER.compendiumConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
static DEFAULT_OPTIONS = {
|
static DEFAULT_OPTIONS = {
|
||||||
id: 'itemBrowser',
|
id: 'itemBrowser',
|
||||||
classes: [],
|
classes: ['dh-style'],
|
||||||
tag: 'div',
|
tag: 'div',
|
||||||
// window: {
|
|
||||||
// frame: true,
|
|
||||||
// title: 'Item Browser',
|
// title: 'Item Browser',
|
||||||
// positioned: true,
|
window: {
|
||||||
// resizable: true
|
frame: true,
|
||||||
// },
|
title: 'Item Browser',
|
||||||
actions: {
|
positioned: true,
|
||||||
// setFear: FearTracker.setFear,
|
resizable: true
|
||||||
// increaseFear: FearTracker.increaseFear
|
|
||||||
},
|
},
|
||||||
/* position: {
|
actions: {
|
||||||
width: 222,
|
selectFolder: this.selectFolder,
|
||||||
height: 222
|
expandContent: this.expandContent,
|
||||||
|
resetFilters: this.resetFilters
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
width: 1000,
|
||||||
|
height: 800
|
||||||
// top: "200px",
|
// top: "200px",
|
||||||
// left: "120px"
|
// left: "120px"
|
||||||
} */
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
static PARTS = {
|
static PARTS = {
|
||||||
resources: {
|
sidebar: {
|
||||||
root: true,
|
template: 'systems/daggerheart/templates/ui/itemBrowser/sidebar.hbs'
|
||||||
template: 'systems/daggerheart/templates/ui/itemBrowser.hbs'
|
},
|
||||||
|
list: {
|
||||||
|
template: 'systems/daggerheart/templates/ui/itemBrowser/itemBrowser.hbs'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* Filter Tracking */
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The currently active search filter.
|
||||||
|
* @type {foundry.applications.ux.SearchFilter}
|
||||||
|
*/
|
||||||
|
#search = {};
|
||||||
|
|
||||||
|
#input = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks which item IDs are currently displayed, organized by filter type and section.
|
||||||
|
* @type {{
|
||||||
|
* inventory: {
|
||||||
|
* search: Set<string>,
|
||||||
|
* input: Set<string>
|
||||||
|
* }
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
#filteredItems = {
|
||||||
|
browser: {
|
||||||
|
search: new Set(),
|
||||||
|
input: new Set()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
async _onRender(context, options) {
|
||||||
|
await super._onRender(context, options);
|
||||||
|
|
||||||
|
this._createSearchFilter();
|
||||||
|
this._createFilterInputs();
|
||||||
|
this._createDragProcess();
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
/* Rendering */
|
/* Rendering */
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
async _prepareContext(options) {
|
async _prepareContext(options) {
|
||||||
const data = await super._prepareContext(options);
|
const context = await super._prepareContext(options);
|
||||||
return data;
|
context.compendiums = this.getCompendiumFolders(foundry.utils.deepClone(this.config));
|
||||||
|
// context.pathTitle = this.pathTile;
|
||||||
|
context.menu = this.selectedMenu;
|
||||||
|
context.formatLabel = this.formatLabel;
|
||||||
|
context.formatChoices = this.formatChoices;
|
||||||
|
context.fieldFilter = this.fieldFilter = this.selectedMenu.data?.filters ? this._createFieldFilter() : [];
|
||||||
|
context.items = this.items;
|
||||||
|
console.log(this.items)
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCompendiumFolders(config, parent = null, depth = 0) {
|
||||||
|
let folders = [];
|
||||||
|
Object.values(config).forEach(c => {
|
||||||
|
const folder = {
|
||||||
|
id: c.id,
|
||||||
|
label: c.label,
|
||||||
|
selected: (!parent || parent.selected) && this.selectedMenu.path[depth] === c.id
|
||||||
|
}
|
||||||
|
folder.folders = c.folders ? ItemBrowser.sortBy(this.getCompendiumFolders(c.folders, folder, depth + 2), 'label') : [];
|
||||||
|
// sortBy(Object.values(c.folders), 'label')
|
||||||
|
folders.push(folder)
|
||||||
|
})
|
||||||
|
|
||||||
|
// console.log(folders)
|
||||||
|
return folders;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async selectFolder(_, target) {
|
||||||
|
const config = foundry.utils.deepClone(this.config),
|
||||||
|
compendium = target.closest('[data-compendium-id]').dataset.compendiumId,
|
||||||
|
folderId = target.dataset.folderId,
|
||||||
|
folderPath = `${compendium}.folders.${folderId}`,
|
||||||
|
folderData = foundry.utils.getProperty(config, folderPath);
|
||||||
|
|
||||||
|
this.selectedMenu = {
|
||||||
|
path: folderPath.split('.'),
|
||||||
|
data: folderData
|
||||||
|
}
|
||||||
|
|
||||||
|
let items = [];
|
||||||
|
for(const key of folderData.keys) {
|
||||||
|
const comp = game.packs.get(`${compendium}.${key}`);
|
||||||
|
if(!comp) return;
|
||||||
|
items = items.concat(await comp.getDocuments({ type__in: folderData.type }));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.items = ItemBrowser.sortBy(items, 'name');
|
||||||
|
this.render({ force: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
static expandContent(_, target) {
|
||||||
|
const parent = target.parentElement;
|
||||||
|
parent.classList.toggle("expanded");
|
||||||
|
}
|
||||||
|
|
||||||
|
static sortBy(data, property) {
|
||||||
|
return data.sort((a, b) => a[property] > b[property] ? 1 : -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
formatLabel(item, field) {
|
||||||
|
const property = foundry.utils.getProperty(item, field.key);
|
||||||
|
if(typeof field.format !== 'function') return property;
|
||||||
|
return field.format(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
formatChoices(data) {
|
||||||
|
if(!data.field.choices) return null;
|
||||||
|
const config = {
|
||||||
|
choices: data.field.choices
|
||||||
|
};
|
||||||
|
foundry.data.fields.StringField._prepareChoiceConfig(config);
|
||||||
|
return config.options.filter(c => data.filtered.includes(c.value) || data.filtered.includes(c.label.toLowerCase()));
|
||||||
|
}
|
||||||
|
|
||||||
|
_createFieldFilter() {
|
||||||
|
const filters = [];
|
||||||
|
this.selectedMenu.data.filters.forEach(f => {
|
||||||
|
if(typeof f.field === 'string')
|
||||||
|
f.field = foundry.utils.getProperty(game, f.field);
|
||||||
|
else if(typeof f.choices === 'function')
|
||||||
|
f.choices = f.choices();
|
||||||
|
filters.push(f)
|
||||||
|
})
|
||||||
|
return filters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* Search Inputs */
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and initialize search filter instances for the inventory and loadout sections.
|
||||||
|
*
|
||||||
|
* Sets up two {@link foundry.applications.ux.SearchFilter} instances:
|
||||||
|
* - One for the inventory, which filters items in the inventory grid.
|
||||||
|
* - One for the loadout, which filters items in the loadout/card grid.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_createSearchFilter() {
|
||||||
|
//Filters could be a application option if needed
|
||||||
|
const filters = [
|
||||||
|
{
|
||||||
|
key: 'browser',
|
||||||
|
input: 'input[type="search"].search-browser',
|
||||||
|
content: '[data-application-part="list"] .item-list',
|
||||||
|
callback: this._onSearchFilterBrowser.bind(this)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const { key, input, content, callback } of filters) {
|
||||||
|
const filter = new foundry.applications.ux.SearchFilter({
|
||||||
|
inputSelector: input,
|
||||||
|
contentSelector: content,
|
||||||
|
callback
|
||||||
|
});
|
||||||
|
filter.bind(this.element);
|
||||||
|
this.#search[key] = filter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* Filter Inputs */
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
_createFilterInputs() {
|
||||||
|
const inputs = [
|
||||||
|
{
|
||||||
|
key: 'browser',
|
||||||
|
container: '[data-application-part="list"] .filter-content .wrapper',
|
||||||
|
content: '[data-application-part="list"] .item-list',
|
||||||
|
callback: this._onInputFilterBrowser.bind(this),
|
||||||
|
// target: '.filter-button',
|
||||||
|
// filters: FilterMenu.invetoryFilters
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
inputs.forEach(m => {
|
||||||
|
const container = this.element.querySelector(m.container);
|
||||||
|
if(!container) return this.#input[m.key] = {};
|
||||||
|
const inputs = container.querySelectorAll('input, select');
|
||||||
|
inputs.forEach(input => {
|
||||||
|
input.addEventListener('change', this._onInputFilterBrowser.bind(this))
|
||||||
|
});
|
||||||
|
this.#filteredItems[m.key].input = new Set(this.items.map(i => i.id));
|
||||||
|
this.#input[m.key] = inputs;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle invetory items search and filtering.
|
||||||
|
* @param {KeyboardEvent} event The keyboard input event.
|
||||||
|
* @param {string} query The input search string.
|
||||||
|
* @param {RegExp} rgx The regular expression query that should be matched against.
|
||||||
|
* @param {HTMLElement} html The container to filter items from.
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
async _onSearchFilterBrowser(event, query, rgx, html) {
|
||||||
|
this.#filteredItems.browser.search.clear();
|
||||||
|
|
||||||
|
for (const li of html.querySelectorAll('.item-container')) {
|
||||||
|
const itemUUID = li.dataset.itemUuid,
|
||||||
|
item = this.items.find(i => i.uuid === itemUUID);
|
||||||
|
const matchesSearch = !query || foundry.applications.ux.SearchFilter.testQuery(rgx, item.name);
|
||||||
|
if (matchesSearch) this.#filteredItems.browser.search.add(item.id);
|
||||||
|
const { input } = this.#filteredItems.browser;
|
||||||
|
li.hidden = !(input.has(item.id) && matchesSearch);
|
||||||
|
// li.hidden = !(matchesSearch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback when filters change
|
||||||
|
* @param {PointerEvent} event
|
||||||
|
* @param {HTMLElement} html
|
||||||
|
*/
|
||||||
|
async _onInputFilterBrowser(event) {
|
||||||
|
this.#filteredItems.browser.input.clear();
|
||||||
|
|
||||||
|
console.log(event.target.name)
|
||||||
|
|
||||||
|
this.fieldFilter.find(f => f.key === event.target.name).value = event.target.value;
|
||||||
|
|
||||||
|
// console.log(_event, html, filters)
|
||||||
|
|
||||||
|
for (const li of event.target.closest('[data-application-part="list"]').querySelectorAll('.item-container')) {
|
||||||
|
const itemUUID = li.dataset.itemUuid,
|
||||||
|
item = this.items.find(i => i.uuid === itemUUID);
|
||||||
|
|
||||||
|
const matchesMenu =
|
||||||
|
this.fieldFilter.length === 0 || this.fieldFilter.every(f => {
|
||||||
|
return (!f.value && f.value !== false) || foundry.applications.ux.SearchFilter.evaluateFilter(item, this.createFilterData(f))
|
||||||
|
});
|
||||||
|
if (matchesMenu) this.#filteredItems.browser.input.add(item.id);
|
||||||
|
|
||||||
|
const { search } = this.#filteredItems.browser;
|
||||||
|
li.hidden = !(search.has(item.id) && matchesMenu);
|
||||||
|
// li.hidden = !(matchesMenu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createFilterData(filter) {
|
||||||
|
return {
|
||||||
|
field: filter.key,
|
||||||
|
value: isNaN(filter.value) ? (["true", "false"].includes(filter.value) ? filter.value === "true" : filter.value) : Number(filter.value),
|
||||||
|
operator: filter.operator,
|
||||||
|
negate: filter.negate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static resetFilters() {
|
||||||
|
this.render({ force: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize salient information about this Document when dragging it.
|
||||||
|
* @returns {object} An object of drag data.
|
||||||
|
*/
|
||||||
|
// toDragData() {
|
||||||
|
// const dragData = {type: this.documentName};
|
||||||
|
// if ( this.id ) dragData.uuid = this.uuid;
|
||||||
|
// else dragData.data = this.toObject();
|
||||||
|
// return dragData;
|
||||||
|
// }
|
||||||
|
|
||||||
|
_createDragProcess() {
|
||||||
|
new foundry.applications.ux.DragDrop.implementation({
|
||||||
|
dragSelector: ".item-container",
|
||||||
|
// dropSelector: ".directory-list",
|
||||||
|
permissions: {
|
||||||
|
dragstart: this._canDragStart.bind(this),
|
||||||
|
// drop: this._canDragDrop.bind(this)
|
||||||
|
},
|
||||||
|
callbacks: {
|
||||||
|
// dragover: this._onDragOver.bind(this),
|
||||||
|
dragstart: this._onDragStart.bind(this),
|
||||||
|
// drop: this._onDrop.bind(this)
|
||||||
|
}
|
||||||
|
}).bind(this.element);
|
||||||
|
// this.element.querySelectorAll(".directory-item.folder").forEach(folder => {
|
||||||
|
// folder.addEventListener("dragenter", this._onDragHighlight.bind(this));
|
||||||
|
// folder.addEventListener("dragleave", this._onDragHighlight.bind(this));
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
|
async _onDragStart(event) {
|
||||||
|
// console.log(event)
|
||||||
|
// ui.context?.close({ animate: false });
|
||||||
|
const { itemUuid } = event.target.closest('[data-item-uuid]').dataset;
|
||||||
|
const dragData = foundry.utils.fromUuidSync(itemUuid).toDragData();
|
||||||
|
// console.log(dragData)
|
||||||
|
// const dragData = { UUID: itemUuid };
|
||||||
|
event.dataTransfer.setData("text/plain", JSON.stringify(dragData));
|
||||||
|
}
|
||||||
|
|
||||||
|
_canDragStart() {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,3 +7,4 @@ export * as generalConfig from './generalConfig.mjs';
|
||||||
export * as itemConfig from './itemConfig.mjs';
|
export * as itemConfig from './itemConfig.mjs';
|
||||||
export * as settingsConfig from './settingsConfig.mjs';
|
export * as settingsConfig from './settingsConfig.mjs';
|
||||||
export * as systemConfig from './system.mjs';
|
export * as systemConfig from './system.mjs';
|
||||||
|
export * as itemBrowserConfig from './itemBrowserConfig.mjs';
|
||||||
|
|
|
||||||
231
module/config/itemBrowserConfig.mjs
Normal file
231
module/config/itemBrowserConfig.mjs
Normal file
|
|
@ -0,0 +1,231 @@
|
||||||
|
export const compendiumConfig = {
|
||||||
|
"daggerheart": {
|
||||||
|
id: "daggerheart",
|
||||||
|
label: "DAGGERHEART",
|
||||||
|
folders: {
|
||||||
|
"adversaries": {
|
||||||
|
id: "adversaries",
|
||||||
|
keys: ["adversaries"],
|
||||||
|
label: "Adversaries",
|
||||||
|
type: ["adversary"],
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
key: "system.tier",
|
||||||
|
label: "Tier"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "system.type",
|
||||||
|
label: "Type"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
key: "system.tier",
|
||||||
|
label: "Tier",
|
||||||
|
field: 'system.api.models.actors.DhAdversary.schema.fields.tier'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "system.type",
|
||||||
|
label: "Type",
|
||||||
|
field: 'system.api.models.actors.DhAdversary.schema.fields.type'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "system.difficulty",
|
||||||
|
label: "Difficulty (Min)",
|
||||||
|
field: 'system.api.models.actors.DhAdversary.schema.fields.difficulty',
|
||||||
|
operator: "gte"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "system.difficulty",
|
||||||
|
label: "Difficulty (Max)",
|
||||||
|
field: 'system.api.models.actors.DhAdversary.schema.fields.difficulty',
|
||||||
|
operator: "lte"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "system.resources.hitPoints.max",
|
||||||
|
label: "Hit Points (Min)",
|
||||||
|
field: 'system.api.models.actors.DhAdversary.schema.fields.resources.fields.hitPoints.fields.max',
|
||||||
|
operator: "gte"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "system.resources.hitPoints.max",
|
||||||
|
label: "Hit Points (Max)",
|
||||||
|
field: 'system.api.models.actors.DhAdversary.schema.fields.resources.fields.hitPoints.fields.max',
|
||||||
|
operator: "lte"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "system.resources.stress.max",
|
||||||
|
label: "Stress (Min)",
|
||||||
|
field: 'system.api.models.actors.DhAdversary.schema.fields.resources.fields.stress.fields.max',
|
||||||
|
operator: "gte"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "system.resources.stress.max",
|
||||||
|
label: "Stress (Max)",
|
||||||
|
field: 'system.api.models.actors.DhAdversary.schema.fields.resources.fields.stress.fields.max',
|
||||||
|
operator: "lte"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ancestries": {
|
||||||
|
id: "ancestries",
|
||||||
|
keys: ["ancestries"],
|
||||||
|
label: "Ancestries",
|
||||||
|
type: ["ancestry"],
|
||||||
|
folders: {
|
||||||
|
"features": {
|
||||||
|
id: "features",
|
||||||
|
keys: ["ancestries"],
|
||||||
|
label: "Features",
|
||||||
|
type: ["feature"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"equipments": {
|
||||||
|
id: "equipments",
|
||||||
|
keys: ["armors", "weapons", "consumables", "loot"],
|
||||||
|
label: "Equipments",
|
||||||
|
type: ["armor", "weapon", "consumable", "loot"],
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
key: "type",
|
||||||
|
label: "Type"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "system.secondary",
|
||||||
|
label: "Subtype",
|
||||||
|
format: (isSecondary) => isSecondary ? "secondary" : (isSecondary === false ? "primary" : '-')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "system.tier",
|
||||||
|
label: "Tier"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
key: "type",
|
||||||
|
label: "Type",
|
||||||
|
// filtered: ["armor", "weapon", "consumable", "loot"],
|
||||||
|
// field: 'system.api.documents.DHItem.schema.fields.type',
|
||||||
|
// valueAttr: 'label'
|
||||||
|
choices: () => CONFIG.Item.documentClass.TYPES.filter(t => ["armor", "weapon", "consumable", "loot"].includes(t)).map(t => ({ value: t, label: t }))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "system.secondary",
|
||||||
|
label: "Subtype",
|
||||||
|
choices: [
|
||||||
|
{ value: false, label: "Primary Weapon"},
|
||||||
|
{ value: true, label: "Secondary Weapon"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "system.tier",
|
||||||
|
label: "Tier",
|
||||||
|
choices: [{ value: "1", label: "1"}, { value: "2", label: "2"}, { value: "3", label: "3"}, { value: "4", label: "4"}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "system.burden",
|
||||||
|
label: "Burden",
|
||||||
|
field: 'system.api.models.items.DHWeapon.schema.fields.burden'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "system.attack.roll.trait",
|
||||||
|
label: "Trait",
|
||||||
|
field: 'system.api.models.actions.actionsTypes.attack.schema.fields.roll.fields.trait'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "system.attack.range",
|
||||||
|
label: "Range",
|
||||||
|
field: 'system.api.models.actions.actionsTypes.attack.schema.fields.range'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "system.baseScore",
|
||||||
|
label: "Armor Score (Min)",
|
||||||
|
field: 'system.api.models.items.DHArmor.schema.fields.baseScore',
|
||||||
|
operator: "gte"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "system.baseScore",
|
||||||
|
label: "Armor Score (Max)",
|
||||||
|
field: 'system.api.models.items.DHArmor.schema.fields.baseScore',
|
||||||
|
operator: "lte"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"classes": {
|
||||||
|
id: "classes",
|
||||||
|
keys: ["classes"],
|
||||||
|
label: "Classes",
|
||||||
|
type: ["class"],
|
||||||
|
folders: {
|
||||||
|
"features": {
|
||||||
|
id: "features",
|
||||||
|
keys: ["classes"],
|
||||||
|
label: "Features",
|
||||||
|
type: ["feature"]
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
id: "items",
|
||||||
|
keys: ["classes"],
|
||||||
|
label: "Items",
|
||||||
|
type: ["armor", "weapon", "consumable", "loot"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"subclasses": {
|
||||||
|
id: "subclasses",
|
||||||
|
keys: ["subclasses"],
|
||||||
|
label: "Subclasses",
|
||||||
|
type: ["subclass"],
|
||||||
|
folders: {
|
||||||
|
"features": {
|
||||||
|
id: "features",
|
||||||
|
keys: ["subclasses"],
|
||||||
|
label: "Features",
|
||||||
|
type: ["feature"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"domains": {
|
||||||
|
id: "domains",
|
||||||
|
keys: ["domains"],
|
||||||
|
label: "Domain Cards",
|
||||||
|
type: ["domainCard"]
|
||||||
|
},
|
||||||
|
"communities": {
|
||||||
|
id: "communities",
|
||||||
|
keys: ["communities"],
|
||||||
|
label: "Communities",
|
||||||
|
type: ["community"],
|
||||||
|
folders: {
|
||||||
|
"features": {
|
||||||
|
id: "features",
|
||||||
|
keys: ["communities"],
|
||||||
|
label: "Features",
|
||||||
|
type: ["feature"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"environments": {
|
||||||
|
id: "environments",
|
||||||
|
keys: ["environments"],
|
||||||
|
label: "Environments",
|
||||||
|
type: ["environment"]
|
||||||
|
},
|
||||||
|
"beastforms": {
|
||||||
|
id: "beastforms",
|
||||||
|
keys: ["beastforms"],
|
||||||
|
label: "Beastforms",
|
||||||
|
type: ["beastform"],
|
||||||
|
folders: {
|
||||||
|
"features": {
|
||||||
|
id: "features",
|
||||||
|
keys: ["beastforms"],
|
||||||
|
label: "Features",
|
||||||
|
type: ["feature"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,7 @@ import * as SETTINGS from './settingsConfig.mjs';
|
||||||
import * as EFFECTS from './effectConfig.mjs';
|
import * as EFFECTS from './effectConfig.mjs';
|
||||||
import * as ACTIONS from './actionConfig.mjs';
|
import * as ACTIONS from './actionConfig.mjs';
|
||||||
import * as FLAGS from './flagsConfig.mjs';
|
import * as FLAGS from './flagsConfig.mjs';
|
||||||
|
import * as ITEMBROWSER from './itemBrowserConfig.mjs'
|
||||||
|
|
||||||
export const SYSTEM_ID = 'daggerheart';
|
export const SYSTEM_ID = 'daggerheart';
|
||||||
|
|
||||||
|
|
@ -18,5 +19,6 @@ export const SYSTEM = {
|
||||||
SETTINGS,
|
SETTINGS,
|
||||||
EFFECTS,
|
EFFECTS,
|
||||||
ACTIONS,
|
ACTIONS,
|
||||||
FLAGS
|
FLAGS,
|
||||||
|
ITEMBROWSER
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,8 @@ export default class RangeField extends fields.StringField {
|
||||||
const options = {
|
const options = {
|
||||||
choices: CONFIG.DH.GENERAL.range,
|
choices: CONFIG.DH.GENERAL.range,
|
||||||
required: false,
|
required: false,
|
||||||
blank: true
|
blank: true,
|
||||||
|
label: "DAGGERHEART.GENERAL.range"
|
||||||
};
|
};
|
||||||
super(options, context);
|
super(options, context);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ export class DHActionRollData extends foundry.abstract.DataModel {
|
||||||
static defineSchema() {
|
static defineSchema() {
|
||||||
return {
|
return {
|
||||||
type: new fields.StringField({ nullable: true, initial: null, choices: CONFIG.DH.GENERAL.rollTypes }),
|
type: new fields.StringField({ nullable: true, initial: null, choices: CONFIG.DH.GENERAL.rollTypes }),
|
||||||
trait: new fields.StringField({ nullable: true, initial: null, choices: CONFIG.DH.ACTOR.abilities }),
|
trait: new fields.StringField({ nullable: true, initial: null, choices: CONFIG.DH.ACTOR.abilities, label: "DAGGERHEART.GENERAL.Trait.single" }),
|
||||||
difficulty: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 }),
|
difficulty: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 }),
|
||||||
bonus: new fields.NumberField({ nullable: true, initial: null, integer: true }),
|
bonus: new fields.NumberField({ nullable: true, initial: null, integer: true }),
|
||||||
advState: new fields.StringField({
|
advState: new fields.StringField({
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,12 @@ export default class DHWeapon extends AttachableItem {
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
return {
|
return {
|
||||||
...super.defineSchema(),
|
...super.defineSchema(),
|
||||||
tier: new fields.NumberField({ required: true, integer: true, initial: 1, min: 1 }),
|
tier: new fields.NumberField({ required: true, integer: true, initial: 1, min: 1, label: "DAGGERHEART.GENERAL.Tiers.singular" }),
|
||||||
equipped: new fields.BooleanField({ initial: false }),
|
equipped: new fields.BooleanField({ initial: false }),
|
||||||
|
|
||||||
//SETTINGS
|
//SETTINGS
|
||||||
secondary: new fields.BooleanField({ initial: false }),
|
secondary: new fields.BooleanField({ initial: false, label: "DAGGERHEART.ITEMS.Weapon.secondaryWeapon" }),
|
||||||
burden: new fields.StringField({ required: true, choices: CONFIG.DH.GENERAL.burden, initial: 'oneHanded' }),
|
burden: new fields.StringField({ required: true, choices: CONFIG.DH.GENERAL.burden, initial: 'oneHanded', label: "DAGGERHEART.GENERAL.burden" }),
|
||||||
weaponFeatures: new fields.ArrayField(
|
weaponFeatures: new fields.ArrayField(
|
||||||
new fields.SchemaField({
|
new fields.SchemaField({
|
||||||
value: new fields.StringField({
|
value: new fields.StringField({
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ export default class RegisterHandlebarsHelpers {
|
||||||
damageSymbols: this.damageSymbols,
|
damageSymbols: this.damageSymbols,
|
||||||
rollParsed: this.rollParsed,
|
rollParsed: this.rollParsed,
|
||||||
hasProperty: foundry.utils.hasProperty,
|
hasProperty: foundry.utils.hasProperty,
|
||||||
|
getProperty: foundry.utils.getProperty,
|
||||||
setVar: this.setVar,
|
setVar: this.setVar,
|
||||||
empty: this.empty
|
empty: this.empty
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
@import './combat-sidebar/encounter-controls.less';
|
@import './combat-sidebar/encounter-controls.less';
|
||||||
@import './combat-sidebar/spotlight-control.less';
|
@import './combat-sidebar/spotlight-control.less';
|
||||||
@import './combat-sidebar/token-actions.less';
|
@import './combat-sidebar/token-actions.less';
|
||||||
|
@import './item-browser/item-browser.less';
|
||||||
|
|
||||||
@import './countdown/countdown.less';
|
@import './countdown/countdown.less';
|
||||||
@import './countdown/sheet.less';
|
@import './countdown/sheet.less';
|
||||||
|
|
|
||||||
204
styles/less/ui/item-browser/item-browser.less
Normal file
204
styles/less/ui/item-browser/item-browser.less
Normal file
|
|
@ -0,0 +1,204 @@
|
||||||
|
@scrollbar-width: 20px;
|
||||||
|
#itemBrowser {
|
||||||
|
border: initial;
|
||||||
|
.window-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 50px;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div[data-application-part="list"] {
|
||||||
|
flex: 1;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compendium-container {
|
||||||
|
summary {
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 2px 12px;
|
||||||
|
border-radius: 3px;
|
||||||
|
background-color: light-dark(#18162e, #f3c267);
|
||||||
|
color: light-dark(#efe6d8, #18162e);
|
||||||
|
list-style: none;
|
||||||
|
|
||||||
|
&::marker, /* Latest Chrome, Edge, Firefox */
|
||||||
|
&::-webkit-details-marker /* Safari */ {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .folder-list {
|
||||||
|
padding: 10px;
|
||||||
|
gap: 0;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
&.folder-list {
|
||||||
|
> div {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.folder-list) {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-path, option, select {
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-path > :first-child {
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-path {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
> span {
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 2px 12px;
|
||||||
|
border-radius: 3px;
|
||||||
|
background-color: light-dark(#18162e, #f3c267);
|
||||||
|
color: light-dark(#efe6d8, #18162e);
|
||||||
|
|
||||||
|
&.path-link {
|
||||||
|
padding: 0 5px;
|
||||||
|
background-color: light-dark(#f3c267, #18162e);
|
||||||
|
color: light-dark(#18162e, #efe6d8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.folder-list, .item-list-header, .item-header > div {
|
||||||
|
gap: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-filter {
|
||||||
|
|
||||||
|
.wrapper, .form-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.folder-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
[data-folder-id] {
|
||||||
|
padding: 2px 12px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-selected, > [data-folder-id]:hover {
|
||||||
|
font-weight: bold;
|
||||||
|
border-radius: 3px;
|
||||||
|
background-color: light-dark(transparent, #18162e);
|
||||||
|
color: light-dark(#18162e, #f3c267);
|
||||||
|
border-color: light-dark(#18162e, #f3c267);
|
||||||
|
}
|
||||||
|
|
||||||
|
.subfolder-list {
|
||||||
|
margin: 0 10px;
|
||||||
|
gap: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-list-header, .item-header > div {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 40px 400px repeat(auto-fit, minmax(100px, 1fr));
|
||||||
|
align-items: center;
|
||||||
|
text-transform: capitalize;
|
||||||
|
// gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-list-header, .item-list {
|
||||||
|
overflow-y: auto;
|
||||||
|
scrollbar-gutter: stable;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-list-header {
|
||||||
|
background-color: light-dark(transparent, #18162e);
|
||||||
|
color: light-dark(#18162e, #f3c267);
|
||||||
|
border: 1px solid light-dark(#18162e, #f3c267);
|
||||||
|
border-radius: 6px;
|
||||||
|
min-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 5px;
|
||||||
|
|
||||||
|
.item-container {
|
||||||
|
&:hover {
|
||||||
|
background: rgba(255, 255, 255, .1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-desc .wrapper {
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-content {
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-content, .item-desc {
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: 0fr;
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
.wrapper {
|
||||||
|
overflow: hidden;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
label {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.form-fields {
|
||||||
|
flex: 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.expanded + .extensible {
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-message {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -68,4 +68,5 @@
|
||||||
canCreate=true
|
canCreate=true
|
||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
|
<button type="button" data-action="tempBrowser">Item Browser</button>
|
||||||
</section>
|
</section>
|
||||||
|
|
@ -6,15 +6,15 @@
|
||||||
<fieldset class="two-columns">
|
<fieldset class="two-columns">
|
||||||
<legend>{{localize tabs.settings.label}}</legend>
|
<legend>{{localize tabs.settings.label}}</legend>
|
||||||
<span>{{localize "DAGGERHEART.GENERAL.Tiers.singular"}}</span>
|
<span>{{localize "DAGGERHEART.GENERAL.Tiers.singular"}}</span>
|
||||||
{{formField systemFields.tier value=source.system.tier}}
|
{{formInput systemFields.tier value=source.system.tier}}
|
||||||
<span>{{localize "DAGGERHEART.ITEMS.Weapon.secondaryWeapon"}}</span>
|
<span>{{localize "DAGGERHEART.ITEMS.Weapon.secondaryWeapon"}}</span>
|
||||||
{{formField systemFields.secondary value=source.system.secondary}}
|
{{formInput systemFields.secondary value=source.system.secondary}}
|
||||||
<span>{{localize "DAGGERHEART.GENERAL.Trait.single"}}</span>
|
<span>{{localize "DAGGERHEART.GENERAL.Trait.single"}}</span>
|
||||||
{{formInput systemFields.attack.fields.roll.fields.trait value=document.system.attack.roll.trait name="system.attack.roll.trait" label="DAGGERHEART.GENERAL.Trait.single" localize=true}}
|
{{formInput systemFields.attack.fields.roll.fields.trait value=document.system.attack.roll.trait name="system.attack.roll.trait" label="DAGGERHEART.GENERAL.Trait.single" localize=true}}
|
||||||
<span>{{localize "DAGGERHEART.GENERAL.range"}}</span>
|
<span>{{localize "DAGGERHEART.GENERAL.range"}}</span>
|
||||||
{{formInput systemFields.attack.fields.range value=document.system.attack.range label="Range" name="system.attack.range" localize=true}}
|
{{formInput systemFields.attack.fields.range value=document.system.attack.range label="Range" name="system.attack.range" localize=true}}
|
||||||
<span>{{localize "DAGGERHEART.GENERAL.burden"}}</span>
|
<span>{{localize "DAGGERHEART.GENERAL.burden"}}</span>
|
||||||
{{formField systemFields.burden value=source.system.burden localize=true}}
|
{{formInput systemFields.burden value=source.system.burden localize=true}}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset class="two-columns">
|
<fieldset class="two-columns">
|
||||||
|
|
|
||||||
80
templates/ui/itemBrowser/itemBrowser.hbs
Normal file
80
templates/ui/itemBrowser/itemBrowser.hbs
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
<div>
|
||||||
|
{{#if menu.data }}
|
||||||
|
<div class="menu-path">
|
||||||
|
{{#each menu.path}}
|
||||||
|
{{#unless (eq this "folders")}}
|
||||||
|
<span>{{this}}</span>
|
||||||
|
{{#unless @last}}
|
||||||
|
<span class="path-link"> > </span>
|
||||||
|
{{/unless}}
|
||||||
|
{{/unless}}
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
<fieldset class="item-filter glassy">
|
||||||
|
<div class="filter-header">
|
||||||
|
<input type="search" name="search" class="search-browser" placeholder="Search...">
|
||||||
|
{{#if fieldFilter}}
|
||||||
|
<button type="button" data-action="expandContent">Filters</button>
|
||||||
|
{{/if}}
|
||||||
|
<button type="button" data-action="resetFilters">Reset</button>
|
||||||
|
</div>
|
||||||
|
<div class="filter-content extensible">
|
||||||
|
<div class="wrapper">
|
||||||
|
{{#each fieldFilter}}
|
||||||
|
{{#if choices }}
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{localize label}}</label>
|
||||||
|
<div class="form-fields">
|
||||||
|
<select name="{{key}}">
|
||||||
|
{{selectOptions choices valueAttr="value" blank="" }}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
{{#if filtered }}
|
||||||
|
{{formField field localize=true blank="" choices=(@root.formatChoices this) valueAttr="value" name=key}}
|
||||||
|
{{else}}
|
||||||
|
{{#if field.label}}
|
||||||
|
{{formField field localize=true blank="" name=key}}
|
||||||
|
{{else}}
|
||||||
|
{{formField field localize=true blank="" name=key label=label}}
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
{{!-- <div class="item-list-container"> --}}
|
||||||
|
{{#if menu.data.columns.length}}
|
||||||
|
<div class="item-list-header">
|
||||||
|
<div></div>
|
||||||
|
<div>Name</div>
|
||||||
|
{{#each menu.data.columns}}
|
||||||
|
<div>{{label}}</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
<div class="item-list">
|
||||||
|
{{#each items}}
|
||||||
|
<div class="item-container" data-item-uuid="{{uuid}}" draggable="true">
|
||||||
|
<div class="item-header">
|
||||||
|
<div data-action="expandContent">
|
||||||
|
<img src="{{img}}" data-item-key="img">
|
||||||
|
<div data-item-key="name">{{name}}</div>
|
||||||
|
{{#each ../menu.data.columns}}
|
||||||
|
<div data-item-key="{{@key}}">{{#with (@root.formatLabel ../this this) as | label |}}{{label}}{{/with}}</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="item-desc extensible">
|
||||||
|
<div class="wrapper">{{{system.description}}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{!-- </div> --}}
|
||||||
|
{{else}}
|
||||||
|
<h2 class="welcome-message">Welcome to DAGGERHEART Items Browser</h2>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
18
templates/ui/itemBrowser/sidebar.hbs
Normal file
18
templates/ui/itemBrowser/sidebar.hbs
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
<div>
|
||||||
|
{{#each compendiums}}
|
||||||
|
<details class="compendium-container" data-compendium-id="{{id}}" open>
|
||||||
|
<summary>{{label}}</summary>
|
||||||
|
<div class="folder-list">
|
||||||
|
{{#each folders}}
|
||||||
|
<div class="{{#if selected}} is-selected{{/if}}" data-action="selectFolder" data-folder-id="{{id}}">{{label}}</div>
|
||||||
|
{{!-- <div data-action="selectFolder" data-folder-id="{{id}}">{{label}}</div> --}}
|
||||||
|
<div class="folder-list subfolder-list">
|
||||||
|
{{#each folders}}
|
||||||
|
<div class="{{#if selected}} is-selected{{/if}}" data-action="selectFolder" data-folder-id="{{../id}}.folders.{{id}}">- {{label}}</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue