Skip to content
Snippets Groups Projects
Commit 3253601d authored by Moritz Stückler's avatar Moritz Stückler :cowboy:
Browse files

Merge branch 'feat/reposition-sidebar' into 'main'

feat: sidebar reposition, add minimize button

Closes #5

See merge request !4
parents e4d45a4c c317530f
No related branches found
No related tags found
1 merge request!4feat: sidebar reposition, add minimize button
......@@ -33,7 +33,7 @@ const FabCityMap: React.FC<Props> = ({ data, mapboxToken, className, baseUrl, ma
<ErrorModal />
<Notification />
<div
className={`fcmap-flex md:fcmap-flex-row-reverse fcmap-flex-col fcmap-h-full fcmap-bg-white ${
className={`fcmap-relative fcmap-h-full fcmap-bg-white fcmap-overflow-hidden ${
className || ''
}`}
>
......
......@@ -32,10 +32,13 @@ const Map: React.FC<Props> = ({ mapboxToken, mapStyle }) => {
const data = useStore((state) => state.poiData);
const selectedPoi = useStore((state) => state.selectedPoi);
const hoveredPoi = useStore((state) => state.hoveredPoi);
const isSidebarHidden = useStore((state) => state.isSidebarHidden);
const { data: filteredData } = useFilteredPoiData();
const DEFAULT_CENTER: [number, number] = [9.986701, 53.550359];
const { fcmap } = useMap();
const [bounds, setBounds] = useState<[[number, number], [number, number]]>();
const DEFAULT_MAP_PADDING = 50;
const OVERLAY_WIDTH_PADDING = 300;
useEffect(() => {
const newBounds = calcBoundsFromCoordinates(data?.map((poi) => [poi.lng, poi.lat]) || [DEFAULT_CENTER]);
......@@ -45,13 +48,29 @@ const Map: React.FC<Props> = ({ mapboxToken, mapStyle }) => {
useEffect(() => {
if (fcmap) {
if (selectedPoi) {
fcmap?.easeTo({ center: [selectedPoi.lng, selectedPoi.lat], zoom: 14, duration: 1500 });
fcmap?.easeTo({
center: [selectedPoi.lng, selectedPoi.lat],
zoom: 14,
duration: 1500,
...(!isSidebarHidden ? { padding: { right: OVERLAY_WIDTH_PADDING, left: 0, top: 0, bottom: 0 } } : {}),
});
} else if (!selectedPoi && bounds) {
fcmap?.fitBounds(bounds, { padding: 50, maxZoom: 16 });
fcmap?.fitBounds(bounds, {
...(!isSidebarHidden
? {
padding: {
right: DEFAULT_MAP_PADDING + OVERLAY_WIDTH_PADDING,
left: DEFAULT_MAP_PADDING,
top: DEFAULT_MAP_PADDING,
bottom: DEFAULT_MAP_PADDING,
},
}
: {}),
maxZoom: 16,
});
}
}
}, [selectedPoi, bounds, fcmap]);
}, [selectedPoi, bounds, fcmap, isSidebarHidden]);
return (
<ReactMapGl
......@@ -67,7 +86,7 @@ const Map: React.FC<Props> = ({ mapboxToken, mapStyle }) => {
id="fcmap"
attributionControl={false}
>
<AttributionControl position="top-right" />
<AttributionControl position="top-left" />
<MapLayerControl />
{selectedPoi ? (
<Marker key={selectedPoi.id} longitude={selectedPoi.lng} latitude={selectedPoi.lat} anchor="bottom">
......
......@@ -18,11 +18,16 @@ const MapLayerControl: React.FC = () => {
};
return (
<div className="fcmap-border fcmap-border-grey-900 fcmap-w-52 fcmap-absolute fcmap-right-0 fcmap-bottom-0 fcmap-mb-4 fcmap-mr-4 fcmap-bg-white fcmap-p-4 fcmap-z-10">
<div className={`fcmap-flex fcmap-justify-between fcmap-cursor-pointer ${isOpen ? 'fcmap-mb-2' : ''}`} onClick={() => setIsOpen(!isOpen)}>
<div className="fcmap-shadow-lg fcmap-w-52 fcmap-absolute fcmap-left-5 fcmap-bottom-0 fcmap-mb-5 fcmap-mr-4 fcmap-bg-white fcmap-p-4 fcmap-z-10">
<div
className={`fcmap-flex fcmap-justify-between fcmap-cursor-pointer ${isOpen ? 'fcmap-mb-2' : ''}`}
onClick={() => setIsOpen(!isOpen)}
>
<h3 className="fcmap-text-base fcmap-font-semibold fcmap-text-gray-900">Kategorien:</h3>
<DownIcon
className={`fcmap-w-6 fcmap-h-6 fcmap-text-gray-400 fcmap-transform fcmap-transition fcmap-duration-300 ${isOpen ? 'fcmap-rotate-180' : 'fcmap-rotate-0'}`}
className={`fcmap-w-6 fcmap-h-6 fcmap-text-gray-400 fcmap-transform fcmap-transition fcmap-duration-300 ${
isOpen ? 'fcmap-rotate-180' : 'fcmap-rotate-0'
}`}
/>
</div>
{isOpen &&
......
......@@ -16,7 +16,7 @@ const ListElement: React.FC<Props> = ({ value, hovered, ...restProps }) => {
{...restProps}
className={`fcmap-border fcmap-border-grey-900 fcmap-border-opacity-40 ${
hovered ? 'fcmap-border-opacity-100' : ''
} fcmap-cursor-pointer fcmap-mx-4 fcmap-my-2`}
} fcmap-cursor-pointer`}
>
<div className="fcmap-p-3">
<h2 className="fcmap-tracking-widest fcmap-text-xs fcmap-uppercase fcmap-title-font fcmap-font-medium fcmap-text-gray-400 fcmap-mb-1">
......
import type { SyntheticEvent } from 'react';
import { ChevronDown } from 'heroicons-react';
interface Props {
onClick: (event: SyntheticEvent) => void;
isMinimized?: boolean;
}
const MinimizeButton: React.FC<Props> = ({ onClick, isMinimized = false }) => {
return (
<button onClick={onClick}>
<ChevronDown className={`${isMinimized ? 'fcmap-rotate-180' : ''} fcmap-text-gray-400 fcmap-w-6 fcmap-h-6`} />
</button>
);
};
export default MinimizeButton;
interface Props {
className?: string;
children: React.ReactNode
children: React.ReactNode;
}
const SidebarContainer: React.FC<Props> = ({ className, children }) => {
return (
<aside
className={`sidebar fcmap-box-border fcmap-flex fcmap-flex-col fcmap-border-t-2 md:fcmap-border-r md:fcmap-border-t-0 fcmap-border-grey-900 ${
className={`fcmap-absolute fcmap-right-0 fcmap-m-5 sidebar-height fcmap-min-h-min fcmap-w-[336px] fcmap-shadow-lg fcmap-bg-white fcmap-box-border fcmap-flex fcmap-flex-col ${
className ?? ''
}`}
>
......
......@@ -8,6 +8,7 @@ import type { Tag } from '../../types/PointOfInterest';
import { FilterOutline as FilterIcon } from 'heroicons-react';
import { useHistory } from 'react-router-dom';
import Select from '../Select';
import MinimizeButton from './MinimizeButton';
const SidebarListView: React.FC = () => {
const tagsToSelectOptions = (tags?: Tag[]) => tags?.map((tag) => ({ label: tag.displayName, value: tag }));
......@@ -18,6 +19,8 @@ const SidebarListView: React.FC = () => {
const hoveredPoi = useStore((state) => state.hoveredPoi);
const setHoveredPoi = useStore((state) => state.setHoveredPoi);
const [filterInputIsOpen, setFilterInputIsOpen] = useState(false);
const isSidebarHidden = useStore((state) => state.isSidebarHidden);
const setIsSidebarHidden = useStore((state) => state.setIsSidebarHidden);
const tags =
data &&
......@@ -28,16 +31,29 @@ const SidebarListView: React.FC = () => {
const options = tagsToSelectOptions(tags);
return (
<SidebarContainer>
<div className="fcmap-flex-col fcmap-m-4 fcmap-mb-2 fcmap-pb-2 fcmap-border-black fcmap-border-opacity-20 fcmap-border-b-2">
<SidebarContainer
className={`fcmap-overflow-hidden fcmap-transition-[top] fcmap-duration-700 fcmap-ease-in-out ${
isSidebarHidden ? 'fcmap-top-[calc(100%-98px)]' : 'fcmap-top-0'
}`}
>
<div className="fcmap-flex fcmap-flex-col fcmap-m-4 fcmap-mb-2 fcmap-pb-2 fcmap-border-black fcmap-border-opacity-20 fcmap-border-b-2 fcmap-gap-2">
<div className="fcmap-flex fcmap-justify-end">
<MinimizeButton
isMinimized={isSidebarHidden}
onClick={() => {
setIsSidebarHidden(!isSidebarHidden);
}}
/>
</div>
<div className="fcmap-flex fcmap-justify-between fcmap-items-center">
<h1 className="fcmap-text-xl fcmap-font-medium fcmap-title-font fcmap-text-gray-900">{filteredData?.length} Orte:</h1>
<h1 className="fcmap-text-xl fcmap-font-medium fcmap-title-font fcmap-text-gray-900">
{filteredData?.length} Orte:
</h1>
<FilterIcon
onClick={() => setFilterInputIsOpen(!filterInputIsOpen)}
className="fcmap-text-black fcmap-text-opacity-20 hover:fcmap-text-opacity-60 fcmap-w-5 fcmap-h-5 fcmap-cursor-pointer"
className="fcmap-text-gray-400 fcmap-w-5 fcmap-h-5 fcmap-cursor-pointer"
/>
</div>
{filterInputIsOpen && (
<div className="fcmap-py-2">
<Select
......@@ -49,19 +65,20 @@ const SidebarListView: React.FC = () => {
</div>
)}
</div>
{filteredData?.map((poi) => (
<ListElement
key={poi.id}
onMouseEnter={() => setHoveredPoi(poi)}
onMouseLeave={() => setHoveredPoi(null)}
onClick={() => {
history.push(`/poi/${String(poi.id)}`);
}}
value={poi}
hovered={hoveredPoi?.id === poi.id}
/>
))}
<div className="fcmap-overflow-y-auto fcmap-flex fcmap-flex-col fcmap-gap-2 fcmap-m-4 fcmap-mr-2 fcmap-pr-2">
{filteredData?.map((poi) => (
<ListElement
key={poi.id}
onMouseEnter={() => setHoveredPoi(poi)}
onMouseLeave={() => setHoveredPoi(null)}
onClick={() => {
history.push(`/poi/${String(poi.id)}`);
}}
value={poi}
hovered={hoveredPoi?.id === poi.id}
/>
))}
</div>
</SidebarContainer>
);
};
......
......@@ -15,7 +15,7 @@ const SidebarSingleView: React.FC = () => {
const history = useHistory();
return (
<SidebarContainer className={`fcmap-relative fcmap-p-0`}>
<SidebarContainer className={`fcmap-top-0 fcmap-p-0 fcmap-overflow-y-auto md:fcmap-mt-9 md:fcmap-mb-4`}>
<div className={`${selectedPoi?.image ? '' : 'fcmap-pl-5 fcmap-pt-5 '}`}>
<CloseButton
absolute
......@@ -35,7 +35,9 @@ const SidebarSingleView: React.FC = () => {
<h2 className="fcmap-tracking-widest fcmap-uppercase fcmap-text-xs fcmap-title-font fcmap-font-medium fcmap-text-gray-400 fcmap-mb-1">
{selectedPoi?.category}
</h2>
<h1 className="fcmap-title-font fcmap-text-lg fcmap-font-medium fcmap-text-gray-900 fcmap-mb-3">{selectedPoi?.name}</h1>
<h1 className="fcmap-title-font fcmap-text-lg fcmap-font-medium fcmap-text-gray-900 fcmap-mb-3">
{selectedPoi?.name}
</h1>
<p className="fcmap-leading-relaxed fcmap-mb-6">{selectedPoi?.description}</p>
{selectedPoi?.website && (
<div className={'fcmap-flex fcmap-items-center'}>
......
......@@ -19,6 +19,8 @@ interface Store {
setFilterTags: (tags: Tag[]) => void;
filterCategories: string[];
setFilterCategories: (categories: string[]) => void;
isSidebarHidden: boolean;
setIsSidebarHidden: (value: boolean) => void;
}
export const useStore = create<Store>()(
......@@ -57,5 +59,9 @@ export const useStore = create<Store>()(
setFilterCategories: (categories) => {
set({ filterCategories: categories });
},
isSidebarHidden: false,
setIsSidebarHidden: (value) => {
set({ isSidebarHidden: value });
},
})),
);
......@@ -20,19 +20,8 @@ code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
}
.sidebar {
flex-basis: 40%;
overflow-y: auto;
flex-shrink: 0;
}
@screen md {
.sidebar {
flex-basis: 30vw;
min-width: 300px;
max-width: 500px;
max-height: initial;
}
.sidebar-height {
max-height: calc(100% - 2 * theme(spacing.5));
}
.input-chevron {
......@@ -44,3 +33,10 @@ code {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
.mapboxgl-ctrl-logo {
position: absolute;
left: 50vw;
bottom: 0;
transform: translateX(-50%);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment