Merge pull request #2 from paperboygold/fix/refresh-button-placement
fix: refresh button placement
This commit is contained in:
@@ -98,7 +98,8 @@ import {
|
|||||||
setupMobileTabs,
|
setupMobileTabs,
|
||||||
removeMobileTabs,
|
removeMobileTabs,
|
||||||
setupMobileKeyboardHandling,
|
setupMobileKeyboardHandling,
|
||||||
setupContentEditableScrolling
|
setupContentEditableScrolling,
|
||||||
|
setupRefreshButtonDrag
|
||||||
} from './src/systems/ui/mobile.js';
|
} from './src/systems/ui/mobile.js';
|
||||||
import {
|
import {
|
||||||
setupDesktopTabs,
|
setupDesktopTabs,
|
||||||
@@ -209,6 +210,14 @@ async function initUI() {
|
|||||||
`;
|
`;
|
||||||
$('body').append(mobileToggleHtml);
|
$('body').append(mobileToggleHtml);
|
||||||
|
|
||||||
|
// Add mobile refresh button (same pattern as toggle button)
|
||||||
|
const mobileRefreshHtml = `
|
||||||
|
<button id="rpg-manual-update-mobile" class="rpg-mobile-refresh" title="Refresh RPG Info">
|
||||||
|
<i class="fa-solid fa-sync"></i>
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
$('body').append(mobileRefreshHtml);
|
||||||
|
|
||||||
// Cache UI elements using state setters
|
// Cache UI elements using state setters
|
||||||
setPanelContainer($('#rpg-companion-panel'));
|
setPanelContainer($('#rpg-companion-panel'));
|
||||||
setUserStatsContainer($('#rpg-user-stats'));
|
setUserStatsContainer($('#rpg-user-stats'));
|
||||||
@@ -297,12 +306,34 @@ async function initUI() {
|
|||||||
toggleAnimations();
|
toggleAnimations();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#rpg-manual-update').on('click', async function() {
|
// Bind to both desktop and mobile refresh buttons
|
||||||
|
$('#rpg-manual-update, #rpg-manual-update-mobile').on('click', async function() {
|
||||||
|
// Get mobile button reference
|
||||||
|
const $mobileBtn = $('#rpg-manual-update-mobile');
|
||||||
|
|
||||||
|
// Skip if we just finished dragging the mobile button
|
||||||
|
if ($mobileBtn.data('just-dragged')) {
|
||||||
|
console.log('[RPG Companion] Click blocked - just finished dragging refresh button');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!extensionSettings.enabled) {
|
if (!extensionSettings.enabled) {
|
||||||
// console.log('[RPG Companion] Extension is disabled. Please enable it in the Extensions tab.');
|
// console.log('[RPG Companion] Extension is disabled. Please enable it in the Extensions tab.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await updateRPGData(renderUserStats, renderInfoBox, renderThoughts, renderInventory);
|
|
||||||
|
// Remove focus to prevent sticky black state on mobile
|
||||||
|
$(this).blur();
|
||||||
|
|
||||||
|
// Add spinning animation to mobile button
|
||||||
|
$mobileBtn.addClass('spinning');
|
||||||
|
|
||||||
|
try {
|
||||||
|
await updateRPGData(renderUserStats, renderInfoBox, renderThoughts, renderInventory);
|
||||||
|
} finally {
|
||||||
|
// Remove spinning animation when done
|
||||||
|
$mobileBtn.removeClass('spinning');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#rpg-stat-bar-color-low').on('change', function() {
|
$('#rpg-stat-bar-color-low').on('change', function() {
|
||||||
@@ -422,6 +453,7 @@ async function initUI() {
|
|||||||
setupPlotButtons(sendPlotProgression);
|
setupPlotButtons(sendPlotProgression);
|
||||||
setupMobileKeyboardHandling();
|
setupMobileKeyboardHandling();
|
||||||
setupContentEditableScrolling();
|
setupContentEditableScrolling();
|
||||||
|
setupRefreshButtonDrag();
|
||||||
initInventoryEventListeners();
|
initInventoryEventListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,10 @@ export const defaultSettings = {
|
|||||||
top: 'calc(var(--topBarBlockSize) + 60px)',
|
top: 'calc(var(--topBarBlockSize) + 60px)',
|
||||||
right: '12px'
|
right: '12px'
|
||||||
}, // Saved position for mobile FAB button
|
}, // Saved position for mobile FAB button
|
||||||
|
mobileRefreshPosition: {
|
||||||
|
bottom: '80px',
|
||||||
|
right: '20px'
|
||||||
|
}, // Saved position for mobile refresh button
|
||||||
userStats: {
|
userStats: {
|
||||||
health: 100,
|
health: 100,
|
||||||
satiety: 100,
|
satiety: 100,
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ export let extensionSettings = {
|
|||||||
top: 'calc(var(--topBarBlockSize) + 60px)',
|
top: 'calc(var(--topBarBlockSize) + 60px)',
|
||||||
right: '12px'
|
right: '12px'
|
||||||
}, // Saved position for mobile FAB button
|
}, // Saved position for mobile FAB button
|
||||||
|
mobileRefreshPosition: {
|
||||||
|
bottom: '80px',
|
||||||
|
right: '20px'
|
||||||
|
}, // Saved position for mobile refresh button
|
||||||
userStats: {
|
userStats: {
|
||||||
health: 100,
|
health: 100,
|
||||||
satiety: 100,
|
satiety: 100,
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ export function closeMobilePanelWithAnimation() {
|
|||||||
$panel.removeClass('rpg-mobile-open').addClass('rpg-mobile-closing');
|
$panel.removeClass('rpg-mobile-open').addClass('rpg-mobile-closing');
|
||||||
$mobileToggle.removeClass('active');
|
$mobileToggle.removeClass('active');
|
||||||
|
|
||||||
|
// Trigger event for other components (like refresh button)
|
||||||
|
$(document).trigger('rpg-panel-toggled', { isOpen: false });
|
||||||
|
|
||||||
// Wait for animation to complete before hiding
|
// Wait for animation to complete before hiding
|
||||||
$panel.one('animationend', function() {
|
$panel.one('animationend', function() {
|
||||||
$panel.removeClass('rpg-mobile-closing');
|
$panel.removeClass('rpg-mobile-closing');
|
||||||
@@ -127,6 +130,9 @@ export function setupCollapseToggle() {
|
|||||||
const $overlay = $('<div class="rpg-mobile-overlay"></div>');
|
const $overlay = $('<div class="rpg-mobile-overlay"></div>');
|
||||||
$('body').append($overlay);
|
$('body').append($overlay);
|
||||||
|
|
||||||
|
// Trigger event for other components (like refresh button)
|
||||||
|
$(document).trigger('rpg-panel-toggled', { isOpen: true });
|
||||||
|
|
||||||
// Debug: Check state after animation should complete
|
// Debug: Check state after animation should complete
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
console.log('[RPG Mobile] 500ms after opening:', {
|
console.log('[RPG Mobile] 500ms after opening:', {
|
||||||
@@ -267,10 +273,13 @@ export function applyPanelPosition() {
|
|||||||
*/
|
*/
|
||||||
export function updateGenerationModeUI() {
|
export function updateGenerationModeUI() {
|
||||||
if (extensionSettings.generationMode === 'together') {
|
if (extensionSettings.generationMode === 'together') {
|
||||||
// In "together" mode, manual update button is hidden
|
// In "together" mode, hide both update buttons
|
||||||
$('#rpg-manual-update').hide();
|
$('#rpg-manual-update').hide();
|
||||||
|
$('#rpg-manual-update-mobile').hide();
|
||||||
} else {
|
} else {
|
||||||
// In "separate" mode, manual update button is visible
|
// In "separate" mode, show both buttons
|
||||||
|
// (CSS media queries control which one is visible based on viewport)
|
||||||
$('#rpg-manual-update').show();
|
$('#rpg-manual-update').show();
|
||||||
|
$('#rpg-manual-update-mobile').show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+243
-12
@@ -278,6 +278,9 @@ export function setupMobileToggle() {
|
|||||||
$('body').append($overlay);
|
$('body').append($overlay);
|
||||||
$mobileToggle.addClass('active');
|
$mobileToggle.addClass('active');
|
||||||
|
|
||||||
|
// Trigger event for other components (like refresh button)
|
||||||
|
$(document).trigger('rpg-panel-toggled', { isOpen: true });
|
||||||
|
|
||||||
// Close when clicking overlay
|
// Close when clicking overlay
|
||||||
$overlay.on('click', function() {
|
$overlay.on('click', function() {
|
||||||
closeMobilePanelWithAnimation();
|
closeMobilePanelWithAnimation();
|
||||||
@@ -310,6 +313,9 @@ export function setupMobileToggle() {
|
|||||||
$('body').append($overlay);
|
$('body').append($overlay);
|
||||||
$mobileToggle.addClass('active');
|
$mobileToggle.addClass('active');
|
||||||
|
|
||||||
|
// Trigger event for other components (like refresh button)
|
||||||
|
$(document).trigger('rpg-panel-toggled', { isOpen: true });
|
||||||
|
|
||||||
$overlay.on('click', function() {
|
$overlay.on('click', function() {
|
||||||
console.log('[RPG Mobile] Overlay clicked - closing panel');
|
console.log('[RPG Mobile] Overlay clicked - closing panel');
|
||||||
closeMobilePanelWithAnimation();
|
closeMobilePanelWithAnimation();
|
||||||
@@ -434,32 +440,41 @@ export function setupMobileToggle() {
|
|||||||
* Constrains the mobile FAB button to viewport bounds with top-bar awareness.
|
* Constrains the mobile FAB button to viewport bounds with top-bar awareness.
|
||||||
* Only runs when button is in user-controlled state (mobileFabPosition exists).
|
* Only runs when button is in user-controlled state (mobileFabPosition exists).
|
||||||
* Ensures button never goes behind the top bar or outside viewport edges.
|
* Ensures button never goes behind the top bar or outside viewport edges.
|
||||||
|
* @param {jQuery} $button - Optional button element (defaults to mobile toggle)
|
||||||
*/
|
*/
|
||||||
export function constrainFabToViewport() {
|
export function constrainFabToViewport($button = null) {
|
||||||
|
// Default to mobile toggle if no button specified
|
||||||
|
if (!$button) {
|
||||||
|
$button = $('#rpg-mobile-toggle');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($button.length === 0) return;
|
||||||
|
|
||||||
|
// Determine which position setting to check based on button ID
|
||||||
|
const isRefreshButton = $button.attr('id') === 'rpg-manual-update-mobile';
|
||||||
|
const positionSetting = isRefreshButton ? 'mobileRefreshPosition' : 'mobileFabPosition';
|
||||||
|
|
||||||
// Only constrain if user has set a custom position
|
// Only constrain if user has set a custom position
|
||||||
if (!extensionSettings.mobileFabPosition) {
|
if (!extensionSettings[positionSetting]) {
|
||||||
console.log('[RPG Mobile] Skipping viewport constraint - using CSS defaults');
|
console.log('[RPG Mobile] Skipping viewport constraint - using CSS defaults');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const $mobileToggle = $('#rpg-mobile-toggle');
|
|
||||||
if ($mobileToggle.length === 0) return;
|
|
||||||
|
|
||||||
// Skip if button is not visible
|
// Skip if button is not visible
|
||||||
if (!$mobileToggle.is(':visible')) {
|
if (!$button.is(':visible')) {
|
||||||
console.log('[RPG Mobile] Skipping viewport constraint - button not visible');
|
console.log('[RPG Mobile] Skipping viewport constraint - button not visible');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get current position
|
// Get current position
|
||||||
const offset = $mobileToggle.offset();
|
const offset = $button.offset();
|
||||||
if (!offset) return;
|
if (!offset) return;
|
||||||
|
|
||||||
let currentX = offset.left;
|
let currentX = offset.left;
|
||||||
let currentY = offset.top;
|
let currentY = offset.top;
|
||||||
|
|
||||||
const buttonWidth = $mobileToggle.outerWidth();
|
const buttonWidth = $button.outerWidth();
|
||||||
const buttonHeight = $mobileToggle.outerHeight();
|
const buttonHeight = $button.outerHeight();
|
||||||
|
|
||||||
// Get top bar height from CSS variable (fallback to 50px if not set)
|
// Get top bar height from CSS variable (fallback to 50px if not set)
|
||||||
const topBarHeight = parseInt(getComputedStyle(document.documentElement).getPropertyValue('--topBarBlockSize')) || 50;
|
const topBarHeight = parseInt(getComputedStyle(document.documentElement).getPropertyValue('--topBarBlockSize')) || 50;
|
||||||
@@ -485,15 +500,15 @@ export function constrainFabToViewport() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Apply new position
|
// Apply new position
|
||||||
$mobileToggle.css({
|
$button.css({
|
||||||
left: newX + 'px',
|
left: newX + 'px',
|
||||||
top: newY + 'px',
|
top: newY + 'px',
|
||||||
right: 'auto',
|
right: 'auto',
|
||||||
bottom: 'auto'
|
bottom: 'auto'
|
||||||
});
|
});
|
||||||
|
|
||||||
// Save corrected position
|
// Save corrected position to appropriate setting
|
||||||
extensionSettings.mobileFabPosition = {
|
extensionSettings[positionSetting] = {
|
||||||
left: newX + 'px',
|
left: newX + 'px',
|
||||||
top: newY + 'px'
|
top: newY + 'px'
|
||||||
};
|
};
|
||||||
@@ -716,3 +731,219 @@ export function setupContentEditableScrolling() {
|
|||||||
}, 300);
|
}, 300);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the mobile refresh button with drag functionality.
|
||||||
|
* Same pattern as mobile toggle button.
|
||||||
|
* Tap = refresh, drag = reposition
|
||||||
|
*/
|
||||||
|
export function setupRefreshButtonDrag() {
|
||||||
|
const $refreshBtn = $('#rpg-manual-update-mobile');
|
||||||
|
|
||||||
|
if ($refreshBtn.length === 0) {
|
||||||
|
console.warn('[RPG Mobile] Refresh button not found in DOM');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('[RPG Mobile] setupRefreshButtonDrag called');
|
||||||
|
|
||||||
|
// Load and apply saved position
|
||||||
|
if (extensionSettings.mobileRefreshPosition) {
|
||||||
|
const pos = extensionSettings.mobileRefreshPosition;
|
||||||
|
console.log('[RPG Mobile] Loading saved refresh button position:', pos);
|
||||||
|
|
||||||
|
// Apply saved position
|
||||||
|
if (pos.top) $refreshBtn.css('top', pos.top);
|
||||||
|
if (pos.right) $refreshBtn.css('right', pos.right);
|
||||||
|
if (pos.bottom) $refreshBtn.css('bottom', pos.bottom);
|
||||||
|
if (pos.left) $refreshBtn.css('left', pos.left);
|
||||||
|
|
||||||
|
// Constrain to viewport after position is applied
|
||||||
|
requestAnimationFrame(() => constrainFabToViewport($refreshBtn));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Touch/drag state
|
||||||
|
let isDragging = false;
|
||||||
|
let touchStartTime = 0;
|
||||||
|
let touchStartX = 0;
|
||||||
|
let touchStartY = 0;
|
||||||
|
let buttonStartX = 0;
|
||||||
|
let buttonStartY = 0;
|
||||||
|
const LONG_PRESS_DURATION = 200;
|
||||||
|
const MOVE_THRESHOLD = 10;
|
||||||
|
let rafId = null;
|
||||||
|
let pendingX = null;
|
||||||
|
let pendingY = null;
|
||||||
|
|
||||||
|
// Update position using requestAnimationFrame
|
||||||
|
function updatePosition() {
|
||||||
|
if (pendingX !== null && pendingY !== null) {
|
||||||
|
$refreshBtn.css({
|
||||||
|
left: pendingX + 'px',
|
||||||
|
top: pendingY + 'px',
|
||||||
|
right: 'auto',
|
||||||
|
bottom: 'auto'
|
||||||
|
});
|
||||||
|
pendingX = null;
|
||||||
|
pendingY = null;
|
||||||
|
}
|
||||||
|
rafId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Touch start
|
||||||
|
$refreshBtn.on('touchstart', function(e) {
|
||||||
|
const touch = e.originalEvent.touches[0];
|
||||||
|
touchStartTime = Date.now();
|
||||||
|
touchStartX = touch.clientX;
|
||||||
|
touchStartY = touch.clientY;
|
||||||
|
|
||||||
|
const offset = $refreshBtn.offset();
|
||||||
|
buttonStartX = offset.left;
|
||||||
|
buttonStartY = offset.top;
|
||||||
|
|
||||||
|
isDragging = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Touch move
|
||||||
|
$refreshBtn.on('touchmove', function(e) {
|
||||||
|
const touch = e.originalEvent.touches[0];
|
||||||
|
const deltaX = touch.clientX - touchStartX;
|
||||||
|
const deltaY = touch.clientY - touchStartY;
|
||||||
|
const timeSinceStart = Date.now() - touchStartTime;
|
||||||
|
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||||
|
|
||||||
|
if (!isDragging && (timeSinceStart > LONG_PRESS_DURATION || distance > MOVE_THRESHOLD)) {
|
||||||
|
isDragging = true;
|
||||||
|
$refreshBtn.addClass('dragging');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDragging) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
let newX = buttonStartX + deltaX;
|
||||||
|
let newY = buttonStartY + deltaY;
|
||||||
|
|
||||||
|
const buttonWidth = $refreshBtn.outerWidth();
|
||||||
|
const buttonHeight = $refreshBtn.outerHeight();
|
||||||
|
|
||||||
|
const minX = 10;
|
||||||
|
const maxX = window.innerWidth - buttonWidth - 10;
|
||||||
|
const minY = 10;
|
||||||
|
const maxY = window.innerHeight - buttonHeight - 10;
|
||||||
|
|
||||||
|
newX = Math.max(minX, Math.min(maxX, newX));
|
||||||
|
newY = Math.max(minY, Math.min(maxY, newY));
|
||||||
|
|
||||||
|
pendingX = newX;
|
||||||
|
pendingY = newY;
|
||||||
|
if (!rafId) {
|
||||||
|
rafId = requestAnimationFrame(updatePosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Touch end
|
||||||
|
$refreshBtn.on('touchend', function(e) {
|
||||||
|
if (isDragging) {
|
||||||
|
// Save new position
|
||||||
|
const offset = $refreshBtn.offset();
|
||||||
|
const newPosition = {
|
||||||
|
left: offset.left + 'px',
|
||||||
|
top: offset.top + 'px'
|
||||||
|
};
|
||||||
|
|
||||||
|
extensionSettings.mobileRefreshPosition = newPosition;
|
||||||
|
saveSettings();
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
$refreshBtn.removeClass('dragging');
|
||||||
|
}, 50);
|
||||||
|
|
||||||
|
// Set flag to prevent click handler from firing
|
||||||
|
$refreshBtn.data('just-dragged', true);
|
||||||
|
setTimeout(() => {
|
||||||
|
$refreshBtn.data('just-dragged', false);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
isDragging = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mouse support for desktop
|
||||||
|
let mouseDown = false;
|
||||||
|
|
||||||
|
$refreshBtn.on('mousedown', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
touchStartTime = Date.now();
|
||||||
|
touchStartX = e.clientX;
|
||||||
|
touchStartY = e.clientY;
|
||||||
|
|
||||||
|
const offset = $refreshBtn.offset();
|
||||||
|
buttonStartX = offset.left;
|
||||||
|
buttonStartY = offset.top;
|
||||||
|
|
||||||
|
mouseDown = true;
|
||||||
|
isDragging = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('mousemove', function(e) {
|
||||||
|
if (!mouseDown) return;
|
||||||
|
|
||||||
|
const deltaX = e.clientX - touchStartX;
|
||||||
|
const deltaY = e.clientY - touchStartY;
|
||||||
|
const timeSinceStart = Date.now() - touchStartTime;
|
||||||
|
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||||
|
|
||||||
|
if (!isDragging && (timeSinceStart > LONG_PRESS_DURATION || distance > MOVE_THRESHOLD)) {
|
||||||
|
isDragging = true;
|
||||||
|
$refreshBtn.addClass('dragging');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDragging) {
|
||||||
|
let newX = buttonStartX + deltaX;
|
||||||
|
let newY = buttonStartY + deltaY;
|
||||||
|
|
||||||
|
const buttonWidth = $refreshBtn.outerWidth();
|
||||||
|
const buttonHeight = $refreshBtn.outerHeight();
|
||||||
|
|
||||||
|
const minX = 10;
|
||||||
|
const maxX = window.innerWidth - buttonWidth - 10;
|
||||||
|
const minY = 10;
|
||||||
|
const maxY = window.innerHeight - buttonHeight - 10;
|
||||||
|
|
||||||
|
newX = Math.max(minX, Math.min(maxX, newX));
|
||||||
|
newY = Math.max(minY, Math.min(maxY, newY));
|
||||||
|
|
||||||
|
pendingX = newX;
|
||||||
|
pendingY = newY;
|
||||||
|
if (!rafId) {
|
||||||
|
rafId = requestAnimationFrame(updatePosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('mouseup', function(e) {
|
||||||
|
if (mouseDown && isDragging) {
|
||||||
|
const offset = $refreshBtn.offset();
|
||||||
|
const newPosition = {
|
||||||
|
left: offset.left + 'px',
|
||||||
|
top: offset.top + 'px'
|
||||||
|
};
|
||||||
|
|
||||||
|
extensionSettings.mobileRefreshPosition = newPosition;
|
||||||
|
saveSettings();
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
$refreshBtn.removeClass('dragging');
|
||||||
|
}, 50);
|
||||||
|
|
||||||
|
$refreshBtn.data('just-dragged', true);
|
||||||
|
setTimeout(() => {
|
||||||
|
$refreshBtn.data('just-dragged', false);
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
mouseDown = false;
|
||||||
|
isDragging = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -744,7 +744,7 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
|||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--rpg-highlight-color);
|
color: var(--rpg-highlight-color);
|
||||||
padding: clamp(1px, 0.2vh, 2px) 0.375em;
|
padding: 0 0.375em;
|
||||||
background: var(--rpg-accent-color);
|
background: var(--rpg-accent-color);
|
||||||
border-radius: clamp(2px, 0.3vh, 3px);
|
border-radius: clamp(2px, 0.3vh, 3px);
|
||||||
border: 1px solid var(--rpg-highlight-color);
|
border: 1px solid var(--rpg-highlight-color);
|
||||||
@@ -2670,7 +2670,7 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================
|
/* ============================================
|
||||||
MANUAL UPDATE BUTTON
|
MANUAL UPDATE BUTTON (Desktop)
|
||||||
============================================ */
|
============================================ */
|
||||||
.rpg-manual-update-btn {
|
.rpg-manual-update-btn {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -2707,6 +2707,64 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
|||||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
MOBILE REFRESH BUTTON (FAB - Same pattern as toggle)
|
||||||
|
============================================ */
|
||||||
|
.rpg-mobile-refresh {
|
||||||
|
display: none;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
position: fixed;
|
||||||
|
/* Position set by JavaScript based on saved settings */
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--SmartThemeBlurTintColor);
|
||||||
|
border: 2px solid var(--SmartThemeBorderColor);
|
||||||
|
color: var(--rpg-text, #ecf0f1);
|
||||||
|
font-size: 1.85vw;
|
||||||
|
cursor: grab;
|
||||||
|
z-index: 1001; /* Above panel (1000) but below mobile toggle (10002) */
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||||
|
transition: opacity 0.3s ease, transform 0.2s ease, top 0.3s ease, left 0.3s ease, right 0.3s ease, bottom 0.3s ease;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
will-change: top, left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable transitions while actively dragging */
|
||||||
|
.rpg-mobile-refresh.dragging {
|
||||||
|
transition: none;
|
||||||
|
cursor: grabbing;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rpg-mobile-refresh:hover {
|
||||||
|
transform: scale(1.1);
|
||||||
|
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rpg-mobile-refresh:active {
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Spinning animation when refreshing */
|
||||||
|
.rpg-mobile-refresh.spinning i {
|
||||||
|
animation: rpg-spin 0.8s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rpg-mobile-refresh i {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rpg-spin {
|
||||||
|
from {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ============================================
|
/* ============================================
|
||||||
SETTINGS BUTTON
|
SETTINGS BUTTON
|
||||||
============================================ */
|
============================================ */
|
||||||
@@ -3292,6 +3350,31 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
|||||||
|
|
||||||
/* Mobile-specific panel behavior - matches SillyTavern's 1000px breakpoint */
|
/* Mobile-specific panel behavior - matches SillyTavern's 1000px breakpoint */
|
||||||
/* CACHE BUST v2025-01-16 */
|
/* CACHE BUST v2025-01-16 */
|
||||||
|
/* Mobile refresh button visibility - opposite of toggle */
|
||||||
|
@media (max-width: 1000px) {
|
||||||
|
/* Show mobile refresh button */
|
||||||
|
.rpg-mobile-refresh {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide desktop refresh button */
|
||||||
|
.rpg-manual-update-btn {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Show refresh button when panel is open (opposite of toggle) */
|
||||||
|
body:has(.rpg-panel.rpg-mobile-open) .rpg-mobile-refresh {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide refresh button when panel is closed */
|
||||||
|
.rpg-mobile-refresh {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 1000px) {
|
@media (max-width: 1000px) {
|
||||||
/* ========================================
|
/* ========================================
|
||||||
MOBILE PANEL FOUNDATION
|
MOBILE PANEL FOUNDATION
|
||||||
@@ -3616,6 +3699,9 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
|||||||
|
|
||||||
.rpg-calendar-day {
|
.rpg-calendar-day {
|
||||||
font-size: clamp(11px, 2.9vw, 14px) !important;
|
font-size: clamp(11px, 2.9vw, 14px) !important;
|
||||||
|
min-height: 3em !important; /* Ensure enough height for content to center */
|
||||||
|
padding: 0.75em 0.5em !important; /* More vertical padding on mobile */
|
||||||
|
line-height: 1.2 !important; /* Tighter line height */
|
||||||
}
|
}
|
||||||
|
|
||||||
.rpg-calendar-year {
|
.rpg-calendar-year {
|
||||||
@@ -3753,14 +3839,20 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
|||||||
grid-row: 3;
|
grid-row: 3;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 6px;
|
gap: 3px !important; /* Reduced from 6px for more compact display */
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
padding: 4px 0.375em !important; /* Reduced vertical padding */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make mood text readable on mobile */
|
/* Make mood text readable on mobile */
|
||||||
.rpg-mood-conditions {
|
.rpg-mood-conditions {
|
||||||
font-size: clamp(11px, 2.8vw, 14px);
|
font-size: clamp(11px, 2.8vw, 14px);
|
||||||
line-height: 1.3;
|
line-height: 1.2 !important; /* Tighter line height */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Smaller emoji on mobile */
|
||||||
|
.rpg-mood-emoji {
|
||||||
|
font-size: clamp(14px, 3.5vw, 18px) !important; /* Slightly smaller */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Attributes - right side, rows 4-6 aligned with mood */
|
/* Attributes - right side, rows 4-6 aligned with mood */
|
||||||
@@ -3960,6 +4052,11 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
|||||||
font-size: clamp(20px, 5.1vw, 26px) !important;
|
font-size: clamp(20px, 5.1vw, 26px) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Larger mobile refresh icon (same as toggle) */
|
||||||
|
.rpg-mobile-refresh {
|
||||||
|
font-size: clamp(20px, 5.1vw, 26px) !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* ========================================
|
/* ========================================
|
||||||
MOBILE SETTINGS POPUP
|
MOBILE SETTINGS POPUP
|
||||||
======================================== */
|
======================================== */
|
||||||
@@ -4059,6 +4156,13 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
|||||||
min-height: 2.75rem;
|
min-height: 2.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Exception: Level value should stay compact */
|
||||||
|
.rpg-level-value.rpg-editable {
|
||||||
|
padding: 0 0.375em;
|
||||||
|
min-height: auto;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
/* Larger close buttons */
|
/* Larger close buttons */
|
||||||
.rpg-thought-close {
|
.rpg-thought-close {
|
||||||
min-width: 2.75rem;
|
min-width: 2.75rem;
|
||||||
|
|||||||
Reference in New Issue
Block a user