Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7,426 changes: 3,239 additions & 4,187 deletions package-lock.json

Large diffs are not rendered by default.

24 changes: 22 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,27 @@
"format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx}\""
},
"dependencies": {
"@heroui/accordion": "^2.2.24",
"@heroui/alert": "^2.2.27",
"@heroui/autocomplete": "^2.3.29",
"@heroui/avatar": "^2.2.22",
"@heroui/button": "^2.2.27",
"@heroui/card": "^2.2.25",
"@heroui/chip": "^2.2.22",
"@heroui/code": "^2.2.21",
"@heroui/dropdown": "^2.3.27",
"@heroui/input": "^2.4.28",
"@heroui/kbd": "^2.2.22",
"@heroui/link": "^2.2.23",
"@heroui/modal": "^2.2.24",
"@heroui/navbar": "^2.2.25",
"@heroui/react": "^2.6.13",
"@heroui/select": "^2.4.28",
"@heroui/slider": "^2.4.24",
"@heroui/spinner": "^2.2.24",
"@heroui/switch": "^2.2.24",
"@heroui/table": "^2.2.27",
"@heroui/tooltip": "^2.2.24",
"@turf/boolean-point-in-polygon": "^7.2.0",
"@turf/helpers": "^7.2.0",
"js-cookie": "^3.0.5",
Expand All @@ -25,19 +45,19 @@
},
"devDependencies": {
"@eslint/js": "^9.15.0",
"@tailwindcss/postcss": "^4.1.17",
"@types/js-cookie": "^3.0.6",
"@types/maplibre-gl": "^1.13.2",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react": "^4.3.4",
"autoprefixer": "^10.4.20",
"eslint": "^9.15.0",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.14",
"globals": "^15.12.0",
"postcss": "^8.4.49",
"prettier": "^3.6.2",
"tailwindcss": "^3.4.17",
"tailwindcss": "^4.1.17",
"typescript": "~5.6.2",
"typescript-eslint": "^8.15.0",
"vite": "^6.0.1"
Expand Down
3 changes: 1 addition & 2 deletions postcss.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
'@tailwindcss/postcss': {},
},
};
32 changes: 29 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const App: React.FC = () => {
const [nameFixAction, setNameFixAction] = useState<string>("check");
const [streetAbbreviationAction, setStreetAbbreviationAction] =
useState<string>("expand");
const [laneTagFixAction, setLaneTagFixAction] = useState<string>("remove");
const [showHelpModal, setShowHelpModal] = useState(false);
const [showSettingsModal, setShowSettingsModal] = useState(false);
const [showAreaCompletedModal, setShowAreaCompletedModal] = useState(false);
Expand Down Expand Up @@ -103,6 +104,26 @@ const App: React.FC = () => {
[findNumberedNameTags],
);

const applyLaneTagFixes = useCallback(
(tags: Tags): Tags => {
const currentWayTags = overpassWays[currentWay]?.tags;
if (!currentWayTags) return tags;

const updatedTags = { ...tags };

// Remove lane tags on unpaved surfaces if action is "remove"
if (laneTagFixAction === "remove") {
delete updatedTags.lanes;
delete updatedTags["lanes:forward"];
delete updatedTags["lanes:backward"];
delete updatedTags.lane_markings;
}

return updatedTags;
},
[overpassWays, currentWay, laneTagFixAction],
);

const applyNameFixes = useCallback(
(tags: Tags): Tags => {
const currentWayTags = overpassWays[currentWay]?.tags;
Expand Down Expand Up @@ -189,12 +210,15 @@ const App: React.FC = () => {
// Step 2: Apply name fixes
processedTags = applyNameFixes(processedTags);

// Step 3: Add fixme message if provided
// Step 3: Apply lane tag fixes
processedTags = applyLaneTagFixes(processedTags);

// Step 4: Add fixme message if provided
if (includeFixmeMessage) {
processedTags["fixme:tigerking"] = includeFixmeMessage;
}

// Step 4: Add detail tags if requested
// Step 5: Add detail tags if requested
if (includeDetailTags) {
const detailTags = addDetailTags();
processedTags = { ...processedTags, ...detailTags };
Expand All @@ -205,7 +229,7 @@ const App: React.FC = () => {

return processedTags;
},
[filterTigerTags, applyNameFixes, addDetailTags],
[filterTigerTags, applyNameFixes, applyLaneTagFixes, addDetailTags],
);

const deduplicateNewWays = useCallback(
Expand Down Expand Up @@ -604,6 +628,8 @@ const App: React.FC = () => {
setNameFixAction={setNameFixAction}
streetAbbreviationAction={streetAbbreviationAction}
setStreetAbbreviationAction={setStreetAbbreviationAction}
laneTagFixAction={laneTagFixAction}
setLaneTagFixAction={setLaneTagFixAction}
onSkip={handleActions.skip}
onFix={handleActions.fix}
onClearTiger={handleActions.clearTiger}
Expand Down
7 changes: 6 additions & 1 deletion src/components/ActionButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import CustomMessageModal from "./modals/CustomMessageModal";
import LoginModal from "./modals/LoginModal";
import { useOsmAuthContext } from "../contexts/useOsmAuth";
import { useWayTagsStore } from "../stores/useWayTagsStore";
import { UNPAVED_SURFACES } from "../objects";

interface ActionButtonsProps {
onSkip: () => void;
Expand All @@ -33,6 +34,8 @@ const ActionButtons: React.FC<ActionButtonsProps> = ({
const [isFixModalOpen, setIsFixModalOpen] = useState(false);
const [customFixMessage, setCustomFixMessage] = useState("");
const { lanes, surface, laneMarkings } = useWayTagsStore();

const isUnpavedSurface = UNPAVED_SURFACES.includes(surface);
const { loggedIn, handleLogin } = useOsmAuthContext();

const fixOptions = [
Expand Down Expand Up @@ -167,7 +170,9 @@ const ActionButtons: React.FC<ActionButtonsProps> = ({
size="md"
className="flex-1"
onPress={handleSubmit}
isDisabled={!surface || (!lanes && laneMarkings)}
isDisabled={
!surface || (!isUnpavedSurface && !lanes && laneMarkings)
}
>
Submit
</Button>
Expand Down
8 changes: 2 additions & 6 deletions src/components/ImagerySelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,15 @@ const ImagerySelect: React.FC<ImagerySelectProps> = ({
{zoom > 8 && Object.keys(standardSources).length > 0 ? (
<SelectSection title={"Regional"}>
{Object.entries(standardSources).map(([id, source]) => (
<SelectItem key={id} value={id}>
{source.name}
</SelectItem>
<SelectItem key={id}>{source.name}</SelectItem>
))}
</SelectSection>
) : null}

{/* Base sources (Esri and USGS) */}
<SelectSection title={"National"}>
{Object.entries(baseSources).map(([id, source]) => (
<SelectItem key={id} value={id}>
{source.name}
</SelectItem>
<SelectItem key={id}>{source.name}</SelectItem>
))}
</SelectSection>
</>
Expand Down
98 changes: 87 additions & 11 deletions src/components/LanesButtons.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
import React from "react";
import { ButtonGroup } from "@heroui/button";
import { Button, ButtonGroup } from "@heroui/button";
import { Slider } from "@heroui/slider";
import TagButtonHeading from "./TagButtonHeading";
import toggleButton from "./ToggleButton";
import { useWayTagsStore } from "../stores/useWayTagsStore";
import { Chip } from "@heroui/react";
import { UNPAVED_SURFACES } from "../objects";

interface LanesButtonsProps {
showLaneDirection: boolean;
setShowLaneDirection: (value: boolean) => void;
currentTags: Record<string, string | undefined>;
}

const LanesButtons: React.FC<LanesButtonsProps> = ({
showLaneDirection,
setShowLaneDirection,
currentTags,
}) => {
const COMMON_LANES = ["2", "4"];

const {
lanes,
setLanes,
Expand All @@ -25,8 +29,44 @@ const LanesButtons: React.FC<LanesButtonsProps> = ({
setLanesForward,
lanesBackward,
setLanesBackward,
surface,
} = useWayTagsStore();

// Check if current surface is unpaved
const isUnpavedSurface = UNPAVED_SURFACES.includes(surface);

// Check if way already has lane tags in original OSM data
const hasExistingLaneTags = Boolean(
currentTags.lanes ||
currentTags["lanes:forward"] ||
currentTags["lanes:backward"] ||
currentTags.lane_markings,
);

// Disable lane buttons if unpaved surface and no existing lane tags
// This allows modification/removal of existing tags but prevents adding new ones
const lanesDisabled = isUnpavedSurface && !hasExistingLaneTags;

// Check if there's any lane data currently set (in store or original tags)
const hasAnyLaneData = Boolean(
lanes ||
lanesForward ||
lanesBackward ||
!laneMarkings ||
hasExistingLaneTags,
);

// Show remove button if unpaved surface with lane data present
const showRemoveButton = isUnpavedSurface && hasAnyLaneData;

const handleRemoveLaneData = () => {
setLanes("");
setLanesForward(0);
setLanesBackward(0);
setLaneMarkings(true);
setShowLaneDirection(false);
};

const renderSlider = (
label: string,
value: number,
Expand Down Expand Up @@ -67,40 +107,62 @@ const LanesButtons: React.FC<LanesButtonsProps> = ({
<div className="w-full">
<TagButtonHeading
header="lanes"
tooltip="The number of lanes on the road as indicated by painted stripes."
tooltip={
lanesDisabled
? "Lane tags are not applicable for unpaved surfaces. Existing tags can be removed."
: "The number of lanes on the road as indicated by painted stripes."
}
warning={lanesDisabled}
/>

<div className="flex gap-2">
{toggleButton(!laneMarkings, "none", () =>
setLaneMarkings(!laneMarkings),
)}
<Button
variant="bordered"
className={`flex-1 border-1 transition-all duration-200 ${
!laneMarkings
? "bg-primary-100 shadow-lg border-primary"
: "hover:bg-primary/10"
}`}
onPress={() => setLaneMarkings(!laneMarkings)}
isDisabled={lanesDisabled}
>
none
</Button>

<ButtonGroup
variant="bordered"
className="flex flex-wrap w-full"
size="md"
>
{COMMON_LANES.map((lanesKey) =>
toggleButton(lanesKey === lanes, lanesKey, () =>
setLanes(lanesKey),
toggleButton(
lanesKey === lanes,
lanesKey,
lanesDisabled ? undefined : () => setLanes(lanesKey),
false,
undefined,
lanesDisabled,
),
)}

{toggleButton(
Boolean(
(lanes && !COMMON_LANES.includes(lanes)) ||
lanesBackward ||
lanesForward,
lanesBackward ||
lanesForward,
),
undefined,
() => setShowLaneDirection(!showLaneDirection),
lanesDisabled
? undefined
: () => setShowLaneDirection(!showLaneDirection),
true,
<Chip>{lanes}</Chip>,
lanesDisabled,
)}
</ButtonGroup>
</div>

{showLaneDirection && (
{showLaneDirection && !lanesDisabled && (
<div className="space-y-4 mt-2">
{renderSlider(
"Lanes",
Expand All @@ -118,6 +180,20 @@ const LanesButtons: React.FC<LanesButtonsProps> = ({
)}
</div>
)}

{showRemoveButton && (
<div className="mt-2">
<Button
color="warning"
variant="flat"
size="sm"
className="w-full"
onPress={handleRemoveLaneData}
>
Remove lane data
</Button>
</div>
)}
</div>
);
};
Expand Down
6 changes: 6 additions & 0 deletions src/components/LeftPane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ interface LeftPaneProps {
setNameFixAction: (action: string) => void;
streetAbbreviationAction: string;
setStreetAbbreviationAction: (action: string) => void;
laneTagFixAction: string;
setLaneTagFixAction: (action: string) => void;
onSkip: () => void;
onFix: (message: string) => void;
onClearTiger: () => void;
Expand All @@ -47,6 +49,8 @@ const LeftPane: React.FC<LeftPaneProps> = ({
setNameFixAction,
streetAbbreviationAction,
setStreetAbbreviationAction,
laneTagFixAction,
setLaneTagFixAction,
onSkip,
onFix,
onClearTiger,
Expand Down Expand Up @@ -106,6 +110,8 @@ const LeftPane: React.FC<LeftPaneProps> = ({
setNameFixAction={setNameFixAction}
streetAbbreviationAction={streetAbbreviationAction}
setStreetAbbreviationAction={setStreetAbbreviationAction}
laneTagFixAction={laneTagFixAction}
setLaneTagFixAction={setLaneTagFixAction}
onSkip={onSkip}
onFix={onFix}
onClearTiger={onClearTiger}
Expand Down
3 changes: 1 addition & 2 deletions src/components/LocationAutocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export const LocationAutocomplete: React.FC<LocationAutocompleteProps> = ({
<Autocomplete
label={!compact ? "Location" : undefined}
aria-label={compact ? "Location Search" : undefined}
className={compact ? "flex-grow" : ""}
className={compact ? "grow" : ""}
placeholder="Enter a location"
listboxProps={{
emptyContent: "No OSM relations found.",
Expand Down Expand Up @@ -163,7 +163,6 @@ export const LocationAutocomplete: React.FC<LocationAutocompleteProps> = ({
key={index}
title={feature.properties.name}
description={generateLocationDescription(feature)}
value={feature.properties.name}
>
{feature.properties.name}
</AutocompleteItem>
Expand Down
4 changes: 2 additions & 2 deletions src/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ const MainNavbar: React.FC<NavbarProps> = ({

return (
<>
<Navbar maxWidth="full" position="static" className="shadow">
<NavbarBrand className="gap-4 flex-grow-0" as={Link} href="/tigerking/">
<Navbar maxWidth="full" position="static" className="shadow-sm">
<NavbarBrand className="gap-4 grow-0" as={Link} href="/tigerking/">
<img src={logo} alt="Logo" className="w-8 h-8" />
<h1 className="text-xl font-bold text-black dark:text-white">
TIGER King
Expand Down
Loading