From 1f948cd5d824b96c5201bf96b1bb0261e37a8ab7 Mon Sep 17 00:00:00 2001 From: Lucas 'Paperboy' Rose-Winters Date: Fri, 17 Oct 2025 15:36:15 +1100 Subject: [PATCH] feat(inventory): wire up v2 system to main panel with full interactivity - Add inventory section to template.html between Thoughts and bottom controls - Wire up renderInventory() to all event handlers (message received, character changed, swipes) - Initialize inventory container reference and event listeners in index.js - Add showInventory toggle checkbox to settings with visibility control - Update layout.js to handle inventory section and divider visibility - Add renderInventory parameter to updateRPGData for separate mode support - Update state.js and config.js with inventory container and showInventory setting Inventory is now fully integrated as a visible, interactive panel section that persists across all user interactions. --- index.js | 20 ++++++++++++++++++-- src/core/config.js | 4 +++- src/core/state.js | 9 ++++++++- src/systems/generation/apiClient.js | 5 ++++- src/systems/integration/sillytavern.js | 6 +++++- src/systems/ui/layout.js | 17 +++++++++++++---- template.html | 13 +++++++++++++ 7 files changed, 64 insertions(+), 10 deletions(-) diff --git a/index.js b/index.js index 12322f5..1b1f914 100644 --- a/index.js +++ b/index.js @@ -18,6 +18,7 @@ import { $userStatsContainer, $infoBoxContainer, $thoughtsContainer, + $inventoryContainer, setExtensionSettings, updateExtensionSettings, setLastGeneratedData, @@ -31,7 +32,8 @@ import { setPanelContainer, setUserStatsContainer, setInfoBoxContainer, - setThoughtsContainer + setThoughtsContainer, + setInventoryContainer } from './src/core/state.js'; import { loadSettings, saveSettings, saveChatData, loadChatData, updateMessageSwipeData } from './src/core/persistence.js'; import { registerAllEvents } from './src/core/events.js'; @@ -58,6 +60,10 @@ import { updateChatThoughts, createThoughtPanel } from './src/systems/rendering/thoughts.js'; +import { renderInventory } from './src/systems/rendering/inventory.js'; + +// Interaction modules +import { initInventoryEventListeners } from './src/systems/interaction/inventoryActions.js'; // UI Systems modules import { @@ -180,6 +186,7 @@ async function initUI() { setUserStatsContainer($('#rpg-user-stats')); setInfoBoxContainer($('#rpg-info-box')); setThoughtsContainer($('#rpg-thoughts')); + setInventoryContainer($('#rpg-inventory')); // Set up event listeners (enable/disable is handled in Extensions tab) $('#rpg-toggle-auto-update').on('change', function() { @@ -225,6 +232,12 @@ async function initUI() { updateSectionVisibility(); }); + $('#rpg-toggle-inventory').on('change', function() { + extensionSettings.showInventory = $(this).prop('checked'); + saveSettings(); + updateSectionVisibility(); + }); + $('#rpg-toggle-thoughts-in-chat').on('change', function() { extensionSettings.showThoughtsInChat = $(this).prop('checked'); // console.log('[RPG Companion] Toggle showThoughtsInChat changed to:', extensionSettings.showThoughtsInChat); @@ -256,7 +269,7 @@ async function initUI() { // console.log('[RPG Companion] Extension is disabled. Please enable it in the Extensions tab.'); return; } - await updateRPGData(renderUserStats, renderInfoBox, renderThoughts); + await updateRPGData(renderUserStats, renderInfoBox, renderThoughts, renderInventory); }); $('#rpg-stat-bar-color-low').on('change', function() { @@ -330,6 +343,7 @@ async function initUI() { $('#rpg-toggle-user-stats').prop('checked', extensionSettings.showUserStats); $('#rpg-toggle-info-box').prop('checked', extensionSettings.showInfoBox); $('#rpg-toggle-thoughts').prop('checked', extensionSettings.showCharacterThoughts); + $('#rpg-toggle-inventory').prop('checked', extensionSettings.showInventory); $('#rpg-toggle-thoughts-in-chat').prop('checked', extensionSettings.showThoughtsInChat); $('#rpg-toggle-html-prompt').prop('checked', extensionSettings.enableHtmlPrompt); $('#rpg-toggle-plot-buttons').prop('checked', extensionSettings.enablePlotButtons); @@ -361,6 +375,7 @@ async function initUI() { renderUserStats(); renderInfoBox(); renderThoughts(); + renderInventory(); updateDiceDisplay(); setupDiceRoller(); setupClassicStatsButtons(); @@ -369,6 +384,7 @@ async function initUI() { setupPlotButtons(sendPlotProgression); setupMobileKeyboardHandling(); setupContentEditableScrolling(); + initInventoryEventListeners(); } diff --git a/src/core/config.js b/src/core/config.js index 1cca094..2ddd8b0 100644 --- a/src/core/config.js +++ b/src/core/config.js @@ -29,6 +29,7 @@ export const defaultSettings = { showUserStats: true, showInfoBox: true, showCharacterThoughts: true, + showInventory: true, // Show inventory section (v2 system) showThoughtsInChat: true, // Show thoughts overlay in chat enableHtmlPrompt: false, // Enable immersive HTML prompt injection enablePlotButtons: true, // Show plot progression buttons above chat input @@ -71,5 +72,6 @@ export const defaultSettings = { wis: 10, cha: 10 }, - lastDiceRoll: null // Store last dice roll result + lastDiceRoll: null, // Store last dice roll result + collapsedInventoryLocations: [] // Array of collapsed storage location names }; diff --git a/src/core/state.js b/src/core/state.js index 91a7ef1..db73901 100644 --- a/src/core/state.js +++ b/src/core/state.js @@ -17,6 +17,7 @@ export let extensionSettings = { showUserStats: true, showInfoBox: true, showCharacterThoughts: true, + showInventory: true, // Show inventory section (v2 system) showThoughtsInChat: true, // Show thoughts overlay in chat enableHtmlPrompt: false, // Enable immersive HTML prompt injection enablePlotButtons: true, // Show plot progression buttons above chat input @@ -59,7 +60,8 @@ export let extensionSettings = { wis: 10, cha: 10 }, - lastDiceRoll: null // Store last dice roll result + lastDiceRoll: null, // Store last dice roll result + collapsedInventoryLocations: [] // Array of collapsed storage location names }; /** @@ -123,6 +125,7 @@ export let $panelContainer = null; export let $userStatsContainer = null; export let $infoBoxContainer = null; export let $thoughtsContainer = null; +export let $inventoryContainer = null; /** * State setters - provide controlled mutation of state variables @@ -186,3 +189,7 @@ export function setInfoBoxContainer($element) { export function setThoughtsContainer($element) { $thoughtsContainer = $element; } + +export function setInventoryContainer($element) { + $inventoryContainer = $element; +} diff --git a/src/systems/generation/apiClient.js b/src/systems/generation/apiClient.js index b51264b..a613be2 100644 --- a/src/systems/generation/apiClient.js +++ b/src/systems/generation/apiClient.js @@ -25,8 +25,9 @@ import { parseResponse, parseUserStats } from './parser.js'; * @param {Function} renderUserStats - UI function to render user stats * @param {Function} renderInfoBox - UI function to render info box * @param {Function} renderThoughts - UI function to render character thoughts + * @param {Function} renderInventory - UI function to render inventory */ -export async function updateRPGData(renderUserStats, renderInfoBox, renderThoughts) { +export async function updateRPGData(renderUserStats, renderInfoBox, renderThoughts, renderInventory) { if (isGenerating) { // console.log('[RPG Companion] Already generating, skipping...'); return; @@ -123,6 +124,7 @@ export async function updateRPGData(renderUserStats, renderInfoBox, renderThough renderUserStats(); renderInfoBox(); renderThoughts(); + renderInventory(); } else { // No assistant message to attach to - just update display if (parsedData.userStats) { @@ -131,6 +133,7 @@ export async function updateRPGData(renderUserStats, renderInfoBox, renderThough renderUserStats(); renderInfoBox(); renderThoughts(); + renderInventory(); } // Save to chat metadata diff --git a/src/systems/integration/sillytavern.js b/src/systems/integration/sillytavern.js index 1b6c9f4..4f6aa98 100644 --- a/src/systems/integration/sillytavern.js +++ b/src/systems/integration/sillytavern.js @@ -28,6 +28,7 @@ import { updateRPGData } from '../generation/apiClient.js'; import { renderUserStats } from '../rendering/userStats.js'; import { renderInfoBox } from '../rendering/infoBox.js'; import { renderThoughts, updateChatThoughts } from '../rendering/thoughts.js'; +import { renderInventory } from '../rendering/inventory.js'; // Utils import { getSafeThumbnailUrl } from '../../utils/avatars.js'; @@ -162,6 +163,7 @@ export async function onMessageReceived(data) { renderUserStats(); renderInfoBox(); renderThoughts(); + renderInventory(); // Save to chat metadata saveChatData(); @@ -169,7 +171,7 @@ export async function onMessageReceived(data) { } else if (extensionSettings.generationMode === 'separate' && extensionSettings.autoUpdate) { // In separate mode with auto-update, trigger update after message setTimeout(async () => { - await updateRPGData(renderUserStats, renderInfoBox, renderThoughts); + await updateRPGData(renderUserStats, renderInfoBox, renderThoughts, renderInventory); }, 500); } @@ -210,6 +212,7 @@ export function onCharacterChanged() { renderUserStats(); renderInfoBox(); renderThoughts(); + renderInventory(); // Update chat thought overlays updateChatThoughts(); @@ -280,6 +283,7 @@ export function onMessageSwiped(messageIndex) { renderUserStats(); renderInfoBox(); renderThoughts(); + renderInventory(); // Update chat thought overlays updateChatThoughts(); diff --git a/src/systems/ui/layout.js b/src/systems/ui/layout.js index 854280f..9993154 100644 --- a/src/systems/ui/layout.js +++ b/src/systems/ui/layout.js @@ -8,7 +8,8 @@ import { $panelContainer, $userStatsContainer, $infoBoxContainer, - $thoughtsContainer + $thoughtsContainer, + $inventoryContainer } from '../../core/state.js'; /** @@ -217,17 +218,25 @@ export function updateSectionVisibility() { $userStatsContainer.toggle(extensionSettings.showUserStats); $infoBoxContainer.toggle(extensionSettings.showInfoBox); $thoughtsContainer.toggle(extensionSettings.showCharacterThoughts); + if ($inventoryContainer) { + $inventoryContainer.toggle(extensionSettings.showInventory); + } // Show/hide dividers intelligently // Divider after User Stats: shown if User Stats is visible AND at least one section after it is visible const showDividerAfterStats = extensionSettings.showUserStats && - (extensionSettings.showInfoBox || extensionSettings.showCharacterThoughts); + (extensionSettings.showInfoBox || extensionSettings.showCharacterThoughts || extensionSettings.showInventory); $('#rpg-divider-stats').toggle(showDividerAfterStats); - // Divider after Info Box: shown if Info Box is visible AND Mind Reading is visible + // Divider after Info Box: shown if Info Box is visible AND at least one section after it is visible const showDividerAfterInfo = extensionSettings.showInfoBox && - extensionSettings.showCharacterThoughts; + (extensionSettings.showCharacterThoughts || extensionSettings.showInventory); $('#rpg-divider-info').toggle(showDividerAfterInfo); + + // Divider after Thoughts: shown if Thoughts is visible AND Inventory is visible + const showDividerAfterThoughts = extensionSettings.showCharacterThoughts && + extensionSettings.showInventory; + $('#rpg-divider-thoughts').toggle(showDividerAfterThoughts); } /** diff --git a/template.html b/template.html index 6d30c04..a720db6 100644 --- a/template.html +++ b/template.html @@ -44,6 +44,14 @@
+ + +
+ + +
+ +
@@ -159,6 +167,11 @@ Show Present Characters + +