diff --git a/src/App.js b/src/App.js index 22bbd77..dda415e 100644 --- a/src/App.js +++ b/src/App.js @@ -131,6 +131,7 @@ class App extends React.Component { featuredObject: { msg: "Click a table row to select object" }, extraColumns: [], toggleOptions: Object.fromEntries(ALL_TOGGLES.map((t) => [t.id, false])), + isDataframeCollapsed: false, filters: { logTypes: { createVehicle: true, @@ -1082,6 +1083,12 @@ class App extends React.Component { })); }; + toggleDataframe = () => { + this.setState((prevState) => ({ + isDataframeCollapsed: !prevState.isDataframeCollapsed, + })); + }; + render() { const { featuredObject, @@ -1092,13 +1099,49 @@ class App extends React.Component { dynamicMarkerLocations, visibleToggles, filters, + isDataframeCollapsed, } = this.state; const selectedEventTime = featuredObject?.timestamp ? new Date(featuredObject.timestamp).getTime() : null; const availableFilters = currentLogData.solutionType === "ODRD" ? ODRD_FILTERS : []; return ( -
+
+
diff --git a/src/Dataframe.js b/src/Dataframe.js index be6b8bc..10208df 100644 --- a/src/Dataframe.js +++ b/src/Dataframe.js @@ -199,11 +199,13 @@ function Dataframe({ featuredObject, extraColumns, onColumnToggle, onToggleMarke }, []); return ( -
+
- +
-
+
{ describe("formatDistance", () => { test("formats under 1000 meters correctly", () => { const { metric, imperial } = formatDistance(500); - expect(metric).toBe("500.0 m"); - expect(imperial).toBe("1640.4 ft"); + expect(metric).toBe("500 m"); + expect(imperial).toBe("1640 ft"); }); test("formats over 1000 meters into km and miles", () => { diff --git a/src/Utils.js b/src/Utils.js index 960c3a5..166f979 100644 --- a/src/Utils.js +++ b/src/Utils.js @@ -152,9 +152,9 @@ export function formatDistance(distanceMeters) { const distanceFeet = distanceMeters * 3.28084; const distanceMiles = distanceMeters * 0.000621371; - const metric = distanceMeters < 1000 ? distanceMeters.toFixed(1) + " m" : (distanceMeters / 1000).toFixed(2) + " km"; + const metric = distanceMeters < 1000 ? distanceMeters.toFixed(0) + " m" : (distanceMeters / 1000).toFixed(2) + " km"; - const imperial = distanceFeet < 5280 ? distanceFeet.toFixed(1) + " ft" : distanceMiles.toFixed(2) + " mi"; + const imperial = distanceFeet < 5280 ? distanceFeet.toFixed(0) + " ft" : distanceMiles.toFixed(2) + " mi"; return { metric, imperial }; } diff --git a/src/global.css b/src/global.css index 1822461..6837ee5 100644 --- a/src/global.css +++ b/src/global.css @@ -1,4 +1,11 @@ /* global.css */ +body, +html { + margin: 0; + padding: 0; + height: 100%; +} + /* Tooltip styles */ [class^="rc-slider-tooltip"] { min-height: 30px; @@ -101,8 +108,6 @@ transform: translateX(-50%); } - - /* Map and button styles */ .map-button { height: 40px; @@ -170,9 +175,11 @@ } .follow-vehicle-button.active .follow-vehicle-background { - border: 2px solid #4285F4; + border: 2px solid #4285f4; background-color: #d1dff7; - box-shadow: 0 0 8px rgba(66, 133, 244, 0.6), inset 0 0 6px rgba(66, 133, 244, 0.6); + box-shadow: + 0 0 8px rgba(66, 133, 244, 0.6), + inset 0 0 6px rgba(66, 133, 244, 0.6); } /* Cloud logging styles */ @@ -216,7 +223,7 @@ } .sideload-logs-button { - background-color: #34A853; + background-color: #34a853; color: white; padding: 12px 6px; border: none; @@ -251,7 +258,7 @@ } .cloud-logging-file-button { - background-color: #34A853; + background-color: #34a853; flex: 1; } @@ -263,12 +270,15 @@ .app-container { display: flex; height: 100vh; + position: relative; + overflow: hidden; } .main-content { width: 70%; display: flex; flex-direction: column; + transition: width 0.3s ease; } .map-and-control-section { @@ -281,9 +291,78 @@ width: 30%; height: 100%; overflow: auto; + transition: width 0.3s ease; +} + +.app-container.dataframe-collapsed .main-content { + width: 100%; +} + +.app-container.dataframe-collapsed .dataframe-section { + width: 0; + overflow: hidden; } -/* Navigation controls */ +.dataframe-header-inner { + display: flex; + align-items: center; + justify-content: flex-end; + padding: 8px; + gap: 8px; + flex-shrink: 0; +} + +.dataframe-toggle-tab { + position: absolute; + right: 30%; + /* Will be the edge of the dataframe section when expanded */ + bottom: 24px; + width: 32px; + height: 48px; + background-color: #f1f3f4; + border: 1px solid #dadce0; + border-right: none; + border-radius: 24px 0 0 24px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + z-index: 1000; + transition: right 0.3s ease, background-color 0.2s ease; + color: #5f6368; + box-shadow: -2px 0 4px rgba(0, 0, 0, 0.05); +} + +.dataframe-toggle-tab:hover { + background-color: #e8eaed; +} + +.app-container.dataframe-collapsed .dataframe-toggle-tab { + right: 0; +} + +.copy-object-button { + padding: 6px 12px; + background-color: transparent; + border: 1px solid #ccc; + border-radius: 4px; + cursor: pointer; + font-size: 13px; + color: #555; + transition: all 0.2s ease; +} + +.copy-object-button:hover { + background-color: #f5f5f5; +} + +.dataframe-content { + overflow: auto; + flex-grow: 1; + padding: 8, 8, 8, 0; +} + +/* App layout styles */ .nav-controls { display: flex; flex-direction: column; @@ -328,12 +407,12 @@ } .dataset-button-active { - background-color: #4CAF50; + background-color: #4caf50; padding: 10px 25px 10px 10px; } .dataset-button-uploaded { - background-color: #008CBA; + background-color: #008cba; padding: 10px 25px 10px 10px; } @@ -591,11 +670,13 @@ } .map-toggle-button.active { - color: #4285F4; + color: #4285f4; background-color: rgba(209, 223, 247, 0.5); - border: 2px solid #4285F4; + border: 2px solid #4285f4; border-radius: 20px; - box-shadow: 0 0 8px rgba(66, 133, 244, 0.4), inset 0 0 4px rgba(66, 133, 244, 0.2); + box-shadow: + 0 0 8px rgba(66, 133, 244, 0.4), + inset 0 0 4px rgba(66, 133, 244, 0.2); } .map-toggle-separator { @@ -603,6 +684,7 @@ height: 100%; background-color: rgba(0, 0, 0, 0.15); } + /* Resizer styles for react-table */ .resizer { display: inline-block; @@ -618,6 +700,7 @@ cursor: col-resize; } -.resizer:hover, .resizer.isResizing { +.resizer:hover, +.resizer.isResizing { background: rgba(0, 0, 0, 0.5); -} +} \ No newline at end of file