feat(geo-map): add live traffic visualization and traffic-aware routing with pluggable providers and UI integration
This commit is contained in:
@@ -25,6 +25,9 @@ export const geoComponentStyles = css`
|
||||
*/
|
||||
export const mapContainerStyles = css`
|
||||
.map-container {
|
||||
--geo-overlay-inset: 12px;
|
||||
--geo-overlay-gap: 8px;
|
||||
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -37,6 +40,58 @@ export const mapContainerStyles = css`
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
}
|
||||
|
||||
/* Overlay grid for UI elements */
|
||||
.map-overlay {
|
||||
position: absolute;
|
||||
inset: var(--geo-overlay-inset);
|
||||
pointer-events: none;
|
||||
z-index: 5;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
grid-template-areas:
|
||||
"top-left . top-right"
|
||||
". . ."
|
||||
"bottom-left . bottom-right";
|
||||
gap: var(--geo-overlay-gap);
|
||||
}
|
||||
|
||||
.map-overlay > * {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.overlay-top-left {
|
||||
grid-area: top-left;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: var(--geo-overlay-gap);
|
||||
}
|
||||
|
||||
.overlay-top-right {
|
||||
grid-area: top-right;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
gap: var(--geo-overlay-gap);
|
||||
}
|
||||
|
||||
.overlay-bottom-left {
|
||||
grid-area: bottom-left;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: var(--geo-overlay-gap);
|
||||
}
|
||||
|
||||
.overlay-bottom-right {
|
||||
grid-area: bottom-right;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
gap: var(--geo-overlay-gap);
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
@@ -44,10 +99,6 @@ export const mapContainerStyles = css`
|
||||
*/
|
||||
export const toolbarStyles = css`
|
||||
.toolbar {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
left: 12px;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
@@ -57,6 +108,7 @@ export const toolbarStyles = css`
|
||||
border-radius: 8px;
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.toolbar-group {
|
||||
@@ -111,15 +163,11 @@ export const toolbarStyles = css`
|
||||
*/
|
||||
export const searchStyles = css`
|
||||
.search-container {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
z-index: 10;
|
||||
width: 280px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.search-input-wrapper {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: var(--geo-toolbar-bg, rgba(30, 30, 30, 0.9));
|
||||
@@ -127,7 +175,6 @@ export const searchStyles = css`
|
||||
border-radius: 8px;
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.search-input-wrapper:focus-within {
|
||||
@@ -224,6 +271,7 @@ export const searchStyles = css`
|
||||
border-radius: 8px;
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.search-results:empty {
|
||||
@@ -274,10 +322,6 @@ export const searchStyles = css`
|
||||
*/
|
||||
export const navigationStyles = css`
|
||||
.navigation-panel {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
left: 60px;
|
||||
z-index: 10;
|
||||
width: 300px;
|
||||
background: var(--geo-toolbar-bg, rgba(30, 30, 30, 0.95));
|
||||
border: 1px solid var(--geo-toolbar-border, rgba(255, 255, 255, 0.1));
|
||||
@@ -285,6 +329,7 @@ export const navigationStyles = css`
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
overflow: hidden;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.nav-header {
|
||||
@@ -484,7 +529,7 @@ export const navigationStyles = css`
|
||||
background: var(--geo-toolbar-bg, rgba(30, 30, 30, 0.98));
|
||||
border: 1px solid var(--geo-toolbar-border, rgba(255, 255, 255, 0.1));
|
||||
border-radius: 6px;
|
||||
z-index: 100;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.nav-search-result {
|
||||
@@ -686,4 +731,330 @@ export const navigationStyles = css`
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Traffic-aware route info */
|
||||
.nav-traffic-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
background: rgba(255, 152, 0, 0.1);
|
||||
border-radius: 6px;
|
||||
margin: 8px 12px;
|
||||
}
|
||||
|
||||
.nav-traffic-info.low {
|
||||
background: rgba(0, 200, 83, 0.1);
|
||||
}
|
||||
|
||||
.nav-traffic-info.moderate {
|
||||
background: rgba(255, 235, 59, 0.15);
|
||||
}
|
||||
|
||||
.nav-traffic-info.heavy {
|
||||
background: rgba(255, 152, 0, 0.15);
|
||||
}
|
||||
|
||||
.nav-traffic-info.severe {
|
||||
background: rgba(244, 67, 54, 0.15);
|
||||
}
|
||||
|
||||
.nav-traffic-indicator {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.nav-traffic-indicator.low {
|
||||
background: #00c853;
|
||||
}
|
||||
|
||||
.nav-traffic-indicator.moderate {
|
||||
background: #ffeb3b;
|
||||
}
|
||||
|
||||
.nav-traffic-indicator.heavy {
|
||||
background: #ff9800;
|
||||
}
|
||||
|
||||
.nav-traffic-indicator.severe {
|
||||
background: #f44336;
|
||||
}
|
||||
|
||||
.nav-traffic-text {
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
.nav-traffic-delay {
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
margin-left: auto;
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* Traffic control styles
|
||||
*/
|
||||
/**
|
||||
* Header toolbar styles for toolbar above map
|
||||
*/
|
||||
export const headerToolbarStyles = css`
|
||||
.geo-component {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.header-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 8px 12px;
|
||||
background: var(--geo-toolbar-bg, rgba(30, 30, 30, 0.95));
|
||||
border-bottom: 1px solid var(--geo-toolbar-border, rgba(255, 255, 255, 0.1));
|
||||
flex-shrink: 0;
|
||||
min-height: 52px;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.toolbar-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.toolbar-center {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.toolbar-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.header-toolbar .toolbar-divider {
|
||||
width: 1px;
|
||||
height: 24px;
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
margin: 0 4px;
|
||||
}
|
||||
|
||||
/* Header toolbar button styles */
|
||||
.header-toolbar .tool-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
padding: 0;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
background: transparent;
|
||||
color: var(--geo-text, #fff);
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s ease, color 0.15s ease;
|
||||
}
|
||||
|
||||
.header-toolbar .tool-button:hover {
|
||||
background: var(--geo-tool-hover, rgba(255, 255, 255, 0.1));
|
||||
}
|
||||
|
||||
.header-toolbar .tool-button.active {
|
||||
background: var(--geo-tool-active, #0084ff);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.header-toolbar .tool-button:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.header-toolbar .tool-button svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
/* Search container in header */
|
||||
.header-toolbar .search-container {
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
/* Map container takes remaining space */
|
||||
.geo-component .map-container {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
min-height: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* Traffic control styles
|
||||
*/
|
||||
export const trafficStyles = css`
|
||||
.traffic-control {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.traffic-toggle-btn {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
padding: 0;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
background: var(--geo-toolbar-bg, rgba(30, 30, 30, 0.9));
|
||||
border: 1px solid var(--geo-toolbar-border, rgba(255, 255, 255, 0.1));
|
||||
color: var(--geo-text, #fff);
|
||||
cursor: pointer;
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
|
||||
}
|
||||
|
||||
.traffic-toggle-btn:hover:not(:disabled) {
|
||||
background: var(--geo-tool-hover, rgba(255, 255, 255, 0.15));
|
||||
}
|
||||
|
||||
.traffic-toggle-btn.active {
|
||||
background: var(--geo-tool-active, #0084ff);
|
||||
border-color: var(--geo-tool-active, #0084ff);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.traffic-toggle-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.traffic-toggle-btn svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.traffic-loading-indicator {
|
||||
position: absolute;
|
||||
bottom: 2px;
|
||||
right: 2px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background: var(--geo-toolbar-bg, rgba(30, 30, 30, 0.9));
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.traffic-loading-indicator svg {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
.traffic-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 6px 12px;
|
||||
background: var(--geo-toolbar-bg, rgba(30, 30, 30, 0.9));
|
||||
border: 1px solid var(--geo-toolbar-border, rgba(255, 255, 255, 0.1));
|
||||
border-radius: 6px;
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
.traffic-status-dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: #00c853;
|
||||
animation: pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.5; }
|
||||
}
|
||||
|
||||
.traffic-status-text {
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.traffic-error {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
color: #f44336;
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.traffic-error svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
/* Traffic Legend */
|
||||
.traffic-legend {
|
||||
padding: 10px 12px;
|
||||
background: var(--geo-toolbar-bg, rgba(30, 30, 30, 0.9));
|
||||
border: 1px solid var(--geo-toolbar-border, rgba(255, 255, 255, 0.1));
|
||||
border-radius: 8px;
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
.traffic-legend-title {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.traffic-legend-items {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.traffic-legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
.traffic-legend-color {
|
||||
width: 16px;
|
||||
height: 4px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.traffic-legend-updated {
|
||||
margin-top: 8px;
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
font-size: 10px;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user