04bb52ed71
- Increase conditions font size from 0.45rem to 0.6rem (33% larger) - Reduce mood emoji size from 1rem to 0.9rem for better proportion - Add font-weight: 600 to mood for better hierarchy - Improve line-height from 1 to 1.2 for readability - Reduce -webkit-line-clamp from 3 to 2 lines for conditions - Add slight opacity (0.9) to conditions for visual separation - Update onResize scaling to maintain balanced proportions (1.4rem / 0.9rem for larger widgets) - Increase mobile conditions size to 0.7rem with 1.3 line-height Result: Conditions text is now much more readable while maintaining good visual balance with the mood emoji in the compact 1x1 widget.
217 lines
7.4 KiB
JavaScript
217 lines
7.4 KiB
JavaScript
/**
|
|
* User Mood Widget
|
|
*
|
|
* Displays user's current mood emoji and active conditions.
|
|
* Compact widget showing emotional state and status effects.
|
|
*
|
|
* Features:
|
|
* - Large mood emoji (editable)
|
|
* - Conditions/status effects text (editable)
|
|
* - Responsive layout
|
|
*/
|
|
|
|
/**
|
|
* Register User Mood Widget
|
|
* @param {WidgetRegistry} registry - Widget registry instance
|
|
* @param {Object} dependencies - External dependencies
|
|
* @param {Function} dependencies.getExtensionSettings - Get extension settings
|
|
* @param {Function} dependencies.onStatsChange - Callback when stats change
|
|
*/
|
|
export function registerUserMoodWidget(registry, dependencies) {
|
|
const {
|
|
getExtensionSettings,
|
|
onStatsChange
|
|
} = dependencies;
|
|
|
|
registry.register('userMood', {
|
|
name: 'User Mood',
|
|
icon: '😊',
|
|
description: 'Mood emoji and active conditions',
|
|
category: 'user',
|
|
minSize: { w: 1, h: 1 },
|
|
defaultSize: { w: 1, h: 1 },
|
|
maxAutoSize: { w: 1, h: 1 }, // Max size for auto-arrange expansion - stays compact in top right
|
|
requiresSchema: false,
|
|
|
|
/**
|
|
* Render widget content
|
|
* @param {HTMLElement} container - Widget container
|
|
* @param {Object} config - Widget configuration
|
|
*/
|
|
render(container, config = {}) {
|
|
const settings = getExtensionSettings();
|
|
const stats = settings.userStats;
|
|
|
|
// Merge default config
|
|
const finalConfig = {
|
|
showMoodEmoji: true,
|
|
showConditions: true,
|
|
...config
|
|
};
|
|
|
|
// Build HTML
|
|
const html = `
|
|
<div class="rpg-mood">
|
|
${finalConfig.showMoodEmoji ? `<div class="rpg-mood-emoji rpg-editable" contenteditable="true" data-field="mood" title="Click to edit emoji">${stats.mood}</div>` : ''}
|
|
${finalConfig.showConditions ? `<div class="rpg-mood-conditions rpg-editable" contenteditable="true" data-field="conditions" title="Click to edit conditions">${stats.conditions}</div>` : ''}
|
|
</div>
|
|
`;
|
|
|
|
container.innerHTML = html;
|
|
|
|
// Attach event handlers
|
|
attachEventHandlers(container, settings, onStatsChange);
|
|
},
|
|
|
|
/**
|
|
* Get configuration options
|
|
* @returns {Object} Configuration schema
|
|
*/
|
|
getConfig() {
|
|
return {
|
|
showMoodEmoji: {
|
|
type: 'boolean',
|
|
label: 'Show Mood Emoji',
|
|
default: true
|
|
},
|
|
showConditions: {
|
|
type: 'boolean',
|
|
label: 'Show Conditions',
|
|
default: true
|
|
}
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Handle configuration changes
|
|
* @param {HTMLElement} container - Widget container
|
|
* @param {Object} newConfig - New configuration
|
|
*/
|
|
onConfigChange(container, newConfig) {
|
|
this.render(container, newConfig);
|
|
},
|
|
|
|
/**
|
|
* Handle widget resize
|
|
* @param {HTMLElement} container - Widget container
|
|
* @param {number} newW - New width
|
|
* @param {number} newH - New height
|
|
*/
|
|
onResize(container, newW, newH) {
|
|
const mood = container.querySelector('.rpg-mood');
|
|
const emoji = container.querySelector('.rpg-mood-emoji');
|
|
const conditions = container.querySelector('.rpg-mood-conditions');
|
|
if (!mood || !emoji || !conditions) return;
|
|
|
|
// Scale based on widget size with balanced proportions
|
|
if (newW >= 2 && newH >= 2) {
|
|
// Larger widget: scale up proportionally
|
|
emoji.style.fontSize = '1.4rem';
|
|
conditions.style.fontSize = '0.9rem';
|
|
} else {
|
|
// Compact 1x1: use CSS defaults (0.9rem / 0.6rem)
|
|
emoji.style.fontSize = '';
|
|
conditions.style.fontSize = '';
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Attach event handlers to widget
|
|
* @private
|
|
*/
|
|
function attachEventHandlers(container, settings, onStatsChange) {
|
|
// Handle mood emoji editing
|
|
const moodEmoji = container.querySelector('.rpg-mood-emoji.rpg-editable');
|
|
if (moodEmoji) {
|
|
let originalMood = moodEmoji.textContent.trim();
|
|
|
|
moodEmoji.addEventListener('focus', () => {
|
|
originalMood = moodEmoji.textContent.trim();
|
|
const range = document.createRange();
|
|
range.selectNodeContents(moodEmoji);
|
|
const selection = window.getSelection();
|
|
selection.removeAllRanges();
|
|
selection.addRange(range);
|
|
});
|
|
|
|
moodEmoji.addEventListener('blur', () => {
|
|
const value = moodEmoji.textContent.trim() || '😐';
|
|
moodEmoji.textContent = value;
|
|
|
|
if (value !== originalMood) {
|
|
settings.userStats.mood = value;
|
|
if (onStatsChange) {
|
|
onStatsChange('userStats', 'mood', value);
|
|
}
|
|
}
|
|
});
|
|
|
|
moodEmoji.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Enter') {
|
|
e.preventDefault();
|
|
moodEmoji.blur();
|
|
}
|
|
if (e.key === 'Escape') {
|
|
e.preventDefault();
|
|
moodEmoji.textContent = originalMood;
|
|
moodEmoji.blur();
|
|
}
|
|
});
|
|
|
|
// Prevent paste with formatting
|
|
moodEmoji.addEventListener('paste', (e) => {
|
|
e.preventDefault();
|
|
const text = (e.clipboardData || window.clipboardData).getData('text/plain');
|
|
document.execCommand('insertText', false, text);
|
|
});
|
|
}
|
|
|
|
// Handle conditions editing
|
|
const moodConditions = container.querySelector('.rpg-mood-conditions.rpg-editable');
|
|
if (moodConditions) {
|
|
let originalConditions = moodConditions.textContent.trim();
|
|
|
|
moodConditions.addEventListener('focus', () => {
|
|
originalConditions = moodConditions.textContent.trim();
|
|
const range = document.createRange();
|
|
range.selectNodeContents(moodConditions);
|
|
const selection = window.getSelection();
|
|
selection.removeAllRanges();
|
|
selection.addRange(range);
|
|
});
|
|
|
|
moodConditions.addEventListener('blur', () => {
|
|
const value = moodConditions.textContent.trim() || 'None';
|
|
moodConditions.textContent = value;
|
|
|
|
if (value !== originalConditions) {
|
|
settings.userStats.conditions = value;
|
|
if (onStatsChange) {
|
|
onStatsChange('userStats', 'conditions', value);
|
|
}
|
|
}
|
|
});
|
|
|
|
moodConditions.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Enter') {
|
|
e.preventDefault();
|
|
moodConditions.blur();
|
|
}
|
|
if (e.key === 'Escape') {
|
|
e.preventDefault();
|
|
moodConditions.textContent = originalConditions;
|
|
moodConditions.blur();
|
|
}
|
|
});
|
|
|
|
// Prevent paste with formatting
|
|
moodConditions.addEventListener('paste', (e) => {
|
|
e.preventDefault();
|
|
const text = (e.clipboardData || window.clipboardData).getData('text/plain');
|
|
document.execCommand('insertText', false, text);
|
|
});
|
|
}
|
|
}
|