313 lines
8.5 KiB
JavaScript
313 lines
8.5 KiB
JavaScript
/**
|
|
* UI HELPERS
|
|
* Quick utility functions for creating themed UI elements
|
|
* Uses UITheme for consistent styling
|
|
*/
|
|
|
|
class UIHelpers {
|
|
/**
|
|
* Create themed button
|
|
*/
|
|
static createButton(scene, x, y, text, callback, buttonType = 'primary') {
|
|
const theme = window.UITheme;
|
|
const btnStyle = theme.buttons[buttonType] || theme.buttons.primary;
|
|
|
|
// Button background
|
|
const width = Math.max(120, text.length * 10 + 40);
|
|
const height = 40;
|
|
|
|
const button = scene.add.container(x, y);
|
|
|
|
// Background rectangle
|
|
const bg = scene.add.rectangle(0, 0, width, height,
|
|
parseInt(btnStyle.background.replace('#', '0x')), 1);
|
|
bg.setStrokeStyle(2, parseInt(btnStyle.border.replace('#', '0x')));
|
|
|
|
// Text
|
|
const btnText = scene.add.text(0, 0, text, {
|
|
fontFamily: theme.fonts.primary,
|
|
fontSize: theme.fontSizes.medium,
|
|
color: btnStyle.text
|
|
});
|
|
btnText.setOrigin(0.5);
|
|
|
|
button.add([bg, btnText]);
|
|
|
|
// Make interactive
|
|
bg.setInteractive({ useHandCursor: true });
|
|
|
|
// Hover effect
|
|
bg.on('pointerover', () => {
|
|
bg.setFillStyle(parseInt(btnStyle.backgroundHover.replace('#', '0x')));
|
|
});
|
|
|
|
bg.on('pointerout', () => {
|
|
bg.setFillStyle(parseInt(btnStyle.background.replace('#', '0x')));
|
|
});
|
|
|
|
// Click
|
|
if (callback) {
|
|
bg.on('pointerdown', callback);
|
|
}
|
|
|
|
return button;
|
|
}
|
|
|
|
/**
|
|
* Create themed panel
|
|
*/
|
|
static createPanel(scene, x, y, width, height, panelType = 'wooden') {
|
|
const theme = window.UITheme;
|
|
return theme.createPanel(scene, x, y, width, height, panelType);
|
|
}
|
|
|
|
/**
|
|
* Create themed text
|
|
*/
|
|
static createText(scene, x, y, text, style = 'normal') {
|
|
const theme = window.UITheme;
|
|
const textStyle = theme.applyTextStyle(null, style);
|
|
|
|
const textObj = scene.add.text(x, y, text, textStyle);
|
|
return textObj;
|
|
}
|
|
|
|
/**
|
|
* Create header text
|
|
*/
|
|
static createHeader(scene, x, y, text) {
|
|
return this.createText(scene, x, y, text, 'header');
|
|
}
|
|
|
|
/**
|
|
* Create progress bar
|
|
*/
|
|
static createProgressBar(scene, x, y, width, height, progress = 0.5) {
|
|
const theme = window.UITheme;
|
|
|
|
const container = scene.add.container(x, y);
|
|
|
|
// Background
|
|
const bg = scene.add.rectangle(0, 0, width, height,
|
|
theme.getColor('backgrounds.dark'), 1);
|
|
bg.setStrokeStyle(2, theme.getColor('secondary.steel'));
|
|
bg.setOrigin(0, 0.5);
|
|
|
|
// Fill
|
|
const fill = scene.add.rectangle(2, 0, (width - 4) * progress, height - 4,
|
|
theme.getColor('states.success'), 1);
|
|
fill.setOrigin(0, 0.5);
|
|
|
|
container.add([bg, fill]);
|
|
|
|
// Update method
|
|
container.setProgress = function (value) {
|
|
fill.width = Math.max(0, Math.min(width - 4, (width - 4) * value));
|
|
};
|
|
|
|
return container;
|
|
}
|
|
|
|
/**
|
|
* Create tooltip
|
|
*/
|
|
static createTooltip(scene, x, y, text) {
|
|
const theme = window.UITheme;
|
|
|
|
const tooltip = scene.add.container(x, y);
|
|
tooltip.setDepth(100000);
|
|
|
|
// Measure text
|
|
const tempText = scene.add.text(0, 0, text, {
|
|
fontFamily: theme.fonts.primary,
|
|
fontSize: theme.fontSizes.small
|
|
});
|
|
const textWidth = tempText.width;
|
|
const textHeight = tempText.height;
|
|
tempText.destroy();
|
|
|
|
// Background
|
|
const padding = 8;
|
|
const bg = scene.add.rectangle(0, 0, textWidth + padding * 2, textHeight + padding * 2,
|
|
theme.getColor('backgrounds.overlay'));
|
|
bg.setStrokeStyle(1, theme.getColor('primary.lightBrown'));
|
|
|
|
// Text
|
|
const tooltipText = scene.add.text(0, 0, text, {
|
|
fontFamily: theme.fonts.primary,
|
|
fontSize: theme.fontSizes.small,
|
|
color: theme.colors.text.primary
|
|
});
|
|
tooltipText.setOrigin(0.5);
|
|
|
|
tooltip.add([bg, tooltipText]);
|
|
tooltip.setAlpha(0);
|
|
|
|
// Show/hide methods
|
|
tooltip.show = function () {
|
|
this.setAlpha(1);
|
|
};
|
|
|
|
tooltip.hide = function () {
|
|
this.setAlpha(0);
|
|
};
|
|
|
|
return tooltip;
|
|
}
|
|
|
|
/**
|
|
* Create notification popup
|
|
*/
|
|
static createNotification(scene, text, duration = 2000, type = 'info') {
|
|
const theme = window.UITheme;
|
|
|
|
const width = scene.cameras.main.width;
|
|
const height = scene.cameras.main.height;
|
|
|
|
const notification = scene.add.container(width / 2, height - 100);
|
|
notification.setScrollFactor(0);
|
|
notification.setDepth(100000);
|
|
|
|
// Background color based on type
|
|
let bgColor = theme.getColor('states.' + type);
|
|
if (!bgColor) bgColor = theme.getColor('backgrounds.medium');
|
|
|
|
// Background
|
|
const bg = scene.add.rectangle(0, 0, 300, 60, bgColor, 0.95);
|
|
bg.setStrokeStyle(2, theme.getColor('primary.darkBrown'));
|
|
|
|
// Text
|
|
const notifText = scene.add.text(0, 0, text, {
|
|
fontFamily: theme.fonts.primary,
|
|
fontSize: theme.fontSizes.medium,
|
|
color: theme.colors.text.primary,
|
|
align: 'center',
|
|
wordWrap: { width: 280 }
|
|
});
|
|
notifText.setOrigin(0.5);
|
|
|
|
notification.add([bg, notifText]);
|
|
|
|
// Animate in
|
|
notification.setAlpha(0);
|
|
notification.y = height - 50;
|
|
|
|
scene.tweens.add({
|
|
targets: notification,
|
|
alpha: 1,
|
|
y: height - 100,
|
|
duration: 300,
|
|
ease: 'Back.easeOut'
|
|
});
|
|
|
|
// Animate out
|
|
scene.tweens.add({
|
|
targets: notification,
|
|
alpha: 0,
|
|
y: height - 50,
|
|
duration: 300,
|
|
delay: duration,
|
|
onComplete: () => {
|
|
notification.destroy();
|
|
}
|
|
});
|
|
|
|
return notification;
|
|
}
|
|
|
|
/**
|
|
* Create icon button (emoji/icon only)
|
|
*/
|
|
static createIconButton(scene, x, y, icon, callback, size = 40) {
|
|
const theme = window.UITheme;
|
|
|
|
const button = scene.add.container(x, y);
|
|
|
|
// Background
|
|
const bg = scene.add.circle(0, 0, size / 2,
|
|
theme.getColor('primary.mediumBrown'), 1);
|
|
bg.setStrokeStyle(2, theme.getColor('primary.darkBrown'));
|
|
|
|
// Icon
|
|
const iconText = scene.add.text(0, 0, icon, {
|
|
fontSize: (size * 0.6) + 'px'
|
|
});
|
|
iconText.setOrigin(0.5);
|
|
|
|
button.add([bg, iconText]);
|
|
|
|
// Interactive
|
|
bg.setInteractive({ useHandCursor: true });
|
|
|
|
bg.on('pointerover', () => {
|
|
bg.setFillStyle(theme.getColor('primary.lightBrown'));
|
|
});
|
|
|
|
bg.on('pointerout', () => {
|
|
bg.setFillStyle(theme.getColor('primary.mediumBrown'));
|
|
});
|
|
|
|
if (callback) {
|
|
bg.on('pointerdown', callback);
|
|
}
|
|
|
|
return button;
|
|
}
|
|
|
|
/**
|
|
* Create checkbox
|
|
*/
|
|
static createCheckbox(scene, x, y, label, isChecked = false, callback) {
|
|
const theme = window.UITheme;
|
|
|
|
const checkbox = scene.add.container(x, y);
|
|
|
|
// Box
|
|
const size = 20;
|
|
const box = scene.add.rectangle(0, 0, size, size,
|
|
theme.getColor('backgrounds.light'), 1);
|
|
box.setStrokeStyle(2, theme.getColor('primary.darkBrown'));
|
|
box.setOrigin(0, 0.5);
|
|
|
|
// Checkmark
|
|
const check = scene.add.text(size / 2, 0, '✓', {
|
|
fontSize: '18px',
|
|
color: theme.colors.accent.forestGreen
|
|
});
|
|
check.setOrigin(0.5);
|
|
check.setVisible(isChecked);
|
|
|
|
// Label
|
|
const labelText = scene.add.text(size + 10, 0, label, {
|
|
fontFamily: theme.fonts.primary,
|
|
fontSize: theme.fontSizes.normal,
|
|
color: theme.colors.text.primary
|
|
});
|
|
labelText.setOrigin(0, 0.5);
|
|
|
|
checkbox.add([box, check, labelText]);
|
|
|
|
// State
|
|
checkbox.checked = isChecked;
|
|
|
|
// Interactive
|
|
box.setInteractive({ useHandCursor: true });
|
|
|
|
box.on('pointerdown', () => {
|
|
checkbox.checked = !checkbox.checked;
|
|
check.setVisible(checkbox.checked);
|
|
|
|
if (callback) {
|
|
callback(checkbox.checked);
|
|
}
|
|
});
|
|
|
|
return checkbox;
|
|
}
|
|
}
|
|
|
|
// Make globally available
|
|
window.UIHelpers = UIHelpers;
|
|
|
|
console.log('🎨 UI Helpers loaded');
|