mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2025-12-13 07:46:10 +00:00
rebuild FilterControl Component
This commit is contained in:
parent
b196e253b1
commit
bec87a23a3
@ -1,94 +1,55 @@
|
||||
import * as React from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import * as React from 'react'
|
||||
import * as L from 'leaflet'
|
||||
import { useLayers } from '../../hooks/useLayers';
|
||||
import { useAddVisibleGroupType, useIsGroupTypeVisible, useToggleVisibleGroupType } from '../../hooks/useFilter';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
const typeMapping = [
|
||||
{value: null, label: 'Kein Filter'},
|
||||
{value: 'kompass', label: 'Würdekompass'},
|
||||
{value: 'themenkompass', label: 'Themenkompass-Gruppe'},
|
||||
{value: 'liebevoll.jetzt', label: 'liebevoll.jetzt'}
|
||||
];
|
||||
export function FilterControl() {
|
||||
|
||||
const CustomFilterIcon = ({ size = 20 }) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={size}
|
||||
height={size}
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor" // Changed from 'none' to 'currentColor'
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3" />
|
||||
</svg>
|
||||
);
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
const CheckmarkIcon = () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<polyline points="20 6 9 17 4 12" />
|
||||
</svg>
|
||||
);
|
||||
const groupTypes = [{text: "Regional Gruppe", value: "wuerdekompass" },{text: "Themen Gruppe", value:"themenkompass"}, {text: "liebevoll.jetzt", value: "liebevoll.jetzt"}]
|
||||
|
||||
const FilterControl = ({ activeFilter, setActiveFilter }) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const toggleFilter = () => {
|
||||
setIsOpen(!isOpen);
|
||||
};
|
||||
useEffect(() => {
|
||||
groupTypes.map(layer =>
|
||||
addVisibleGroupType(layer.value)
|
||||
)
|
||||
}, [])
|
||||
|
||||
const applyFilter = (filterValue) => {
|
||||
setActiveFilter(filterValue);
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
const isGroupTypeVisible = useIsGroupTypeVisible();
|
||||
const toggleVisibleGroupType = useToggleVisibleGroupType();
|
||||
const addVisibleGroupType = useAddVisibleGroupType();
|
||||
|
||||
return (
|
||||
<div className="tw-relative">
|
||||
<div className="tw-indicator">
|
||||
{activeFilter !== null && (
|
||||
<span className="tw-indicator-item tw-badge tw-badge-secondary tw-bg-red-500 tw-border-red-500"></span>
|
||||
)}
|
||||
<button
|
||||
className="tw-w-12 tw-h-12 tw-rounded-full tw-bg-base-100 tw-flex tw-items-center tw-justify-center tw-border tw-border-gray-300 hover:tw-bg-gray-200 focus:tw-bg-gray-200 focus:tw-outline-none"
|
||||
onClick={toggleFilter}
|
||||
>
|
||||
<CustomFilterIcon size={24} />
|
||||
</button>
|
||||
</div>
|
||||
<div className="tw-card tw-bg-base-100 tw-shadow-xl tw-mt-2 tw-w-fit">
|
||||
{
|
||||
open ?
|
||||
<div className="tw-card-body tw-p-2 tw-w-fit tw-transition-all tw-duration-300">
|
||||
<label className="tw-btn tw-btn-sm tw-rounded-2xl tw-btn-circle tw-btn-ghost hover:tw-bg-transparent tw-absolute tw-right-0 tw-top-0 tw-text-gray-600" onClick={() => {
|
||||
setOpen(false)
|
||||
}}>
|
||||
<p className='tw-text-center '>✕</p></label>
|
||||
<ul className='tw-flex-row'>
|
||||
{
|
||||
groupTypes.map(groupType =>
|
||||
<li key={groupType.value}><label htmlFor={groupType.value} className="tw-label tw-justify-normal tw-pt-1 tw-pb-1"><input id={groupType.value} onChange={() => toggleVisibleGroupType(groupType.value)} type="checkbox" className="tw-checkbox tw-checkbox-xs tw-checkbox-success" checked={isGroupTypeVisible(groupType.value)} /><span className='tw-text-sm tw-label-text tw-mx-2 tw-cursor-pointer'>{groupType.text}</span></label></li>
|
||||
)
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
:
|
||||
<div className="tw-card-body hover:tw-bg-slate-300 tw-card tw-p-2 tw-h-10 tw-w-10 tw-transition-all tw-duration-300 hover:tw-cursor-pointer" onClick={() => {
|
||||
setOpen(true)
|
||||
}}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={2} stroke="currentColor" className="size-6">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 3c2.755 0 5.455.232 8.083.678.533.09.917.556.917 1.096v1.044a2.25 2.25 0 0 1-.659 1.591l-5.432 5.432a2.25 2.25 0 0 0-.659 1.591v2.927a2.25 2.25 0 0 1-1.244 2.013L9.75 21v-6.568a2.25 2.25 0 0 0-.659-1.591L3.659 7.409A2.25 2.25 0 0 1 3 5.818V4.774c0-.54.384-1.006.917-1.096A48.32 48.32 0 0 1 12 3Z" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
{isOpen && (
|
||||
<div className="tw-absolute tw-bottom-12 tw-left-0 tw-bg-base-100 tw-shadow-xl tw-rounded-lg tw-overflow-hidden tw-border tw-border-gray-200 tw-min-w-[250px]">
|
||||
<ul className="tw-py-1">
|
||||
{typeMapping.map((type) => (
|
||||
<li key={type.value}>
|
||||
<button
|
||||
onClick={() => applyFilter(type.value)}
|
||||
className={`tw-w-full tw-text-left tw-text-sm tw-px-4 tw-py-2 tw-flex tw-items-center tw-space-x-2
|
||||
hover:tw-bg-gray-300 focus:tw-bg-gray-300 focus:tw-outline-none
|
||||
${activeFilter === type.value ? 'tw-bg-gray-200' : ''}`}
|
||||
>
|
||||
<span className="tw-w-4">
|
||||
{activeFilter === type.value && <CheckmarkIcon />}
|
||||
</span>
|
||||
<span>{type.label}</span>
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FilterControl;
|
||||
)
|
||||
}
|
||||
|
||||
@ -10,18 +10,12 @@ export function LayerControl() {
|
||||
|
||||
const layers = useLayers();
|
||||
|
||||
useEffect(() => {
|
||||
layers.map(layer =>
|
||||
addVisibleLayer(layer)
|
||||
)
|
||||
}, [layers])
|
||||
|
||||
const isLayerVisible = useIsLayerVisible();
|
||||
const toggleVisibleLayer = useToggleVisibleLayer();
|
||||
const addVisibleLayer = useAddVisibleLayer();
|
||||
|
||||
return (
|
||||
<div className="tw-card tw-bg-base-100 tw-shadow-xl ">
|
||||
<div className="tw-card tw-bg-base-100 tw-shadow-xl tw-mt-2 tw-w-fit">
|
||||
{
|
||||
open ?
|
||||
<div className="tw-card-body tw-p-2 tw-w-36 tw-transition-all tw-duration-300">
|
||||
@ -45,6 +39,8 @@ export function LayerControl() {
|
||||
<path id="svg_1" fill="currentColor" d="m2.75565,11.90727l-1.03852,0.28372c-0.77718,0.38859 -0.77718,1.0138 0,1.4023l7.0156,3.5078c0.77718,0.38859 2.0275,0.38859 2.8047,0l7.0156,-3.5078c0.77718,-0.38859 0.77718,-1.0138 0,-1.4023l-0.63311,-0.48643l-4.67718,2.23624c-1.5452,0.77262 -3.31877,1.58343 -4.86407,0.81081l-5.62302,-2.84434z" />
|
||||
<path id="svg_2" strokeWidth="2" stroke="currentColor" fill="none" d="m11.247,4.30851l6.2349,3.0877c0.69083,0.34211 0.69083,0.89295 0,1.2351l-6.2349,3.0877c-0.69083,0.34211 -1.8031,0.34212 -2.494,0l-6.2349,-3.0877c-0.69083,-0.34211 -0.69083,-0.89295 0,-1.2351l6.2349,-3.0877c0.69083,-0.34211 1.8031,-0.34211 2.494,0z" />
|
||||
</svg>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
@ -12,6 +12,9 @@ type ActionType =
|
||||
| { type: "TOGGLE_LAYER"; layer: LayerProps }
|
||||
| { type: "ADD_LAYER"; layer: LayerProps }
|
||||
| { type: "RESET_LAYERS" }
|
||||
| { type: "TOGGLE_GROUP_TYPE"; groupType: string }
|
||||
| { type: "ADD_GROUP_TYPE"; groupType: string }
|
||||
| { type: "RESET_GROUP_TYPE" }
|
||||
;
|
||||
|
||||
type UseFilterManagerResult = ReturnType<typeof useFilterManager>;
|
||||
@ -27,7 +30,11 @@ const FilterContext = createContext<UseFilterManagerResult>({
|
||||
addVisibleLayer: () => { },
|
||||
toggleVisibleLayer: () => { },
|
||||
resetVisibleLayers: () => { },
|
||||
isLayerVisible: () => true
|
||||
isLayerVisible: () => true,
|
||||
|
||||
addVisibleGroupType: () => { },
|
||||
toggleVisibleGroupType: () => { },
|
||||
isGroupTypeVisible: () => true
|
||||
});
|
||||
|
||||
function useFilterManager(initialTags: Tag[]): {
|
||||
@ -42,6 +49,9 @@ function useFilterManager(initialTags: Tag[]): {
|
||||
toggleVisibleLayer: (layer: LayerProps) => void;
|
||||
resetVisibleLayers: () => void;
|
||||
isLayerVisible: (layer: LayerProps) => boolean;
|
||||
addVisibleGroupType: (groupType: string) => void;
|
||||
toggleVisibleGroupType: (groupType: string) => void;
|
||||
isGroupTypeVisible: (groupType: string) => boolean;
|
||||
} {
|
||||
const [filterTags, dispatchTags] = useReducer((state: Tag[], action: ActionType) => {
|
||||
switch (action.type) {
|
||||
@ -90,6 +100,29 @@ function useFilterManager(initialTags: Tag[]): {
|
||||
}
|
||||
}, initialLayers);
|
||||
|
||||
const [visibleGroupTypes, dispatchGroupTypes] = useReducer((state: string[], action: ActionType) => {
|
||||
switch (action.type) {
|
||||
case "ADD_GROUP_TYPE":
|
||||
const exist1 = state.find((groupType) =>
|
||||
groupType === action.groupType ? true : false
|
||||
);
|
||||
if (!exist1) return [
|
||||
...state,
|
||||
action.groupType,
|
||||
];
|
||||
else return state;
|
||||
case "TOGGLE_GROUP_TYPE":
|
||||
const exist2 = state.some((groupType) =>
|
||||
groupType === action.groupType);
|
||||
if(exist2) return state.filter((groupType) => groupType != action.groupType);
|
||||
else return [... state, action.groupType];
|
||||
case "RESET_GROUP_TYPE":
|
||||
return initialLayers;
|
||||
default:
|
||||
throw new Error();
|
||||
}
|
||||
}, initialLayers);
|
||||
|
||||
const [searchPhrase, searchPhraseSet] = React.useState<string>("");
|
||||
|
||||
const addFilterTag = (tag: Tag) => {
|
||||
@ -170,11 +203,31 @@ function useFilterManager(initialTags: Tag[]): {
|
||||
return visibleLayers.some(l => l.name === layer.name)
|
||||
}, [visibleLayers]);
|
||||
|
||||
const addVisibleGroupType = (groupType: string) => {
|
||||
dispatchGroupTypes({
|
||||
type: "ADD_GROUP_TYPE",
|
||||
groupType,
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
const toggleVisibleGroupType = (groupType: string) => {
|
||||
dispatchGroupTypes({
|
||||
type: "TOGGLE_GROUP_TYPE",
|
||||
groupType,
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
const isGroupTypeVisible = useCallback((groupType: string) => {
|
||||
return visibleGroupTypes.some(gt => gt === groupType)
|
||||
}, [visibleGroupTypes]);
|
||||
|
||||
const setSearchPhrase = useCallback((phrase: string) => {
|
||||
searchPhraseSet(phrase)
|
||||
}, []);
|
||||
|
||||
return { filterTags, addFilterTag, removeFilterTag, resetFilterTags, setSearchPhrase, searchPhrase, visibleLayers, toggleVisibleLayer, resetVisibleLayers, isLayerVisible, addVisibleLayer };
|
||||
return { filterTags, addFilterTag, removeFilterTag, resetFilterTags, setSearchPhrase, searchPhrase, visibleLayers, toggleVisibleLayer, resetVisibleLayers, isLayerVisible, addVisibleLayer, addVisibleGroupType, toggleVisibleGroupType, isGroupTypeVisible };
|
||||
}
|
||||
|
||||
export const FilterProvider: React.FunctionComponent<{
|
||||
@ -239,4 +292,21 @@ export const useResetVisibleLayers = (): UseFilterManagerResult["resetVisibleLay
|
||||
export const useIsLayerVisible = (): UseFilterManagerResult["isLayerVisible"] => {
|
||||
const { isLayerVisible } = useContext(FilterContext);
|
||||
return isLayerVisible;
|
||||
};
|
||||
|
||||
export const useAddVisibleGroupType = (): UseFilterManagerResult["addVisibleGroupType"] => {
|
||||
const { addVisibleGroupType } = useContext(FilterContext);
|
||||
return addVisibleGroupType;
|
||||
};
|
||||
|
||||
|
||||
export const useToggleVisibleGroupType = (): UseFilterManagerResult["toggleVisibleGroupType"] => {
|
||||
const { toggleVisibleGroupType } = useContext(FilterContext);
|
||||
return toggleVisibleGroupType;
|
||||
};
|
||||
|
||||
|
||||
export const useIsGroupTypeVisible = (): UseFilterManagerResult["isGroupTypeVisible"] => {
|
||||
const { isGroupTypeVisible } = useContext(FilterContext);
|
||||
return isGroupTypeVisible
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user