diff --git a/index.js b/index.js
index 1b1f914..a0b696d 100644
--- a/index.js
+++ b/index.js
@@ -100,6 +100,10 @@ import {
setupMobileKeyboardHandling,
setupContentEditableScrolling
} from './src/systems/ui/mobile.js';
+import {
+ setupDesktopTabs,
+ removeDesktopTabs
+} from './src/systems/ui/desktop.js';
// Feature modules
import { setupPlotButtons, sendPlotProgression } from './src/systems/features/plotProgression.js';
@@ -368,6 +372,11 @@ async function initUI() {
// Setup mobile toggle button
setupMobileToggle();
+ // Setup desktop tabs (only on desktop viewport)
+ if (window.innerWidth > 1000) {
+ setupDesktopTabs();
+ }
+
// Setup collapse/expand toggle button
setupCollapseToggle();
diff --git a/src/systems/ui/desktop.js b/src/systems/ui/desktop.js
new file mode 100644
index 0000000..2b8e2a4
--- /dev/null
+++ b/src/systems/ui/desktop.js
@@ -0,0 +1,139 @@
+/**
+ * Desktop UI Module
+ * Handles desktop-specific UI functionality: tab navigation
+ */
+
+/**
+ * Sets up desktop tab navigation for organizing content.
+ * Only runs on desktop viewports (>1000px).
+ * Creates two tabs: Status (Stats/Info/Thoughts) and Inventory.
+ */
+export function setupDesktopTabs() {
+ const isDesktop = window.innerWidth > 1000;
+ if (!isDesktop) return;
+
+ // Check if tabs already exist
+ if ($('.rpg-tabs-nav').length > 0) return;
+
+ const $contentBox = $('.rpg-content-box');
+
+ // Get existing sections
+ const $userStats = $('#rpg-user-stats');
+ const $infoBox = $('#rpg-info-box');
+ const $thoughts = $('#rpg-thoughts');
+ const $inventory = $('#rpg-inventory');
+
+ // If no sections exist, nothing to organize
+ if ($userStats.length === 0 && $infoBox.length === 0 && $thoughts.length === 0 && $inventory.length === 0) {
+ return;
+ }
+
+ // Create tab navigation
+ const $tabNav = $(`
+
+
+
+
+ `);
+
+ // Create tab content containers
+ const $statusTab = $('');
+ const $inventoryTab = $('');
+
+ // Move sections into their respective tabs (detach to preserve event handlers)
+ if ($userStats.length > 0) {
+ $statusTab.append($userStats.detach());
+ $userStats.show();
+ }
+ if ($infoBox.length > 0) {
+ $statusTab.append($infoBox.detach());
+ $infoBox.show();
+ }
+ if ($thoughts.length > 0) {
+ $statusTab.append($thoughts.detach());
+ $thoughts.show();
+ }
+ if ($inventory.length > 0) {
+ $inventoryTab.append($inventory.detach());
+ $inventory.show();
+ }
+
+ // Hide dividers on desktop tabs (tabs separate content naturally)
+ $('.rpg-divider').hide();
+
+ // Build desktop tab structure
+ const $tabsContainer = $('');
+ $tabsContainer.append($tabNav);
+ $tabsContainer.append($statusTab);
+ $tabsContainer.append($inventoryTab);
+
+ // Replace content box with tabs container
+ $contentBox.html('').append($tabsContainer);
+
+ // Handle tab switching
+ $tabNav.find('.rpg-tab-btn').on('click', function() {
+ const tabName = $(this).data('tab');
+
+ // Update active tab button
+ $tabNav.find('.rpg-tab-btn').removeClass('active');
+ $(this).addClass('active');
+
+ // Update active tab content
+ $('.rpg-tab-content').removeClass('active');
+ $(`.rpg-tab-content[data-tab-content="${tabName}"]`).addClass('active');
+ });
+
+ console.log('[RPG Desktop] Desktop tabs initialized');
+}
+
+/**
+ * Removes desktop tab navigation and restores original layout.
+ * Used when transitioning from desktop to mobile.
+ */
+export function removeDesktopTabs() {
+ // Get sections from tabs before removing
+ const $userStats = $('#rpg-user-stats').detach();
+ const $infoBox = $('#rpg-info-box').detach();
+ const $thoughts = $('#rpg-thoughts').detach();
+ const $inventory = $('#rpg-inventory').detach();
+
+ // Remove tabs container
+ $('.rpg-tabs-container').remove();
+
+ // Get dividers
+ const $dividerStats = $('#rpg-divider-stats');
+ const $dividerInfo = $('#rpg-divider-info');
+ const $dividerThoughts = $('#rpg-divider-thoughts');
+
+ // Restore original sections to content box in correct order
+ const $contentBox = $('.rpg-content-box');
+
+ // Re-insert sections in original order: User Stats, Info Box, Thoughts, Inventory
+ if ($dividerStats.length) {
+ $dividerStats.before($userStats);
+ $dividerInfo.before($infoBox);
+ $dividerThoughts.before($thoughts);
+ $contentBox.append($inventory);
+ } else {
+ // Fallback if dividers don't exist
+ $contentBox.append($userStats);
+ $contentBox.append($infoBox);
+ $contentBox.append($thoughts);
+ $contentBox.append($inventory);
+ }
+
+ // Show sections and dividers
+ $userStats.show();
+ $infoBox.show();
+ $thoughts.show();
+ $inventory.show();
+ $('.rpg-divider').show();
+
+ console.log('[RPG Desktop] Desktop tabs removed');
+}
diff --git a/src/systems/ui/mobile.js b/src/systems/ui/mobile.js
index d109995..f2648b3 100644
--- a/src/systems/ui/mobile.js
+++ b/src/systems/ui/mobile.js
@@ -6,6 +6,7 @@
import { extensionSettings } from '../../core/state.js';
import { saveSettings } from '../../core/persistence.js';
import { closeMobilePanelWithAnimation, updateCollapseToggleIcon } from './layout.js';
+import { setupDesktopTabs, removeDesktopTabs } from './desktop.js';
/**
* Sets up the mobile toggle button (FAB) with drag functionality.
@@ -331,6 +332,9 @@ export function setupMobileToggle() {
if (!wasMobile && isMobile) {
console.log('[RPG Mobile] Transitioning desktop -> mobile');
+ // Remove desktop tabs first
+ removeDesktopTabs();
+
// Remove desktop positioning classes
$panel.removeClass('rpg-position-right rpg-position-left rpg-position-top');
@@ -384,6 +388,9 @@ export function setupMobileToggle() {
// Remove mobile tabs structure
removeMobileTabs();
+ // Setup desktop tabs
+ setupDesktopTabs();
+
// Force reflow to apply position instantly
$panel[0].offsetHeight;
@@ -519,54 +526,59 @@ export function setupMobileTabs() {
return;
}
- // Create tab navigation (only show tabs for sections that exist)
+ // Create tab navigation (3 tabs for mobile)
const tabs = [];
- const hasInfoOrCharacters = $infoBox.length > 0 || $thoughts.length > 0;
- const hasStatsOrInventory = $userStats.length > 0 || $inventory.length > 0;
+ const hasStats = $userStats.length > 0;
+ const hasInfo = $infoBox.length > 0 || $thoughts.length > 0;
+ const hasInventory = $inventory.length > 0;
- if (hasStatsOrInventory) {
+ // Tab 1: Stats (User Stats only)
+ if (hasStats) {
tabs.push('');
}
- // Combine Info and Characters into one tab
- if (hasInfoOrCharacters) {
- tabs.push('');
+ // Tab 2: Info (Info Box + Character Thoughts)
+ if (hasInfo) {
+ tabs.push('');
+ }
+ // Tab 3: Inventory
+ if (hasInventory) {
+ tabs.push('');
}
const $tabNav = $('' + tabs.join('') + '
');
// Determine which tab should be active
let firstTab = '';
- if (hasStatsOrInventory) firstTab = 'stats';
- else if (hasInfoOrCharacters) firstTab = 'info-characters';
+ if (hasStats) firstTab = 'stats';
+ else if (hasInfo) firstTab = 'info';
+ else if (hasInventory) firstTab = 'inventory';
// Create tab content wrappers
const $statsTab = $('');
- const $infoCharactersTab = $('');
-
- // Create combined content wrapper for Info and Characters
- const $combinedWrapper = $('');
+ const $infoTab = $('');
+ const $inventoryTab = $('');
// Move sections into their respective tabs (detach to preserve event handlers)
+ // Stats tab: User Stats only
if ($userStats.length > 0) {
$statsTab.append($userStats.detach());
$userStats.show();
}
- if ($inventory.length > 0) {
- $statsTab.append($inventory.detach());
- $inventory.show();
- }
+
+ // Info tab: Info Box + Character Thoughts
if ($infoBox.length > 0) {
- $combinedWrapper.append($infoBox.detach());
+ $infoTab.append($infoBox.detach());
$infoBox.show();
}
if ($thoughts.length > 0) {
- $combinedWrapper.append($thoughts.detach());
+ $infoTab.append($thoughts.detach());
$thoughts.show();
}
- // Add combined wrapper to the info-characters tab
- if (hasInfoOrCharacters) {
- $infoCharactersTab.append($combinedWrapper);
+ // Inventory tab: Inventory only
+ if ($inventory.length > 0) {
+ $inventoryTab.append($inventory.detach());
+ $inventory.show();
}
// Hide dividers on mobile
@@ -577,8 +589,9 @@ export function setupMobileTabs() {
$mobileContainer.append($tabNav);
// Only append tab content wrappers that have content
- if (hasStatsOrInventory) $mobileContainer.append($statsTab);
- if (hasInfoOrCharacters) $mobileContainer.append($infoCharactersTab);
+ if (hasStats) $mobileContainer.append($statsTab);
+ if (hasInfo) $mobileContainer.append($infoTab);
+ if (hasInventory) $mobileContainer.append($inventoryTab);
// Insert mobile tab structure at the beginning of content box
$contentBox.prepend($mobileContainer);
diff --git a/style.css b/style.css
index 8ebe3b8..2db615f 100644
--- a/style.css
+++ b/style.css
@@ -4109,6 +4109,81 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
color: white;
}
+/* ============================================
+ DESKTOP TABS SYSTEM
+ ============================================ */
+
+/* Desktop tabs container */
+.rpg-tabs-container {
+ display: flex;
+ flex-direction: column;
+ gap: 0;
+ height: 100%;
+ width: 100%;
+}
+
+/* Desktop tab navigation */
+.rpg-tabs-nav {
+ display: flex;
+ gap: 0;
+ background: var(--SmartThemeBlurTintColor);
+ border-bottom: 2px solid var(--SmartThemeBorderColor);
+ margin-bottom: 1rem;
+}
+
+/* Desktop tab button */
+.rpg-tab-btn {
+ flex: 1;
+ padding: 0.75rem 1rem;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 0.5rem;
+ font-size: 0.95rem;
+ font-weight: 500;
+ color: var(--SmartThemeBodyColor);
+ background: transparent;
+ border: none;
+ border-bottom: 3px solid transparent;
+ cursor: pointer;
+ transition: all 0.2s ease;
+}
+
+.rpg-tab-btn:hover {
+ background: var(--SmartThemeQuoteColor);
+ color: var(--ac-style-color-matchedText);
+}
+
+.rpg-tab-btn.active {
+ background: var(--SmartThemeQuoteColor);
+ border-bottom-color: var(--ac-style-color-matchedText);
+ color: var(--ac-style-color-matchedText);
+}
+
+.rpg-tab-btn i {
+ font-size: 1.1rem;
+}
+
+/* Desktop tab content */
+.rpg-tab-content {
+ display: none;
+ flex-direction: column;
+ gap: 1rem;
+ overflow-y: auto;
+ overflow-x: hidden;
+ padding: 0 0.5rem;
+ flex: 1;
+}
+
+.rpg-tab-content.active {
+ display: flex;
+}
+
+/* Hide dividers when tabs are active (tabs separate content) */
+.rpg-tabs-container .rpg-divider {
+ display: none;
+}
+
/* Mobile Responsive Styles */
@media (max-width: 768px) {
.rpg-inventory-subtabs {