mirror of https://github.com/kortix-ai/suna.git
381 lines
12 KiB
JavaScript
381 lines
12 KiB
JavaScript
// Enhanced UI elements for RideShare app
|
|
|
|
// Add floating action button for quick actions
|
|
function addFloatingActionButton() {
|
|
const fab = document.createElement('div');
|
|
fab.className = 'floating-action-button';
|
|
fab.innerHTML = '<i class="fas fa-plus"></i>';
|
|
fab.style.position = 'absolute';
|
|
fab.style.bottom = '100px';
|
|
fab.style.right = '20px';
|
|
fab.style.width = '56px';
|
|
fab.style.height = '56px';
|
|
fab.style.borderRadius = '50%';
|
|
fab.style.backgroundColor = '#276EF1';
|
|
fab.style.color = 'white';
|
|
fab.style.display = 'flex';
|
|
fab.style.alignItems = 'center';
|
|
fab.style.justifyContent = 'center';
|
|
fab.style.boxShadow = '0 4px 8px rgba(0,0,0,0.2)';
|
|
fab.style.cursor = 'pointer';
|
|
fab.style.zIndex = '100';
|
|
fab.style.transition = 'transform 0.2s, background-color 0.2s';
|
|
|
|
// Add hover effect
|
|
fab.addEventListener('mouseenter', () => {
|
|
fab.style.transform = 'scale(1.1)';
|
|
});
|
|
|
|
fab.addEventListener('mouseleave', () => {
|
|
fab.style.transform = 'scale(1)';
|
|
});
|
|
|
|
// Add click functionality to show quick actions menu
|
|
let isMenuOpen = false;
|
|
fab.addEventListener('click', () => {
|
|
if (!isMenuOpen) {
|
|
showQuickActionsMenu(fab);
|
|
fab.innerHTML = '<i class="fas fa-times"></i>';
|
|
isMenuOpen = true;
|
|
} else {
|
|
hideQuickActionsMenu();
|
|
fab.innerHTML = '<i class="fas fa-plus"></i>';
|
|
isMenuOpen = false;
|
|
}
|
|
});
|
|
|
|
document.querySelector('.map-container').appendChild(fab);
|
|
return fab;
|
|
}
|
|
|
|
// Show quick actions menu
|
|
function showQuickActionsMenu(fab) {
|
|
const actions = [
|
|
{ icon: 'fa-home', label: 'Home', action: () => selectSavedPlace('Home') },
|
|
{ icon: 'fa-briefcase', label: 'Work', action: () => selectSavedPlace('Work') },
|
|
{ icon: 'fa-clock', label: 'Schedule', action: () => document.getElementById('scheduleRideBtn').click() },
|
|
{ icon: 'fa-history', label: 'History', action: () => document.getElementById('tripHistoryBtn').click() }
|
|
];
|
|
|
|
const menu = document.createElement('div');
|
|
menu.className = 'quick-actions-menu';
|
|
menu.style.position = 'absolute';
|
|
menu.style.bottom = '170px';
|
|
menu.style.right = '20px';
|
|
menu.style.display = 'flex';
|
|
menu.style.flexDirection = 'column';
|
|
menu.style.alignItems = 'flex-end';
|
|
menu.style.gap = '10px';
|
|
menu.style.zIndex = '99';
|
|
|
|
actions.forEach((action, index) => {
|
|
const item = document.createElement('div');
|
|
item.className = 'quick-action-item';
|
|
item.innerHTML = `
|
|
<div class="action-label">${action.label}</div>
|
|
<div class="action-button">
|
|
<i class="fas ${action.icon}"></i>
|
|
</div>
|
|
`;
|
|
item.style.display = 'flex';
|
|
item.style.alignItems = 'center';
|
|
item.style.gap = '10px';
|
|
item.style.opacity = '0';
|
|
item.style.transform = 'translateY(20px)';
|
|
item.style.transition = 'opacity 0.2s, transform 0.2s';
|
|
item.style.transitionDelay = `${index * 0.05}s`;
|
|
|
|
const actionButton = item.querySelector('.action-button');
|
|
actionButton.style.width = '48px';
|
|
actionButton.style.height = '48px';
|
|
actionButton.style.borderRadius = '50%';
|
|
actionButton.style.backgroundColor = 'white';
|
|
actionButton.style.color = '#276EF1';
|
|
actionButton.style.display = 'flex';
|
|
actionButton.style.alignItems = 'center';
|
|
actionButton.style.justifyContent = 'center';
|
|
actionButton.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)';
|
|
actionButton.style.cursor = 'pointer';
|
|
|
|
const actionLabel = item.querySelector('.action-label');
|
|
actionLabel.style.backgroundColor = 'rgba(0,0,0,0.7)';
|
|
actionLabel.style.color = 'white';
|
|
actionLabel.style.padding = '5px 10px';
|
|
actionLabel.style.borderRadius = '4px';
|
|
actionLabel.style.fontSize = '14px';
|
|
|
|
item.addEventListener('click', () => {
|
|
action.action();
|
|
hideQuickActionsMenu();
|
|
fab.innerHTML = '<i class="fas fa-plus"></i>';
|
|
});
|
|
|
|
menu.appendChild(item);
|
|
|
|
// Trigger animation after a small delay
|
|
setTimeout(() => {
|
|
item.style.opacity = '1';
|
|
item.style.transform = 'translateY(0)';
|
|
}, 10);
|
|
});
|
|
|
|
menu.id = 'quickActionsMenu';
|
|
document.querySelector('.map-container').appendChild(menu);
|
|
}
|
|
|
|
// Hide quick actions menu
|
|
function hideQuickActionsMenu() {
|
|
const menu = document.getElementById('quickActionsMenu');
|
|
if (menu) {
|
|
const items = menu.querySelectorAll('.quick-action-item');
|
|
items.forEach((item, index) => {
|
|
item.style.opacity = '0';
|
|
item.style.transform = 'translateY(20px)';
|
|
item.style.transitionDelay = `${(items.length - index - 1) * 0.05}s`;
|
|
});
|
|
|
|
setTimeout(() => {
|
|
menu.remove();
|
|
}, items.length * 50 + 200);
|
|
}
|
|
}
|
|
|
|
// Helper function to select a saved place
|
|
function selectSavedPlace(place) {
|
|
const savedPlaces = document.querySelectorAll('.saved-place');
|
|
savedPlaces.forEach(savedPlace => {
|
|
if (savedPlace.querySelector('span').textContent === place) {
|
|
savedPlace.click();
|
|
}
|
|
});
|
|
}
|
|
|
|
// Add a map style switcher
|
|
function addMapStyleSwitcher() {
|
|
const styleSwitch = document.createElement('div');
|
|
styleSwitch.className = 'map-style-switcher';
|
|
styleSwitch.innerHTML = `
|
|
<div class="style-option selected" data-style="streets">
|
|
<i class="fas fa-road"></i>
|
|
<span>Streets</span>
|
|
</div>
|
|
<div class="style-option" data-style="satellite">
|
|
<i class="fas fa-satellite"></i>
|
|
<span>Satellite</span>
|
|
</div>
|
|
<div class="style-option" data-style="dark">
|
|
<i class="fas fa-moon"></i>
|
|
<span>Dark</span>
|
|
</div>
|
|
`;
|
|
|
|
styleSwitch.style.position = 'absolute';
|
|
styleSwitch.style.top = '120px';
|
|
styleSwitch.style.right = '10px';
|
|
styleSwitch.style.backgroundColor = 'white';
|
|
styleSwitch.style.borderRadius = '8px';
|
|
styleSwitch.style.boxShadow = '0 2px 6px rgba(0,0,0,0.1)';
|
|
styleSwitch.style.overflow = 'hidden';
|
|
styleSwitch.style.zIndex = '100';
|
|
|
|
const styleOptions = styleSwitch.querySelectorAll('.style-option');
|
|
styleOptions.forEach(option => {
|
|
option.style.padding = '8px 12px';
|
|
option.style.display = 'flex';
|
|
option.style.alignItems = 'center';
|
|
option.style.gap = '8px';
|
|
option.style.cursor = 'pointer';
|
|
option.style.transition = 'background-color 0.2s';
|
|
|
|
option.addEventListener('mouseenter', () => {
|
|
if (!option.classList.contains('selected')) {
|
|
option.style.backgroundColor = '#f5f5f5';
|
|
}
|
|
});
|
|
|
|
option.addEventListener('mouseleave', () => {
|
|
if (!option.classList.contains('selected')) {
|
|
option.style.backgroundColor = 'white';
|
|
}
|
|
});
|
|
|
|
option.addEventListener('click', () => {
|
|
styleOptions.forEach(opt => {
|
|
opt.classList.remove('selected');
|
|
opt.style.backgroundColor = 'white';
|
|
opt.style.fontWeight = 'normal';
|
|
});
|
|
|
|
option.classList.add('selected');
|
|
option.style.backgroundColor = '#f5f5f5';
|
|
option.style.fontWeight = 'bold';
|
|
|
|
// Change map style
|
|
const style = option.getAttribute('data-style');
|
|
switch(style) {
|
|
case 'streets':
|
|
window.map.setStyle('mapbox://styles/mapbox/streets-v11');
|
|
break;
|
|
case 'satellite':
|
|
window.map.setStyle('mapbox://styles/mapbox/satellite-streets-v11');
|
|
break;
|
|
case 'dark':
|
|
window.map.setStyle('mapbox://styles/mapbox/dark-v10');
|
|
break;
|
|
}
|
|
});
|
|
});
|
|
|
|
document.querySelector('.map-container').appendChild(styleSwitch);
|
|
}
|
|
|
|
// Add a traffic toggle button
|
|
function addTrafficToggle() {
|
|
const trafficToggle = document.createElement('div');
|
|
trafficToggle.className = 'traffic-toggle';
|
|
trafficToggle.innerHTML = `
|
|
<i class="fas fa-traffic-light"></i>
|
|
<span>Traffic</span>
|
|
`;
|
|
|
|
trafficToggle.style.position = 'absolute';
|
|
trafficToggle.style.top = '70px';
|
|
trafficToggle.style.left = '10px';
|
|
trafficToggle.style.backgroundColor = 'white';
|
|
trafficToggle.style.padding = '8px 12px';
|
|
trafficToggle.style.borderRadius = '20px';
|
|
trafficToggle.style.boxShadow = '0 2px 6px rgba(0,0,0,0.1)';
|
|
trafficToggle.style.display = 'flex';
|
|
trafficToggle.style.alignItems = 'center';
|
|
trafficToggle.style.gap = '8px';
|
|
trafficToggle.style.cursor = 'pointer';
|
|
trafficToggle.style.zIndex = '100';
|
|
trafficToggle.style.fontSize = '14px';
|
|
|
|
let trafficEnabled = false;
|
|
|
|
trafficToggle.addEventListener('click', () => {
|
|
trafficEnabled = !trafficEnabled;
|
|
|
|
if (trafficEnabled) {
|
|
trafficToggle.style.backgroundColor = '#276EF1';
|
|
trafficToggle.style.color = 'white';
|
|
|
|
// In a real app, this would add a traffic layer to the map
|
|
showToast('Traffic layer enabled');
|
|
|
|
// Simulate traffic data
|
|
if (window.map.getSource('route')) {
|
|
window.map.setPaintProperty('route', 'line-color', [
|
|
'step',
|
|
['random'],
|
|
'#4CAF50', // Green for low traffic
|
|
0.3, '#FFC107', // Yellow for medium traffic
|
|
0.6, '#FF5722' // Red for heavy traffic
|
|
]);
|
|
}
|
|
|
|
} else {
|
|
trafficToggle.style.backgroundColor = 'white';
|
|
trafficToggle.style.color = 'black';
|
|
|
|
// In a real app, this would remove the traffic layer
|
|
showToast('Traffic layer disabled');
|
|
|
|
// Reset route color
|
|
if (window.map.getSource('route')) {
|
|
window.map.setPaintProperty('route', 'line-color', '#276EF1');
|
|
}
|
|
}
|
|
});
|
|
|
|
document.querySelector('.map-container').appendChild(trafficToggle);
|
|
}
|
|
|
|
// Add voice command functionality
|
|
function addVoiceCommandButton() {
|
|
const voiceButton = document.createElement('div');
|
|
voiceButton.className = 'voice-command-button';
|
|
voiceButton.innerHTML = '<i class="fas fa-microphone"></i>';
|
|
voiceButton.style.position = 'absolute';
|
|
voiceButton.style.bottom = '170px';
|
|
voiceButton.style.right = '20px';
|
|
voiceButton.style.width = '48px';
|
|
voiceButton.style.height = '48px';
|
|
voiceButton.style.borderRadius = '50%';
|
|
voiceButton.style.backgroundColor = 'white';
|
|
voiceButton.style.color = '#276EF1';
|
|
voiceButton.style.display = 'flex';
|
|
voiceButton.style.alignItems = 'center';
|
|
voiceButton.style.justifyContent = 'center';
|
|
voiceButton.style.boxShadow = '0 2px 6px rgba(0,0,0,0.2)';
|
|
voiceButton.style.cursor = 'pointer';
|
|
voiceButton.style.zIndex = '100';
|
|
voiceButton.style.transition = 'transform 0.2s, background-color 0.2s';
|
|
|
|
// Add hover effect
|
|
voiceButton.addEventListener('mouseenter', () => {
|
|
voiceButton.style.transform = 'scale(1.1)';
|
|
});
|
|
|
|
voiceButton.addEventListener('mouseleave', () => {
|
|
voiceButton.style.transform = 'scale(1)';
|
|
});
|
|
|
|
// Add click functionality
|
|
voiceButton.addEventListener('click', () => {
|
|
// Simulate voice recognition
|
|
voiceButton.style.backgroundColor = '#276EF1';
|
|
voiceButton.style.color = 'white';
|
|
voiceButton.innerHTML = '<i class="fas fa-microphone-alt"></i>';
|
|
|
|
showToast('Listening for commands...');
|
|
|
|
// Simulate processing
|
|
setTimeout(() => {
|
|
voiceButton.style.backgroundColor = 'white';
|
|
voiceButton.style.color = '#276EF1';
|
|
voiceButton.innerHTML = '<i class="fas fa-microphone"></i>';
|
|
|
|
// Simulate a random command
|
|
const commands = [
|
|
'Take me home',
|
|
'Take me to work',
|
|
'Show my trip history',
|
|
'Schedule a ride'
|
|
];
|
|
|
|
const randomCommand = commands[Math.floor(Math.random() * commands.length)];
|
|
showToast(`Command recognized: "${randomCommand}"`);
|
|
|
|
// Execute the simulated command
|
|
setTimeout(() => {
|
|
if (randomCommand === 'Take me home') {
|
|
selectSavedPlace('Home');
|
|
} else if (randomCommand === 'Take me to work') {
|
|
selectSavedPlace('Work');
|
|
} else if (randomCommand === 'Show my trip history') {
|
|
document.getElementById('tripHistoryBtn').click();
|
|
} else if (randomCommand === 'Schedule a ride') {
|
|
document.getElementById('scheduleRideBtn').click();
|
|
}
|
|
}, 500);
|
|
}, 2000);
|
|
});
|
|
|
|
document.querySelector('.map-container').appendChild(voiceButton);
|
|
}
|
|
|
|
// Initialize enhanced UI
|
|
function initEnhancedUI() {
|
|
// Add with a slight delay to ensure the map is loaded
|
|
setTimeout(() => {
|
|
addFloatingActionButton();
|
|
addMapStyleSwitcher();
|
|
addTrafficToggle();
|
|
addVoiceCommandButton();
|
|
}, 1500);
|
|
}
|
|
|
|
// Export to window
|
|
window.initEnhancedUI = initEnhancedUI; |