feat(dashboard): implement smart widget scaling and improved auto-layout
- Add resetWidgetSizesToDefault() to reset all widgets to default sizes before auto-arrange/reset - Implement continuous expansion algorithm that fills available space up to maxAutoSize limits - Add visible height detection to prevent widgets expanding beyond viewport (no forced scroll) - Update all widget defaultSize and maxAutoSize for optimal 1x1 compact layouts - Info widgets (calendar, weather, temp, clock): 1x1 default, 1x2 max - Location: 2x2 max (was 3x3) - Characters: 3x5 max, moved to 'scene' category (eliminates Social tab) - User Info: 2x1 max (prevents expansion) - User Mood: 1x1 default and max (compact top-right placement) - User Attributes: 3x5 max (fills bottom space) - User Stats: 3x3 max - Fix CSS scaling for 1x1 widgets - Replace viewport-based units with fixed rem values - Reduce icon/graphic sizes to fit with visible text - Add explicit gaps and padding for consistent spacing - Set line-height: 1 to prevent text overflow - Reorganize default layout - Status tab: User Info (2x1) + Mood (1x1 top right) + Stats + Attributes - Scene tab: Info widgets (1x1) + Location + Characters (all on one tab) - Inventory tab: Full inventory widget Auto-arrange and reset now properly size widgets to defaults and expand to fill available space without exceeding visible area.
This commit is contained in:
@@ -1183,6 +1183,15 @@ export class DashboardManager {
|
|||||||
await this.persistence.resetToDefault(this.defaultLayout);
|
await this.persistence.resetToDefault(this.defaultLayout);
|
||||||
this.applyDashboardConfig(this.defaultLayout);
|
this.applyDashboardConfig(this.defaultLayout);
|
||||||
|
|
||||||
|
// Reset all widgets to default sizes
|
||||||
|
const allWidgets = [];
|
||||||
|
this.dashboard.tabs.forEach(tab => {
|
||||||
|
if (tab.widgets && tab.widgets.length > 0) {
|
||||||
|
allWidgets.push(...tab.widgets);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.resetWidgetSizesToDefault(allWidgets);
|
||||||
|
|
||||||
// Auto-layout each tab to prevent overlap (default positions may have changed)
|
// Auto-layout each tab to prevent overlap (default positions may have changed)
|
||||||
this.dashboard.tabs.forEach(tab => {
|
this.dashboard.tabs.forEach(tab => {
|
||||||
if (tab.widgets && tab.widgets.length > 0) {
|
if (tab.widgets && tab.widgets.length > 0) {
|
||||||
@@ -1212,6 +1221,28 @@ export class DashboardManager {
|
|||||||
this.defaultLayout = layout;
|
this.defaultLayout = layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset all widgets to their default sizes
|
||||||
|
* @param {Array} widgets - Widgets to reset
|
||||||
|
*/
|
||||||
|
resetWidgetSizesToDefault(widgets) {
|
||||||
|
let resetCount = 0;
|
||||||
|
widgets.forEach(widget => {
|
||||||
|
const definition = this.registry.get(widget.type);
|
||||||
|
if (definition && definition.defaultSize) {
|
||||||
|
const oldSize = `${widget.w}x${widget.h}`;
|
||||||
|
widget.w = definition.defaultSize.w;
|
||||||
|
widget.h = definition.defaultSize.h;
|
||||||
|
const newSize = `${widget.w}x${widget.h}`;
|
||||||
|
if (oldSize !== newSize) {
|
||||||
|
console.log(`[DashboardManager] Reset ${widget.type} from ${oldSize} to ${newSize}`);
|
||||||
|
resetCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log(`[DashboardManager] Reset ${resetCount} widgets to default sizes`);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Auto-layout widgets on current tab to efficiently use all available space
|
* Auto-layout widgets on current tab to efficiently use all available space
|
||||||
*
|
*
|
||||||
@@ -1221,6 +1252,7 @@ export class DashboardManager {
|
|||||||
*
|
*
|
||||||
* @param {Object} options - Layout options
|
* @param {Object} options - Layout options
|
||||||
* @param {boolean} [options.preferFullWidth=true] - Prefer full-width widgets when possible
|
* @param {boolean} [options.preferFullWidth=true] - Prefer full-width widgets when possible
|
||||||
|
* @param {boolean} [options.resetSizes=true] - Reset widgets to default sizes before layout
|
||||||
*/
|
*/
|
||||||
autoLayoutWidgets(options = {}) {
|
autoLayoutWidgets(options = {}) {
|
||||||
console.log('[DashboardManager] Auto-layout widgets requested');
|
console.log('[DashboardManager] Auto-layout widgets requested');
|
||||||
@@ -1241,6 +1273,11 @@ export class DashboardManager {
|
|||||||
|
|
||||||
console.log(`[DashboardManager] Total widgets to layout: ${allWidgets.length}`);
|
console.log(`[DashboardManager] Total widgets to layout: ${allWidgets.length}`);
|
||||||
|
|
||||||
|
// Reset widget sizes to defaults (unless explicitly disabled)
|
||||||
|
if (options.resetSizes !== false) {
|
||||||
|
this.resetWidgetSizesToDefault(allWidgets);
|
||||||
|
}
|
||||||
|
|
||||||
// Smart category-aware sorting BEFORE auto-layout
|
// Smart category-aware sorting BEFORE auto-layout
|
||||||
const widgetsToLayout = this.sortWidgetsByCategory(allWidgets);
|
const widgetsToLayout = this.sortWidgetsByCategory(allWidgets);
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export function generateDefaultDashboard() {
|
|||||||
icon: '📊',
|
icon: '📊',
|
||||||
order: 0,
|
order: 0,
|
||||||
widgets: [
|
widgets: [
|
||||||
// Row 0: User Info (avatar, name, level)
|
// Row 0: User Info (left) + User Mood (top right in 3-col)
|
||||||
{
|
{
|
||||||
id: 'widget-userinfo',
|
id: 'widget-userinfo',
|
||||||
type: 'userInfo',
|
type: 'userInfo',
|
||||||
@@ -49,6 +49,15 @@ export function generateDefaultDashboard() {
|
|||||||
h: 1,
|
h: 1,
|
||||||
config: {}
|
config: {}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'widget-usermood',
|
||||||
|
type: 'userMood',
|
||||||
|
x: 2,
|
||||||
|
y: 0,
|
||||||
|
w: 1,
|
||||||
|
h: 1,
|
||||||
|
config: {}
|
||||||
|
},
|
||||||
// Row 1-2: User Stats (health/energy bars)
|
// Row 1-2: User Stats (health/energy bars)
|
||||||
{
|
{
|
||||||
id: 'widget-userstats',
|
id: 'widget-userstats',
|
||||||
@@ -61,22 +70,12 @@ export function generateDefaultDashboard() {
|
|||||||
statBarGradient: true
|
statBarGradient: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Row 3: User Mood
|
// Row 3-4: User Attributes
|
||||||
{
|
|
||||||
id: 'widget-usermood',
|
|
||||||
type: 'userMood',
|
|
||||||
x: 0,
|
|
||||||
y: 3,
|
|
||||||
w: 2,
|
|
||||||
h: 1,
|
|
||||||
config: {}
|
|
||||||
},
|
|
||||||
// Row 4-5: User Attributes
|
|
||||||
{
|
{
|
||||||
id: 'widget-userattributes',
|
id: 'widget-userattributes',
|
||||||
type: 'userAttributes',
|
type: 'userAttributes',
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 4,
|
y: 3,
|
||||||
w: 2,
|
w: 2,
|
||||||
h: 2,
|
h: 2,
|
||||||
config: {}
|
config: {}
|
||||||
@@ -90,14 +89,14 @@ export function generateDefaultDashboard() {
|
|||||||
icon: '🌍',
|
icon: '🌍',
|
||||||
order: 1,
|
order: 1,
|
||||||
widgets: [
|
widgets: [
|
||||||
// Row 0-1: Calendar (left) + Weather (right)
|
// Row 0: Calendar (left) + Weather (right)
|
||||||
{
|
{
|
||||||
id: 'widget-calendar',
|
id: 'widget-calendar',
|
||||||
type: 'calendar',
|
type: 'calendar',
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
w: 1,
|
w: 1,
|
||||||
h: 2,
|
h: 1,
|
||||||
config: {}
|
config: {}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -106,19 +105,19 @@ export function generateDefaultDashboard() {
|
|||||||
x: 1,
|
x: 1,
|
||||||
y: 0,
|
y: 0,
|
||||||
w: 1,
|
w: 1,
|
||||||
h: 2,
|
h: 1,
|
||||||
config: {
|
config: {
|
||||||
compact: false
|
compact: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Row 2-3: Temperature (left) + Clock (right)
|
// Row 1: Temperature (left) + Clock (right)
|
||||||
{
|
{
|
||||||
id: 'widget-temperature',
|
id: 'widget-temperature',
|
||||||
type: 'temperature',
|
type: 'temperature',
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 2,
|
y: 1,
|
||||||
w: 1,
|
w: 1,
|
||||||
h: 2,
|
h: 1,
|
||||||
config: {
|
config: {
|
||||||
unit: 'celsius'
|
unit: 'celsius'
|
||||||
}
|
}
|
||||||
@@ -127,29 +126,29 @@ export function generateDefaultDashboard() {
|
|||||||
id: 'widget-clock',
|
id: 'widget-clock',
|
||||||
type: 'clock',
|
type: 'clock',
|
||||||
x: 1,
|
x: 1,
|
||||||
y: 2,
|
y: 1,
|
||||||
w: 1,
|
w: 1,
|
||||||
h: 2,
|
h: 1,
|
||||||
config: {
|
config: {
|
||||||
format: 'digital'
|
format: 'digital'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Row 4-5: Location (full width)
|
// Row 2-3: Location (full width)
|
||||||
{
|
{
|
||||||
id: 'widget-location',
|
id: 'widget-location',
|
||||||
type: 'location',
|
type: 'location',
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 4,
|
y: 2,
|
||||||
w: 2,
|
w: 2,
|
||||||
h: 2,
|
h: 2,
|
||||||
config: {}
|
config: {}
|
||||||
},
|
},
|
||||||
// Row 6-8: Present Characters (full width, will expand with auto-layout)
|
// Row 4-6: Present Characters (full width, will expand with auto-layout)
|
||||||
{
|
{
|
||||||
id: 'widget-presentchars',
|
id: 'widget-presentchars',
|
||||||
type: 'presentCharacters',
|
type: 'presentCharacters',
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 6,
|
y: 4,
|
||||||
w: 2,
|
w: 2,
|
||||||
h: 3,
|
h: 3,
|
||||||
config: {
|
config: {
|
||||||
|
|||||||
@@ -435,10 +435,22 @@ export class GridEngine {
|
|||||||
|
|
||||||
const preserveOrder = options.preserveOrder || false;
|
const preserveOrder = options.preserveOrder || false;
|
||||||
|
|
||||||
|
// Calculate maximum visible rows based on container height
|
||||||
|
let maxVisibleRows = 100; // Fallback
|
||||||
|
if (this.container) {
|
||||||
|
const containerHeight = this.container.clientHeight; // pixels
|
||||||
|
const rootFontSize = parseFloat(getComputedStyle(document.documentElement).fontSize); // px per rem
|
||||||
|
const containerHeightRem = containerHeight / rootFontSize;
|
||||||
|
const rowHeightWithGap = this.rowHeight + this.gap;
|
||||||
|
maxVisibleRows = Math.floor(containerHeightRem / rowHeightWithGap);
|
||||||
|
console.log('[GridEngine] Container height:', containerHeight + 'px', '=', containerHeightRem.toFixed(2) + 'rem', '→', maxVisibleRows, 'rows');
|
||||||
|
}
|
||||||
|
|
||||||
console.log('[GridEngine] Auto-layout started:', {
|
console.log('[GridEngine] Auto-layout started:', {
|
||||||
widgetCount: widgets.length,
|
widgetCount: widgets.length,
|
||||||
columns: this.columns,
|
columns: this.columns,
|
||||||
preserveOrder
|
preserveOrder,
|
||||||
|
maxVisibleRows
|
||||||
});
|
});
|
||||||
|
|
||||||
// Sort widgets (or preserve input order for category-aware layout)
|
// Sort widgets (or preserve input order for category-aware layout)
|
||||||
@@ -586,8 +598,8 @@ export class GridEngine {
|
|||||||
return definition.maxAutoSize;
|
return definition.maxAutoSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Default max size if not specified (flexible expansion)
|
// Default max size if not specified (conservative expansion)
|
||||||
return { w: this.columns, h: 10 };
|
return { w: this.columns, h: 3 };
|
||||||
};
|
};
|
||||||
|
|
||||||
sortedForExpand.forEach(widget => {
|
sortedForExpand.forEach(widget => {
|
||||||
@@ -595,9 +607,15 @@ export class GridEngine {
|
|||||||
const originalW = widget.w;
|
const originalW = widget.w;
|
||||||
const originalH = widget.h;
|
const originalH = widget.h;
|
||||||
|
|
||||||
// Try expanding height first (fills vertical gaps)
|
// Try expanding height first (fills vertical gaps) - keep trying until maxSize or collision
|
||||||
let expandedH = false;
|
let expandedH = false;
|
||||||
for (let tryH = originalH + 1; tryH <= Math.min(maxSize.h, originalH + 3); tryH++) {
|
for (let tryH = originalH + 1; tryH <= maxSize.h; tryH++) {
|
||||||
|
// Check if expansion would go beyond visible area
|
||||||
|
if (widget.y + tryH > maxVisibleRows) {
|
||||||
|
console.log(`[GridEngine] ${widget.id} cannot expand to h=${tryH} (would exceed visible area: row ${widget.y + tryH} > ${maxVisibleRows})`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Clear current position
|
// Clear current position
|
||||||
for (let row = widget.y; row < widget.y + widget.h; row++) {
|
for (let row = widget.y; row < widget.y + widget.h; row++) {
|
||||||
for (let col = widget.x; col < widget.x + widget.w; col++) {
|
for (let col = widget.x; col < widget.x + widget.w; col++) {
|
||||||
@@ -611,15 +629,19 @@ export class GridEngine {
|
|||||||
markOccupied(widget, widget.x, widget.y, widget.w, tryH);
|
markOccupied(widget, widget.x, widget.y, widget.w, tryH);
|
||||||
expandedH = true;
|
expandedH = true;
|
||||||
expandedCount++;
|
expandedCount++;
|
||||||
console.log(`[GridEngine] Expanded ${widget.id} height: ${originalH} → ${tryH}`);
|
// Continue trying to expand further
|
||||||
break;
|
|
||||||
} else {
|
} else {
|
||||||
// Re-mark original and try next size
|
// Hit a collision, stop expanding height
|
||||||
markOccupied(widget, widget.x, widget.y, widget.w, widget.h);
|
markOccupied(widget, widget.x, widget.y, widget.w, widget.h);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try expanding width (fills horizontal gaps)
|
if (expandedH) {
|
||||||
|
console.log(`[GridEngine] Expanded ${widget.id} height: ${originalH} → ${widget.h}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try expanding width (fills horizontal gaps) - keep trying until maxSize or collision
|
||||||
let expandedW = false;
|
let expandedW = false;
|
||||||
for (let tryW = originalW + 1; tryW <= Math.min(maxSize.w, this.columns); tryW++) {
|
for (let tryW = originalW + 1; tryW <= Math.min(maxSize.w, this.columns); tryW++) {
|
||||||
// Clear current position
|
// Clear current position
|
||||||
@@ -635,14 +657,18 @@ export class GridEngine {
|
|||||||
markOccupied(widget, widget.x, widget.y, tryW, widget.h);
|
markOccupied(widget, widget.x, widget.y, tryW, widget.h);
|
||||||
expandedW = true;
|
expandedW = true;
|
||||||
expandedCount++;
|
expandedCount++;
|
||||||
console.log(`[GridEngine] Expanded ${widget.id} width: ${originalW} → ${tryW}`);
|
// Continue trying to expand further
|
||||||
break;
|
|
||||||
} else {
|
} else {
|
||||||
// Re-mark original and try next size
|
// Hit a collision, stop expanding width
|
||||||
markOccupied(widget, widget.x, widget.y, widget.w, widget.h);
|
markOccupied(widget, widget.x, widget.y, widget.w, widget.h);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (expandedW) {
|
||||||
|
console.log(`[GridEngine] Expanded ${widget.id} width: ${originalW} → ${widget.w}`);
|
||||||
|
}
|
||||||
|
|
||||||
if (!expandedH && !expandedW) {
|
if (!expandedH && !expandedW) {
|
||||||
// Widget couldn't expand - ensure it's still marked in grid
|
// Widget couldn't expand - ensure it's still marked in grid
|
||||||
markOccupied(widget, widget.x, widget.y, widget.w, widget.h);
|
markOccupied(widget, widget.x, widget.y, widget.w, widget.h);
|
||||||
|
|||||||
@@ -192,9 +192,9 @@ export function registerCalendarWidget(registry, dependencies) {
|
|||||||
icon: '📅',
|
icon: '📅',
|
||||||
description: 'Date, weekday, month, and year display',
|
description: 'Date, weekday, month, and year display',
|
||||||
category: 'scene',
|
category: 'scene',
|
||||||
minSize: { w: 1, h: 2 },
|
minSize: { w: 1, h: 1 },
|
||||||
defaultSize: { w: 1, h: 2 },
|
defaultSize: { w: 1, h: 1 },
|
||||||
maxAutoSize: { w: 2, h: 3 }, // Max size for auto-arrange expansion
|
maxAutoSize: { w: 1, h: 2 }, // Max size for auto-arrange expansion
|
||||||
requiresSchema: false,
|
requiresSchema: false,
|
||||||
|
|
||||||
render(container, config = {}) {
|
render(container, config = {}) {
|
||||||
@@ -280,9 +280,9 @@ export function registerWeatherWidget(registry, dependencies) {
|
|||||||
name: 'Weather',
|
name: 'Weather',
|
||||||
icon: '🌤️',
|
icon: '🌤️',
|
||||||
description: 'Weather emoji and forecast',
|
description: 'Weather emoji and forecast',
|
||||||
minSize: { w: 1, h: 2 },
|
minSize: { w: 1, h: 1 },
|
||||||
defaultSize: { w: 1, h: 2 },
|
defaultSize: { w: 1, h: 1 },
|
||||||
maxAutoSize: { w: 2, h: 3 }, // Max size for auto-arrange expansion
|
maxAutoSize: { w: 1, h: 2 }, // Max size for auto-arrange expansion
|
||||||
requiresSchema: false,
|
requiresSchema: false,
|
||||||
|
|
||||||
render(container, config = {}) {
|
render(container, config = {}) {
|
||||||
@@ -314,9 +314,9 @@ export function registerTemperatureWidget(registry, dependencies) {
|
|||||||
name: 'Temperature',
|
name: 'Temperature',
|
||||||
icon: '🌡️',
|
icon: '🌡️',
|
||||||
description: 'Temperature display with thermometer',
|
description: 'Temperature display with thermometer',
|
||||||
minSize: { w: 1, h: 2 },
|
minSize: { w: 1, h: 1 },
|
||||||
defaultSize: { w: 1, h: 2 },
|
defaultSize: { w: 1, h: 1 },
|
||||||
maxAutoSize: { w: 2, h: 3 }, // Max size for auto-arrange expansion
|
maxAutoSize: { w: 1, h: 2 }, // Max size for auto-arrange expansion
|
||||||
requiresSchema: false,
|
requiresSchema: false,
|
||||||
|
|
||||||
render(container, config = {}) {
|
render(container, config = {}) {
|
||||||
@@ -355,9 +355,9 @@ export function registerClockWidget(registry, dependencies) {
|
|||||||
name: 'Clock',
|
name: 'Clock',
|
||||||
icon: '🕐',
|
icon: '🕐',
|
||||||
description: 'Analog clock with time display',
|
description: 'Analog clock with time display',
|
||||||
minSize: { w: 1, h: 2 },
|
minSize: { w: 1, h: 1 },
|
||||||
defaultSize: { w: 1, h: 2 },
|
defaultSize: { w: 1, h: 1 },
|
||||||
maxAutoSize: { w: 2, h: 3 }, // Max size for auto-arrange expansion
|
maxAutoSize: { w: 1, h: 2 }, // Max size for auto-arrange expansion
|
||||||
requiresSchema: false,
|
requiresSchema: false,
|
||||||
|
|
||||||
render(container, config = {}) {
|
render(container, config = {}) {
|
||||||
@@ -407,7 +407,7 @@ export function registerLocationWidget(registry, dependencies) {
|
|||||||
description: 'Map with location display',
|
description: 'Map with location display',
|
||||||
minSize: { w: 1, h: 2 },
|
minSize: { w: 1, h: 2 },
|
||||||
defaultSize: { w: 2, h: 2 },
|
defaultSize: { w: 2, h: 2 },
|
||||||
maxAutoSize: { w: 3, h: 3 }, // Max size for auto-arrange expansion
|
maxAutoSize: { w: 2, h: 2 }, // Max size for auto-arrange expansion
|
||||||
requiresSchema: false,
|
requiresSchema: false,
|
||||||
|
|
||||||
render(container, config = {}) {
|
render(container, config = {}) {
|
||||||
|
|||||||
@@ -235,10 +235,10 @@ export function registerPresentCharactersWidget(registry, dependencies) {
|
|||||||
name: 'Present Characters',
|
name: 'Present Characters',
|
||||||
icon: '👥',
|
icon: '👥',
|
||||||
description: 'Character cards with avatars, traits, and relationships',
|
description: 'Character cards with avatars, traits, and relationships',
|
||||||
category: 'social',
|
category: 'scene',
|
||||||
minSize: { w: 2, h: 2 },
|
minSize: { w: 2, h: 2 },
|
||||||
defaultSize: { w: 2, h: 3 },
|
defaultSize: { w: 2, h: 3 },
|
||||||
maxAutoSize: { w: 3, h: 6 }, // Max size for auto-arrange expansion (can expand significantly)
|
maxAutoSize: { w: 3, h: 5 }, // Max size for auto-arrange expansion
|
||||||
requiresSchema: false,
|
requiresSchema: false,
|
||||||
|
|
||||||
render(container, config = {}) {
|
render(container, config = {}) {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ export function registerUserAttributesWidget(registry, dependencies) {
|
|||||||
category: 'user',
|
category: 'user',
|
||||||
minSize: { w: 2, h: 2 },
|
minSize: { w: 2, h: 2 },
|
||||||
defaultSize: { w: 2, h: 2 },
|
defaultSize: { w: 2, h: 2 },
|
||||||
|
maxAutoSize: { w: 3, h: 5 }, // Max size for auto-arrange expansion
|
||||||
requiresSchema: false,
|
requiresSchema: false,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ export function registerUserInfoWidget(registry, dependencies) {
|
|||||||
category: 'user',
|
category: 'user',
|
||||||
minSize: { w: 1, h: 1 },
|
minSize: { w: 1, h: 1 },
|
||||||
defaultSize: { w: 2, h: 1 },
|
defaultSize: { w: 2, h: 1 },
|
||||||
|
maxAutoSize: { w: 2, h: 1 }, // Max size for auto-arrange expansion
|
||||||
requiresSchema: false,
|
requiresSchema: false,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ export function registerUserMoodWidget(registry, dependencies) {
|
|||||||
description: 'Mood emoji and active conditions',
|
description: 'Mood emoji and active conditions',
|
||||||
category: 'user',
|
category: 'user',
|
||||||
minSize: { w: 1, h: 1 },
|
minSize: { w: 1, h: 1 },
|
||||||
defaultSize: { w: 2, 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,
|
requiresSchema: false,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ export function registerUserStatsWidget(registry, dependencies) {
|
|||||||
category: 'user',
|
category: 'user',
|
||||||
minSize: { w: 1, h: 2 },
|
minSize: { w: 1, h: 2 },
|
||||||
defaultSize: { w: 2, h: 2 },
|
defaultSize: { w: 2, h: 2 },
|
||||||
|
maxAutoSize: { w: 3, h: 3 }, // Max size for auto-arrange expansion
|
||||||
requiresSchema: false,
|
requiresSchema: false,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1400,7 +1400,7 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
|||||||
.rpg-calendar-top {
|
.rpg-calendar-top {
|
||||||
background: var(--rpg-highlight);
|
background: var(--rpg-highlight);
|
||||||
color: var(--rpg-bg);
|
color: var(--rpg-bg);
|
||||||
font-size: clamp(0.6rem, 0.7rem, 0.8rem);
|
font-size: 0.65rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding: 0.125em 0.375em;
|
padding: 0.125em 0.375em;
|
||||||
border-radius: 3px 3px 0 0;
|
border-radius: 3px 3px 0 0;
|
||||||
@@ -1412,9 +1412,9 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
|||||||
.rpg-calendar-day {
|
.rpg-calendar-day {
|
||||||
background: rgba(255, 255, 255, 0.1);
|
background: rgba(255, 255, 255, 0.1);
|
||||||
color: var(--rpg-text);
|
color: var(--rpg-text);
|
||||||
font-size: clamp(1.5rem, 2.5rem, 3.5rem);
|
font-size: 1.8rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding: 0.25em;
|
padding: 0.1em;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border: 2px solid var(--rpg-highlight);
|
border: 2px solid var(--rpg-highlight);
|
||||||
@@ -1427,7 +1427,7 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.rpg-calendar-year {
|
.rpg-calendar-year {
|
||||||
font-size: clamp(0.6rem, 0.7rem, 0.8rem);
|
font-size: 0.55rem;
|
||||||
color: var(--rpg-text);
|
color: var(--rpg-text);
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
margin-top: 0.062em;
|
margin-top: 0.062em;
|
||||||
@@ -1439,19 +1439,21 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-around;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0.5rem;
|
padding: 0.25rem;
|
||||||
|
gap: 0.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rpg-weather-icon {
|
.rpg-weather-icon {
|
||||||
font-size: clamp(2rem, 8vh, 4rem);
|
font-size: 2rem;
|
||||||
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.5));
|
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.5));
|
||||||
flex-shrink: 0;
|
flex-shrink: 1;
|
||||||
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rpg-weather-forecast {
|
.rpg-weather-forecast {
|
||||||
font-size: clamp(0.7rem, 0.9rem, 1.1rem);
|
font-size: 0.65rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@@ -1477,13 +1479,14 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5rem;
|
padding: 0.25rem;
|
||||||
|
gap: 0.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rpg-thermometer {
|
.rpg-thermometer {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: clamp(1.5rem, 2rem, 3rem);
|
width: 1.2rem;
|
||||||
height: clamp(4rem, 60%, 8rem);
|
height: 2.5rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -1522,11 +1525,12 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.rpg-temp-value {
|
.rpg-temp-value {
|
||||||
font-size: clamp(0.7rem, 0.9rem, 1.1rem);
|
font-size: 0.65rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: var(--rpg-text);
|
color: var(--rpg-text);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clock Widget */
|
/* Clock Widget */
|
||||||
@@ -1534,18 +1538,19 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-around;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5rem;
|
padding: 0.25rem;
|
||||||
|
gap: 0.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rpg-clock {
|
.rpg-clock {
|
||||||
width: clamp(3rem, 60%, 6rem);
|
width: 2.5rem;
|
||||||
height: clamp(3rem, 60%, 6rem);
|
height: 2.5rem;
|
||||||
aspect-ratio: 1 / 1;
|
aspect-ratio: 1 / 1;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: rgba(0, 0, 0, 0.4);
|
background: rgba(0, 0, 0, 0.4);
|
||||||
border: 3px solid var(--rpg-border);
|
border: 2px solid var(--rpg-border);
|
||||||
box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.5);
|
box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.5);
|
||||||
position: relative;
|
position: relative;
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
@@ -1593,10 +1598,11 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.rpg-time-value {
|
.rpg-time-value {
|
||||||
font-size: clamp(0.7rem, 0.9rem, 1.1rem);
|
font-size: 0.65rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: var(--rpg-text);
|
color: var(--rpg-text);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Location Widget - Map */
|
/* Location Widget - Map */
|
||||||
@@ -1623,7 +1629,7 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.rpg-map-marker {
|
.rpg-map-marker {
|
||||||
font-size: clamp(1.5rem, 4vh, 3rem);
|
font-size: 2rem;
|
||||||
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.8));
|
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.8));
|
||||||
animation: markerPulse 2s ease-in-out infinite;
|
animation: markerPulse 2s ease-in-out infinite;
|
||||||
}
|
}
|
||||||
@@ -1634,7 +1640,7 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.rpg-location-text {
|
.rpg-location-text {
|
||||||
font-size: clamp(0.7rem, 0.9rem, 1.1rem);
|
font-size: 0.75rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: var(--rpg-text);
|
color: var(--rpg-text);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
Reference in New Issue
Block a user