feat: implement comprehensive mobile UX for RPG Companion panel
- Add bottom-sliding drawer system for mobile (≤1000px viewport) - Implement tabbed navigation with Stats and Info & Characters tabs - Combine Info Box and Present Characters into single tab with 50/50 split - Add smooth transitions between desktop and mobile layouts - Reposition collapse button as close button on mobile - Implement FAB toggle button for opening mobile drawer Mobile Stats Tab: - Use CSS Grid layout for efficient space utilization - Portrait centered at top, stat bars below - Inventory and mood on left, attributes list on right - Convert attributes from 3x2 grid to vertical list Mobile Info Box: - Scale dashboard widgets to fill allocated space - Proportional row heights (60% top row, 40% location) - Widgets expand to fill available vertical space Technical improvements: - Bottom-based drawer positioning instead of transform - CSS-only transitions, JavaScript only toggles classes - Instant tab setup on desktop→mobile for smooth transition - Temporary transition disabling for mobile→desktop snap - Proper flex hierarchy for space filling
This commit is contained in:
@@ -1010,6 +1010,211 @@ function setupMobileToggle() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle viewport resize to manage desktop/mobile transitions
|
||||||
|
let wasMobile = window.innerWidth <= 1000;
|
||||||
|
let resizeTimer;
|
||||||
|
|
||||||
|
$(window).on('resize', function() {
|
||||||
|
clearTimeout(resizeTimer);
|
||||||
|
|
||||||
|
const isMobile = window.innerWidth <= 1000;
|
||||||
|
const $panel = $('#rpg-companion-panel');
|
||||||
|
const $mobileToggle = $('#rpg-mobile-toggle');
|
||||||
|
|
||||||
|
// Transitioning from desktop to mobile - handle immediately for smooth transition
|
||||||
|
if (!wasMobile && isMobile) {
|
||||||
|
// Remove desktop positioning classes
|
||||||
|
$panel.removeClass('rpg-position-right rpg-position-left rpg-position-top');
|
||||||
|
|
||||||
|
// Clear collapsed state - mobile doesn't use collapse
|
||||||
|
$panel.removeClass('rpg-collapsed');
|
||||||
|
|
||||||
|
// Close panel on mobile - CSS handles smooth transition
|
||||||
|
$panel.removeClass('rpg-mobile-open');
|
||||||
|
$mobileToggle.removeClass('active');
|
||||||
|
$('.rpg-mobile-overlay').remove();
|
||||||
|
|
||||||
|
// Set up mobile tabs IMMEDIATELY (no debounce delay)
|
||||||
|
setupMobileTabs();
|
||||||
|
|
||||||
|
wasMobile = isMobile;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For mobile to desktop transition, use debounce
|
||||||
|
resizeTimer = setTimeout(function() {
|
||||||
|
const isMobile = window.innerWidth <= 1000;
|
||||||
|
|
||||||
|
// Transitioning from mobile to desktop
|
||||||
|
if (wasMobile && !isMobile) {
|
||||||
|
// Disable transitions to prevent left→right slide animation
|
||||||
|
$panel.css('transition', 'none');
|
||||||
|
|
||||||
|
$panel.removeClass('rpg-mobile-open');
|
||||||
|
$mobileToggle.removeClass('active');
|
||||||
|
$('.rpg-mobile-overlay').remove();
|
||||||
|
|
||||||
|
// Restore desktop positioning class
|
||||||
|
const position = extensionSettings.panelPosition || 'right';
|
||||||
|
$panel.addClass('rpg-position-' + position);
|
||||||
|
|
||||||
|
// Remove mobile tabs structure
|
||||||
|
removeMobileTabs();
|
||||||
|
|
||||||
|
// Force reflow to apply position instantly
|
||||||
|
$panel[0].offsetHeight;
|
||||||
|
|
||||||
|
// Re-enable transitions after positioned
|
||||||
|
setTimeout(function() {
|
||||||
|
$panel.css('transition', '');
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
wasMobile = isMobile;
|
||||||
|
}, 150); // Debounce only for mobile→desktop
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize mobile tabs if starting on mobile
|
||||||
|
const isMobile = window.innerWidth <= 1000;
|
||||||
|
if (isMobile) {
|
||||||
|
setupMobileTabs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up mobile tab navigation for organizing content.
|
||||||
|
* Only runs on mobile viewports (<=1000px).
|
||||||
|
*/
|
||||||
|
function setupMobileTabs() {
|
||||||
|
const isMobile = window.innerWidth <= 1000;
|
||||||
|
if (!isMobile) return;
|
||||||
|
|
||||||
|
// Check if tabs already exist
|
||||||
|
if ($('.rpg-mobile-tabs').length > 0) return;
|
||||||
|
|
||||||
|
const $panel = $('#rpg-companion-panel');
|
||||||
|
const $contentBox = $panel.find('.rpg-content-box');
|
||||||
|
|
||||||
|
// Get existing sections
|
||||||
|
const $userStats = $('#rpg-user-stats');
|
||||||
|
const $infoBox = $('#rpg-info-box');
|
||||||
|
const $thoughts = $('#rpg-thoughts');
|
||||||
|
|
||||||
|
// If no sections exist, nothing to organize
|
||||||
|
if ($userStats.length === 0 && $infoBox.length === 0 && $thoughts.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create tab navigation (only show tabs for sections that exist)
|
||||||
|
const tabs = [];
|
||||||
|
const hasInfoOrCharacters = $infoBox.length > 0 || $thoughts.length > 0;
|
||||||
|
|
||||||
|
if ($userStats.length > 0) {
|
||||||
|
tabs.push('<button class="rpg-mobile-tab active" data-tab="stats"><i class="fa-solid fa-chart-bar"></i><span>Stats</span></button>');
|
||||||
|
}
|
||||||
|
// Combine Info and Characters into one tab
|
||||||
|
if (hasInfoOrCharacters) {
|
||||||
|
tabs.push('<button class="rpg-mobile-tab ' + (tabs.length === 0 ? 'active' : '') + '" data-tab="info-characters"><i class="fa-solid fa-book"></i><span>Info & Characters</span></button>');
|
||||||
|
}
|
||||||
|
|
||||||
|
const $tabNav = $('<div class="rpg-mobile-tabs">' + tabs.join('') + '</div>');
|
||||||
|
|
||||||
|
// Determine which tab should be active
|
||||||
|
let firstTab = '';
|
||||||
|
if ($userStats.length > 0) firstTab = 'stats';
|
||||||
|
else if (hasInfoOrCharacters) firstTab = 'info-characters';
|
||||||
|
|
||||||
|
// Create tab content wrappers
|
||||||
|
const $statsTab = $('<div class="rpg-mobile-tab-content ' + (firstTab === 'stats' ? 'active' : '') + '" data-tab-content="stats"></div>');
|
||||||
|
const $infoCharactersTab = $('<div class="rpg-mobile-tab-content ' + (firstTab === 'info-characters' ? 'active' : '') + '" data-tab-content="info-characters"></div>');
|
||||||
|
|
||||||
|
// Create combined content wrapper for Info and Characters
|
||||||
|
const $combinedWrapper = $('<div class="rpg-mobile-combined-content"></div>');
|
||||||
|
|
||||||
|
// Move sections into their respective tabs (detach to preserve event handlers)
|
||||||
|
if ($userStats.length > 0) {
|
||||||
|
$statsTab.append($userStats.detach());
|
||||||
|
$userStats.show();
|
||||||
|
}
|
||||||
|
if ($infoBox.length > 0) {
|
||||||
|
$combinedWrapper.append($infoBox.detach());
|
||||||
|
$infoBox.show();
|
||||||
|
}
|
||||||
|
if ($thoughts.length > 0) {
|
||||||
|
$combinedWrapper.append($thoughts.detach());
|
||||||
|
$thoughts.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add combined wrapper to the info-characters tab
|
||||||
|
if (hasInfoOrCharacters) {
|
||||||
|
$infoCharactersTab.append($combinedWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide dividers on mobile
|
||||||
|
$('.rpg-divider').hide();
|
||||||
|
|
||||||
|
// Build mobile tab structure
|
||||||
|
const $mobileContainer = $('<div class="rpg-mobile-container"></div>');
|
||||||
|
$mobileContainer.append($tabNav);
|
||||||
|
|
||||||
|
// Only append tab content wrappers that have content
|
||||||
|
if ($userStats.length > 0) $mobileContainer.append($statsTab);
|
||||||
|
if (hasInfoOrCharacters) $mobileContainer.append($infoCharactersTab);
|
||||||
|
|
||||||
|
// Insert mobile tab structure at the beginning of content box
|
||||||
|
$contentBox.prepend($mobileContainer);
|
||||||
|
|
||||||
|
// Handle tab switching
|
||||||
|
$tabNav.find('.rpg-mobile-tab').on('click', function() {
|
||||||
|
const tabName = $(this).data('tab');
|
||||||
|
|
||||||
|
// Update active tab button
|
||||||
|
$tabNav.find('.rpg-mobile-tab').removeClass('active');
|
||||||
|
$(this).addClass('active');
|
||||||
|
|
||||||
|
// Update active tab content
|
||||||
|
$mobileContainer.find('.rpg-mobile-tab-content').removeClass('active');
|
||||||
|
$mobileContainer.find('[data-tab-content="' + tabName + '"]').addClass('active');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes mobile tab navigation and restores desktop layout.
|
||||||
|
*/
|
||||||
|
function removeMobileTabs() {
|
||||||
|
// Get sections from tabs before removing
|
||||||
|
const $userStats = $('#rpg-user-stats').detach();
|
||||||
|
const $infoBox = $('#rpg-info-box').detach();
|
||||||
|
const $thoughts = $('#rpg-thoughts').detach();
|
||||||
|
|
||||||
|
// Remove mobile tab container
|
||||||
|
$('.rpg-mobile-container').remove();
|
||||||
|
|
||||||
|
// Get dividers
|
||||||
|
const $dividerStats = $('#rpg-divider-stats');
|
||||||
|
const $dividerInfo = $('#rpg-divider-info');
|
||||||
|
|
||||||
|
// Restore original sections to content box in correct order
|
||||||
|
const $contentBox = $('.rpg-content-box');
|
||||||
|
|
||||||
|
// Re-insert sections in original order
|
||||||
|
if ($dividerStats.length) {
|
||||||
|
$dividerStats.before($userStats);
|
||||||
|
$dividerInfo.before($infoBox);
|
||||||
|
$contentBox.append($thoughts);
|
||||||
|
} else {
|
||||||
|
// Fallback if dividers don't exist
|
||||||
|
$contentBox.prepend($thoughts);
|
||||||
|
$contentBox.prepend($infoBox);
|
||||||
|
$contentBox.prepend($userStats);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show sections and dividers
|
||||||
|
$userStats.show();
|
||||||
|
$infoBox.show();
|
||||||
|
$thoughts.show();
|
||||||
|
$('.rpg-divider').show();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1021,6 +1226,17 @@ function setupCollapseToggle() {
|
|||||||
const $icon = $collapseToggle.find('i');
|
const $icon = $collapseToggle.find('i');
|
||||||
|
|
||||||
$collapseToggle.on('click', function() {
|
$collapseToggle.on('click', function() {
|
||||||
|
const isMobile = window.innerWidth <= 1000;
|
||||||
|
|
||||||
|
// On mobile: button acts as close button for mobile panel
|
||||||
|
if (isMobile) {
|
||||||
|
$panel.removeClass('rpg-mobile-open');
|
||||||
|
$('.rpg-mobile-overlay').remove();
|
||||||
|
$('#rpg-mobile-toggle').removeClass('active');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Desktop behavior: collapse/expand side panel
|
||||||
const isCollapsed = $panel.hasClass('rpg-collapsed');
|
const isCollapsed = $panel.hasClass('rpg-collapsed');
|
||||||
|
|
||||||
if (isCollapsed) {
|
if (isCollapsed) {
|
||||||
|
|||||||
@@ -2974,8 +2974,12 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
|||||||
backdrop-filter: blur(2px);
|
backdrop-filter: blur(2px);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mobile-specific panel behavior */
|
/* Mobile-specific panel behavior - matches SillyTavern's 1000px breakpoint */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 1000px) {
|
||||||
|
/* ========================================
|
||||||
|
MOBILE PANEL FOUNDATION
|
||||||
|
======================================== */
|
||||||
|
|
||||||
/* Show the FAB on mobile */
|
/* Show the FAB on mobile */
|
||||||
.rpg-mobile-toggle {
|
.rpg-mobile-toggle {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -2988,32 +2992,388 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hide panel by default on mobile */
|
/* Remove margin adjustments on mobile - content takes full width */
|
||||||
|
body:has(.rpg-panel) #sheld {
|
||||||
|
margin-right: 0 !important;
|
||||||
|
margin-left: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CLEAN SLATE: Reset ALL desktop positioning */
|
||||||
.rpg-panel {
|
.rpg-panel {
|
||||||
transform: translateY(100%);
|
position: fixed !important;
|
||||||
transition: transform 0.3s ease-in-out;
|
left: 0 !important;
|
||||||
}
|
right: 0 !important;
|
||||||
|
top: auto !important;
|
||||||
/* Show panel when opened */
|
width: 100dvw !important;
|
||||||
.rpg-panel.rpg-mobile-open {
|
max-width: 100dvw !important;
|
||||||
transform: translateY(0);
|
min-width: unset !important;
|
||||||
z-index: 999;
|
height: calc(100dvh - var(--topBarBlockSize)) !important;
|
||||||
}
|
max-height: calc(100dvh - var(--topBarBlockSize)) !important;
|
||||||
|
border-radius: 20px 20px 0 0;
|
||||||
/* On mobile, panel is always at bottom */
|
overflow-y: auto;
|
||||||
.rpg-panel.rpg-position-right,
|
|
||||||
.rpg-panel.rpg-position-left,
|
|
||||||
.rpg-panel.rpg-position-top {
|
|
||||||
position: fixed;
|
|
||||||
top: var(--topBarBlockSize);
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 100%;
|
|
||||||
border-radius: 1.25em 1.25em 0 0;
|
|
||||||
overflow-y: scroll;
|
|
||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
|
box-shadow: 0 -5px 20px var(--rpg-shadow);
|
||||||
|
border-left: 1px solid var(--SmartThemeBorderColor);
|
||||||
|
border-right: 1px solid var(--SmartThemeBorderColor);
|
||||||
|
border-top: 1px solid var(--SmartThemeBorderColor);
|
||||||
|
backdrop-filter: blur(calc(var(--SmartThemeBlurStrength) * 2));
|
||||||
|
|
||||||
|
/* DRAWER POSITIONING: Starts below viewport */
|
||||||
|
bottom: calc(-100dvh + var(--topBarBlockSize));
|
||||||
|
|
||||||
|
/* ONLY transition bottom property */
|
||||||
|
transition: bottom 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Show panel when opened - slides up */
|
||||||
|
.rpg-panel.rpg-mobile-open {
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable collapsed state on mobile */
|
||||||
|
.rpg-panel.rpg-collapsed {
|
||||||
|
max-width: 100dvw !important;
|
||||||
|
min-width: unset !important;
|
||||||
|
width: 100dvw !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rpg-panel.rpg-collapsed .rpg-game-container {
|
||||||
|
opacity: 1 !important;
|
||||||
|
pointer-events: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reposition collapse toggle on mobile as close button inside panel */
|
||||||
|
.rpg-collapse-toggle {
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
position: absolute;
|
||||||
|
top: 12px;
|
||||||
|
right: 12px;
|
||||||
|
left: auto !important;
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
min-width: 44px;
|
||||||
|
min-height: 44px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--SmartThemeBlurTintColor);
|
||||||
|
border: 2px solid var(--SmartThemeBorderColor);
|
||||||
|
z-index: 100;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
transform: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rpg-collapse-toggle:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
transform: scale(1.05) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rpg-collapse-toggle:active {
|
||||||
|
transform: scale(0.95) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Change icon to X on mobile */
|
||||||
|
.rpg-collapse-toggle i {
|
||||||
|
transform: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rpg-collapse-toggle i::before {
|
||||||
|
content: "\f00d" !important; /* fa-times (X icon) */
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================
|
||||||
|
MOBILE TAB NAVIGATION
|
||||||
|
======================================== */
|
||||||
|
|
||||||
|
/* Mobile tab container wrapper */
|
||||||
|
.rpg-mobile-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 0;
|
||||||
|
margin: -12px -12px 16px -12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tab container at top of panel */
|
||||||
|
.rpg-mobile-tabs {
|
||||||
|
display: flex;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 10;
|
||||||
|
background: var(--SmartThemeBlurTintColor);
|
||||||
|
backdrop-filter: blur(calc(var(--SmartThemeBlurStrength) * 1.5));
|
||||||
|
border-bottom: 2px solid var(--SmartThemeBorderColor);
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rpg-mobile-tab {
|
||||||
|
flex: 1;
|
||||||
|
height: 44px;
|
||||||
|
min-height: 44px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--SmartThemeBodyColor);
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
border-bottom: 3px solid transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
padding: 0 8px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rpg-mobile-tab:active {
|
||||||
|
transform: scale(0.97);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rpg-mobile-tab.active {
|
||||||
|
color: var(--SmartThemeQuoteColor);
|
||||||
|
border-bottom-color: var(--SmartThemeQuoteColor);
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rpg-mobile-tab i {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tab content sections */
|
||||||
|
.rpg-mobile-tab-content {
|
||||||
|
display: none;
|
||||||
|
animation: fadeIn 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rpg-mobile-tab-content.active {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from { opacity: 0; transform: translateY(10px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Combined Info & Characters wrapper */
|
||||||
|
.rpg-mobile-combined-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Info Box takes fixed 50% of vertical space */
|
||||||
|
.rpg-mobile-combined-content > #rpg-info-box {
|
||||||
|
flex: 0 0 50%;
|
||||||
|
min-height: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-bottom: 16px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Characters section takes remaining 50% */
|
||||||
|
.rpg-mobile-combined-content > #rpg-thoughts {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add divider between Info and Characters */
|
||||||
|
.rpg-mobile-combined-content > .rpg-section:not(:last-child) {
|
||||||
|
border-bottom: 1px solid var(--SmartThemeBorderColor);
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide dividers on mobile (tabs handle separation) */
|
||||||
|
.rpg-divider {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================
|
||||||
|
MOBILE INFO BOX IMPROVEMENTS
|
||||||
|
======================================== */
|
||||||
|
|
||||||
|
/* Rows scale proportionally to fill Info Box */
|
||||||
|
.rpg-dashboard-row-1 {
|
||||||
|
flex: 1.2 !important; /* Slightly more space for 4 widgets */
|
||||||
|
display: flex !important;
|
||||||
|
gap: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rpg-dashboard-row-2 {
|
||||||
|
flex: 0.8 !important; /* Less space for 1 widget */
|
||||||
|
display: flex !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Widgets fill their row height */
|
||||||
|
.rpg-dashboard-row-1 .rpg-dashboard-widget,
|
||||||
|
.rpg-dashboard-row-2 .rpg-dashboard-widget {
|
||||||
|
height: 100% !important;
|
||||||
|
flex: 1 !important;
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: column !important;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================
|
||||||
|
MOBILE STATS TAB LAYOUT IMPROVEMENTS
|
||||||
|
======================================== */
|
||||||
|
|
||||||
|
/* Make the entire stats section a grid */
|
||||||
|
.rpg-stats-section {
|
||||||
|
display: grid !important;
|
||||||
|
grid-template-columns: 40% 60%; /* Left for inventory/mood, right for attributes */
|
||||||
|
grid-template-rows: auto auto auto auto; /* Portrait, stat bars, inventory, mood */
|
||||||
|
gap: 12px;
|
||||||
|
padding: 16px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use display: contents so children participate in grid */
|
||||||
|
.rpg-stats-header,
|
||||||
|
.rpg-stats-content {
|
||||||
|
display: contents !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Portrait row - centered at top, full width */
|
||||||
|
.rpg-stats-header-left {
|
||||||
|
grid-column: 1 / 3;
|
||||||
|
grid-row: 1;
|
||||||
|
display: flex !important;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rpg-user-portrait {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide stats title on mobile */
|
||||||
|
.rpg-stats-title {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stat bars row - full width */
|
||||||
|
.rpg-stats-left {
|
||||||
|
grid-column: 1 / 3;
|
||||||
|
grid-row: 2;
|
||||||
|
display: contents !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rpg-stats-grid {
|
||||||
|
grid-column: 1 / 3;
|
||||||
|
grid-row: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inventory - bottom left */
|
||||||
|
.rpg-inventory-box {
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 3;
|
||||||
|
margin: 0;
|
||||||
|
min-height: auto;
|
||||||
|
max-height: none;
|
||||||
|
max-width: 100%; /* Override 12.5rem restriction */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mood - below inventory on left */
|
||||||
|
.rpg-mood {
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 4;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attributes - right side, spanning rows 3-4 */
|
||||||
|
.rpg-stats-right {
|
||||||
|
grid-column: 2;
|
||||||
|
grid-row: 3 / 5;
|
||||||
|
display: contents !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rpg-classic-stats {
|
||||||
|
grid-column: 2;
|
||||||
|
grid-row: 3 / 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attributes as vertical list instead of grid */
|
||||||
|
.rpg-classic-stats-grid {
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: column !important;
|
||||||
|
gap: 10px;
|
||||||
|
margin: 12px 0;
|
||||||
|
grid-template-columns: none !important;
|
||||||
|
grid-template-rows: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Each attribute as horizontal row */
|
||||||
|
.rpg-classic-stat {
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: row !important;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 12px 16px;
|
||||||
|
gap: 12px;
|
||||||
|
min-height: auto;
|
||||||
|
height: auto;
|
||||||
|
background: var(--SmartThemeBlurTintColor);
|
||||||
|
border: 1px solid var(--SmartThemeBorderColor);
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Label on left */
|
||||||
|
.rpg-classic-stat-label {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
min-width: 50px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Value in middle */
|
||||||
|
.rpg-classic-stat-value {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--SmartThemeQuoteColor);
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Buttons on right */
|
||||||
|
.rpg-classic-stat-controls {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rpg-classic-stat-btn {
|
||||||
|
min-width: 40px !important;
|
||||||
|
min-height: 40px !important;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user