diff --git a/src/Components/AppShell/AppShell.tsx b/src/Components/AppShell/AppShell.tsx index f8b050fc..6be2a031 100644 --- a/src/Components/AppShell/AppShell.tsx +++ b/src/Components/AppShell/AppShell.tsx @@ -23,15 +23,15 @@ export function AppShell({ appName, children, assetsApi }: { appName: string, ch return ( - - - - - - - - - + + + + + + + + + @@ -55,15 +55,15 @@ export function AppShell({ appName, children, assetsApi }: { appName: string, ch - - - - - - - - - + + + + + + + + + ) } diff --git a/src/Components/Map/Subcomponents/Controls/Control.tsx b/src/Components/Map/Subcomponents/Controls/Control.tsx index 4adf3005..a7bf2707 100644 --- a/src/Components/Map/Subcomponents/Controls/Control.tsx +++ b/src/Components/Map/Subcomponents/Controls/Control.tsx @@ -3,7 +3,7 @@ import * as React from 'react' -export const Control = ({ position, children, zIndex }: { position: "topLeft" | "topRight" | "bottomLeft" | "bottomRight", children: React.ReactNode, zIndex: string }) => { +export const Control = ({ position, children, zIndex, absolute }: { position: "topLeft" | "topRight" | "bottomLeft" | "bottomRight", children: React.ReactNode, zIndex: string, absolute: boolean }) => { const controlContainerRef = React.createRef() @@ -17,7 +17,7 @@ export const Control = ({ position, children, zIndex }: { position: "topLeft" | }, [controlContainerRef]) return ( -
+
{children}
diff --git a/src/Components/Map/Subcomponents/Controls/SearchControl.tsx b/src/Components/Map/Subcomponents/Controls/SearchControl.tsx index 280050fb..a79b51df 100644 --- a/src/Components/Map/Subcomponents/Controls/SearchControl.tsx +++ b/src/Components/Map/Subcomponents/Controls/SearchControl.tsx @@ -88,7 +88,7 @@ export const SearchControl = () => { useEffect(() => { let params = new URLSearchParams(location.search); let embedded = params.get("embedded"); - embedded != "true" && setEmbedded(false) + embedded != "true" && setEmbedded(false) }, [location]); @@ -97,6 +97,7 @@ export const SearchControl = () => {
{embedded && } +
setValue(e.target.value)} @@ -105,9 +106,10 @@ export const SearchControl = () => { if (windowDimensions.width < 500) map.closePopup(); }} onBlur={() => hide()} /> + {value.length > 0 && } +
- {value.length > 0 && } {hideSuggestions || Array.from(geoResults).length == 0 && itemsResults.length == 0 && tagsResults.length == 0 && !isGeoCoordinate(value) || value.length == 0 ? "" :
{tagsResults.length > 0 && @@ -115,8 +117,6 @@ export const SearchControl = () => { {tagsResults.slice(0, 3).map(tag => (
{ addFilterTag(tag) - let params = new URLSearchParams(window.location.search); - window.history.pushState({}, "", "/" + `${params ? `?${params}` : ""}`); }}> #{decodeTag(tag.name)}
diff --git a/src/Components/Map/Tags.tsx b/src/Components/Map/Tags.tsx index 01277f34..2ef90b3e 100644 --- a/src/Components/Map/Tags.tsx +++ b/src/Components/Map/Tags.tsx @@ -3,7 +3,7 @@ import { useEffect } from 'react'; import { ItemsApi, Tag } from '../../types'; import { useSetTagData, useSetTagApi, useTags } from './hooks/useTags' import { useLocation } from 'react-router-dom'; -import { useAddFilterTag, useResetFilterTags } from './hooks/useFilter'; +import { useAddFilterTag, useFilterTags, useResetFilterTags } from './hooks/useFilter'; export function Tags({data, api} : {data?: Tag[], api?: ItemsApi}) { const setTagData = useSetTagData(); @@ -19,16 +19,18 @@ const location = useLocation(); const addFilterTag = useAddFilterTag(); const resetFilterTags = useResetFilterTags(); const tags = useTags(); +const filterTags = useFilterTags() useEffect(() => { let params = new URLSearchParams(location.search); - let urlTags = params.get("tags"); - resetFilterTags() - urlTags?.split(",").map(urlTag => { + let urlTags = params.get("tags")?.split(","); + if(urlTags?.some(ut => !filterTags.find(ft => ut.toLocaleLowerCase() === ft.name.toLocaleLowerCase()))||filterTags?.some(ft => !urlTags?.find(ut => ut.toLocaleLowerCase() === ft.name.toLocaleLowerCase()))) + {resetFilterTags() + urlTags?.map(urlTag => { const tag = tags.find(t => t.name.toLocaleLowerCase() === urlTag.toLocaleLowerCase()) tag && addFilterTag(tag) - }); + });} }, [location, tags]); diff --git a/src/Components/Map/UtopiaMap.tsx b/src/Components/Map/UtopiaMap.tsx index e8780036..09fb6e1e 100644 --- a/src/Components/Map/UtopiaMap.tsx +++ b/src/Components/Map/UtopiaMap.tsx @@ -78,11 +78,11 @@ function UtopiaMap({
- + - + diff --git a/src/Components/Map/hooks/useFilter.tsx b/src/Components/Map/hooks/useFilter.tsx index ac73bd86..3b8d5042 100644 --- a/src/Components/Map/hooks/useFilter.tsx +++ b/src/Components/Map/hooks/useFilter.tsx @@ -2,7 +2,7 @@ import { useCallback, useReducer, createContext, useContext } from "react"; import * as React from "react"; import { LayerProps, Tag } from "../../../types"; import { useLayers } from "./useLayers"; -import { useLocation } from "react-router-dom"; +import { useLocation, useNavigate } from "react-router-dom"; type ActionType = | { type: "ADD_TAG"; tag: Tag } @@ -63,6 +63,7 @@ function useFilterManager(initialTags: Tag[]): { }, initialTags); const initialLayers = useLayers() + const navigate = useNavigate() const [visibleLayers, dispatchLayers] = useReducer((state: LayerProps[], action: ActionType) => { switch (action.type) { @@ -95,7 +96,8 @@ function useFilterManager(initialTags: Tag[]): { let urlTags = params.get("tags"); if(!urlTags?.includes(tag.name)) params.set("tags", `${urlTags ? urlTags : ""}${urlTags? ',' : ''}${tag.name}`) - window.history.pushState('','', "?" +params.toString()); + navigate(location.pathname + `${params ? `?${params}` : ""}`); + dispatchTags({ type: "ADD_TAG", @@ -117,11 +119,11 @@ function useFilterManager(initialTags: Tag[]): { }); if(newUrlTags !== "") { params.set("tags", `${newUrlTags}`) - window.history.pushState('','', "?" +params.toString()); + navigate(location.pathname + `${params ? `?${params}` : ""}`); } else { - - window.history.pushState('','', window.location.pathname); + params.delete("tags"); + navigate(location.pathname + `${params ? `?${params}` : ""}`); } dispatchTags({ diff --git a/src/Components/Templates/ItemCard.tsx b/src/Components/Templates/ItemCard.tsx index dfa62685..14dd7fc5 100644 --- a/src/Components/Templates/ItemCard.tsx +++ b/src/Components/Templates/ItemCard.tsx @@ -9,7 +9,10 @@ export const ItemCard = ({i,loading, url, parameterField, deleteCallback}:{i:Ite const navigate = useNavigate(); return ( -
navigate(url + getValue(i, parameterField))}> +
{ + let params = new URLSearchParams(window.location.search); + navigate(url + getValue(i, parameterField) + `${params ? `?${params}` : ""}`) + }}> navigate("/edit-item/" + i.id)} deleteCallback={() => deleteCallback(i)}>
{i.layer?.itemType.show_start_end && diff --git a/src/Components/Templates/OverlayItemsIndexPage.tsx b/src/Components/Templates/OverlayItemsIndexPage.tsx index 2045e5be..78b7b031 100644 --- a/src/Components/Templates/OverlayItemsIndexPage.tsx +++ b/src/Components/Templates/OverlayItemsIndexPage.tsx @@ -5,7 +5,7 @@ import { getValue } from '../../Utils/GetValue'; import { PopupStartEndInput, StartEndView, TextView } from '../Map'; import { PlusButton } from '../Profile/PlusButton'; import { TextInput, TextAreaInput } from '../Input'; -import { useAddTag, useTags } from '../Map/hooks/useTags'; +import { useAddTag, useGetItemTags, useTags } from '../Map/hooks/useTags'; import { toast } from 'react-toastify'; import { hashTagRegex } from '../../Utils/HashTagRegex'; import { randomColor } from '../../Utils/RandomColor'; @@ -16,6 +16,10 @@ import { MapOverlayPage } from './MapOverlayPage'; import { useAddItem, useItems, useRemoveItem } from '../Map/hooks/useItems'; import { DateUserInfo } from './DateUserInfo'; import { ItemCard } from './ItemCard'; +import { Control } from '../Map/Subcomponents/Controls/Control'; +import { SearchControl } from '../Map/Subcomponents/Controls/SearchControl'; +import { TagsControl } from '../Map/Subcomponents/Controls/TagsControl'; +import { useFilterTags } from '../Map/hooks/useFilter'; type breadcrumb = { @@ -24,7 +28,7 @@ type breadcrumb = { } -export const OverlayItemsIndexPage = ({ url, layerName, parameterField, breadcrumbs, plusButton = true, children }: { layerName: string, url: string, parameterField: string, breadcrumbs: Array, plusButton?: boolean, children?: ReactNode }) => { +export const OverlayItemsIndexPage = ({ url, layerName, parameterField, plusButton = true }: { layerName: string, url: string, parameterField: string, plusButton?: boolean }) => { @@ -41,8 +45,6 @@ export const OverlayItemsIndexPage = ({ url, layerName, parameterField, breadcru scroll(); }, [addItemPopupType]) - const navigate = useNavigate(); - const tags = useTags(); const addTag = useAddTag(); const { user } = useAuth(); @@ -51,15 +53,11 @@ export const OverlayItemsIndexPage = ({ url, layerName, parameterField, breadcru const removeItem = useRemoveItem(); const layers = useLayers(); - useEffect(() => { - console.log(items); - - - }, [items]) + const filterTags = useFilterTags(); + const getItemTags = useGetItemTags(); const layer = layers.find(l => l.name == layerName); - const submitNewItem = async (evt: any) => { evt.preventDefault(); const formItem: Item = {} as Item; @@ -107,58 +105,59 @@ export const OverlayItemsIndexPage = ({ url, layerName, parameterField, breadcru } + return ( <> - -
- {breadcrumbs && -
-
    - {breadcrumbs.map((b, i) =>
  • {b.name}
  • )} -
-
} -
-
- { - items?.filter(i => i.layer?.name === layerName) - .sort((a, b) => { - // Convert date_created to milliseconds, handle undefined by converting to lowest possible date (0 milliseconds) - const dateA = a.date_updated ? new Date(a.date_updated).getTime() : a.date_created ? new Date(a.date_created).getTime() : 0; - const dateB = b.date_updated ? new Date(b.date_updated).getTime() : b.date_created ? new Date(b.date_created).getTime() : 0; - return dateB - dateA; // Subtracts milliseconds which are numbers - }) - .map((i, k) => { - return ( - deleteItem(i)} > - ) - }) - } - {addItemPopupType == "place" ? + +
+
+ + + + +
+
+ { + items?.filter(i => i.layer?.name === layerName). + filter(item => + filterTags.length == 0 ? item : filterTags.every(tag => getItemTags(item).some(filterTag => filterTag.name.toLocaleLowerCase() === tag.name.toLocaleLowerCase())))?. + sort((a, b) => { + // Convert date_created to milliseconds, handle undefined by converting to lowest possible date (0 milliseconds) + const dateA = a.date_updated ? new Date(a.date_updated).getTime() : a.date_created ? new Date(a.date_created).getTime() : 0; + const dateB = b.date_updated ? new Date(b.date_updated).getTime() : b.date_created ? new Date(b.date_created).getTime() : 0; + return dateB - dateA; // Subtracts milliseconds which are numbers + })?. + map((i, k) => { + return ( + deleteItem(i)} > + ) + }) + } + {addItemPopupType == "place" ? -
submitNewItem(e)} > + submitNewItem(e)} > -
- - - {layer?.itemType.show_start_end_input && - - } - -
- +
+ + + {layer?.itemType.show_start_end_input && + + } + +
+ +
-
- : <> - } + : <> + } +
- {children} - diff --git a/src/index.css b/src/index.css index a5583f95..c46cd342 100644 --- a/src/index.css +++ b/src/index.css @@ -74,4 +74,28 @@ input[type="file"] { .tw-tab-content .container { height: 100%; +} + +.masonry { + column-count: 1; + column-gap: 1.5rem; +} +.masonry-item { + break-inside: avoid; + margin-bottom: 1.5rem; +} +@media (min-width: 640px) { + .masonry { + column-count: 2; + } +} +@media (min-width: 1024px) { + .masonry { + column-count: 3; + } +} +@media (min-width: 1536px) { + .masonry { + column-count: 4; + } } \ No newline at end of file