Skip to content

Commit

Permalink
Filters
Browse files Browse the repository at this point in the history
  • Loading branch information
rtcoder committed May 3, 2023
1 parent 4f8c259 commit 79fb514
Show file tree
Hide file tree
Showing 7 changed files with 277 additions and 13 deletions.
18 changes: 7 additions & 11 deletions src/components/Creator/CreatorArea/ActionButtons/ActionButtons.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import styles from './ActionButtons.module.scss'
import Icon from "@/components/construction/Icon/Icon";
import classNames from "@/helpers/classNames";
import {useCallback, useEffect, useRef} from "react";
import {useCallback, useEffect, useRef, useState} from "react";
import {duplicateBlock, removeBlock} from "@/store/structureSlice";
import {useDispatch, useSelector} from "react-redux";
import ActionMoveButtons from "@/components/Creator/CreatorArea/ActionButtons/ActionMoveButtons/ActionMoveButtons";
Expand All @@ -13,13 +13,13 @@ export default function ActionButtons() {
const selectedBlock = useSelector((state: any) => state.structure.selectedBlock);
const pageYOffset = useSelector((state: any) => state.structure.pageYOffset);

const duplicate = useCallback(() => {
dispatch(duplicateBlock(selectedBlock));
const duplicate = useCallback((block) => {
dispatch(duplicateBlock({...block}));
}, [dispatch]);

const deleteBlk = useCallback(() => {
const deleteBlk = useCallback((block) => {
if (confirm('Are you sure you want to delete this block?')) {
dispatch(removeBlock(selectedBlock));
dispatch(removeBlock({...block}));
}
}, [dispatch]);

Expand Down Expand Up @@ -55,17 +55,13 @@ export default function ActionButtons() {
useEffect(() => {
setComponentPosition();
}, [selectedBlock, pageYOffset])
useEffect(() => {
console.log(pageYOffset)
}, [pageYOffset])

return (
<> {selectedBlock
? <div className={styles.actionButtons} ref={ref}>
<ActionMoveButtons block={selectedBlock}/>
<MediaActionButtons block={selectedBlock}/>

{/*${this.getAdditionalButtonsHtml()}*/}
<Icon className={styles.itemButton}
title="Ustawienia"
type="material-outlined"
Expand All @@ -75,7 +71,7 @@ export default function ActionButtons() {
title="Duplikuj"
type="material-outlined"
name="content_copy"
onClick={duplicate}/>
onClick={()=>duplicate(selectedBlock)}/>

<Icon className={styles.itemButton}
title="Przenieś"
Expand All @@ -86,7 +82,7 @@ export default function ActionButtons() {
title="Usuń"
type="material-outlined"
name="close"
onClick={deleteBlk}/>
onClick={()=>deleteBlk(selectedBlock)}/>
</div> : ''}</>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.singleFilter {
border-bottom: 1px solid #ccc;
}

.icon {
width: 30px;
height: 30px;
align-self: flex-end;
cursor: pointer;

&:hover {
color: #f00;
}
}
161 changes: 161 additions & 0 deletions src/components/Creator/LeftPanel/StylesPanel/Filter/Filter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import styles from "@/components/Creator/LeftPanel/StylesPanel/StylesPanel.module.scss";
import filterStyles from './Filter.module.scss'
import {Option, Select} from "@/components/construction/Select";
import {useEffect, useState} from "react";
import {getInheritedStyleWith} from "@/helpers/block-styles";
import {useSelector} from "react-redux";
import {Units} from "@/types/units";
import FilterSingle from "@/components/Creator/LeftPanel/StylesPanel/Filter/FilterSingle/FilterSingle";
import FilterDropShadow from "@/components/Creator/LeftPanel/StylesPanel/Filter/FilterDropShadow/FilterDropShadow";
import classNames from "@/helpers/classNames";
import Icon from "@/components/construction/Icon/Icon";

interface Props {
onChange: (value: string | null, property: string) => void
}

type SelectedFilter = [id: string, value: any];
const filterDefaultUnits: [name: string, unit: Units][] = [
['blur', 'px'],
['brightness', '%'],
['contrast', '%'],
['grayscale', '%'],
['hue-rotate', 'deg'],
['invert', '%'],
['opacity', '%'],
['saturate', '%'],
['sepia', '%'],
];
const allFiltersNames: [id: string, name: string][] = [
['blur', 'Rozmycie'],
['brightness', 'Jasność'],
['contrast', 'Kontrast'],
['drop-shadow', 'Cień'],
['grayscale', 'Skala szarości'],
['hue-rotate', 'Obracanie odcienia'],
['invert', 'Odwrócenie kolorów'],
['opacity', 'Nieprzezroczystość'],
['saturate', 'Saturacja'],
['sepia', 'Sepia'],
];
const filtersDefaultValues: [id: string, value: any][] = [
['blur', 0],
['brightness', 100],
['contrast', 100],
['drop-shadow', ['0px', '0px', '0px', '#000']],
['grayscale', 0],
['hue-rotate', 0],
['invert', 0],
['opacity', 100],
['saturate', 0],
['sepia', 0],
];
export default function (props: Props) {
const selectedBlock = useSelector((state: any) => state.structure.selectedBlock);
const rwd = useSelector((state: any) => state.structure.rwdMode);
const styleState = useSelector((state: any) => state.structure.styleState);
const [filter, seFilter] = useState('');
const [selectedFilters, setSelectedFilters] = useState<SelectedFilter[]>([]);

const changed = value => {
value = addFilterUnits(value);
props.onChange(
value.map(([id, value]: SelectedFilter) => `${id}(${value})`).join(' '),
'filter'
)
}
const addFilterUnits = value => {
return [...value].map(([id, val]) => {
if(id === 'drop-shadow' ){
return [id, val.map((v,index)=>{
if(index===3){
return v;
}
return `${parseInt(v)}px`
}).join(' ')]
}
const [, unit] = filterDefaultUnits.find(([f_id, _unit]) => f_id === id)!
return [id, `${val}${unit}`]
});
}
const mapFiltersToArray = (value: string): SelectedFilter[] => {
const filtersArr = value.match(/[\w-]+\([\w.,%\s]+[\(]{1}[\w.,%\s]+[\)]{1}\)|[\w-]+\([\w.,%\s\#]+\)/gm) ?? [];
const getFilterVal = name => filtersArr.find(filterName => filterName.startsWith(name))
.trim().replace(`${name}(`, '').replace(/\)$/, '');
const filters: SelectedFilter[] = [];

filtersArr.forEach(filter => {
const [name] = filter.split('(');

if (name.includes('drop-shadow')) {
const dropShadow = getFilterVal('drop-shadow');
const [hShadow, vShadow, blur, color] = dropShadow.match(/\S+\([\d\s,\.]+\)|[\w\#]+/gm);
filters.push([name, [parseInt(hShadow), parseInt(vShadow), parseInt(blur), color]]);
} else {
filters.push([name, parseInt(getFilterVal(name))]);
}
});

return filters;
}

useEffect(() => {
const style = getInheritedStyleWith(
selectedBlock.styles,
rwd, styleState,
['filter'],
) as any;
seFilter(style.filter || '');
setSelectedFilters(mapFiltersToArray(style.filter || ''));
}, [selectedBlock, rwd, styleState])

const addFilter = (filterId: string) => {
const [, defaultValue] = filtersDefaultValues.find(([id, _]) => id === filterId);
const newFilter: SelectedFilter = [filterId, defaultValue];
setSelectedFilters([...selectedFilters, newFilter]);
changed([...selectedFilters, newFilter]);
}
const removeFilter = index => {
selectedFilters.splice(index, 1);
setSelectedFilters([...selectedFilters]);
changed([...selectedFilters]);
}
const getFiltersList = () => {
return selectedFilters.map(([id, val], index) => {
return <div className={classNames([styles.stylesFormRow, filterStyles.singleFilter])} key={id}>
{id === 'drop-shadow'
? <FilterDropShadow value={val} onChange={e => changedFilter(id, e)}/>
: <FilterSingle filterId={id} value={+val} onChange={e => changedFilter(id, e)}/>
}
<Icon type="material" name="close" onClick={e => removeFilter(index)} className={filterStyles.icon}/>
</div>
}
)
}
const isFilterChosen = (id: string): boolean => {
return selectedFilters.some(([filterId, _]) => id === filterId)
}

const changedFilter = (id: string, val: any) => {
const index = selectedFilters.findIndex(([filterId, _]) => id === filterId)
selectedFilters[index] = [id, val];
setSelectedFilters([...selectedFilters]);
changed([...selectedFilters]);
}

return (
<div className={styles.stylesFormGroup}>
<div className={styles.stylesFormRow}>
<Select onChange={addFilter} label="Dodaj filtr">
<Option value="" selected={true}>Wybierz</Option>
{allFiltersNames.map(([id, name]) =>
<Option key={id} value={id} disabled={isFilterChosen(id)}>{name}</Option>
)}
</Select>
</div>

{getFiltersList()}

</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import styles from "@/components/Creator/LeftPanel/StylesPanel/StylesPanel.module.scss";
import InputWithUnits from "@/components/construction/InputWithUnits/InputWithUnits";
import ColorPicker from "@/components/construction/ColorPicker/ColorPicker";
import {useState} from "react";

type ValueType = [x: number, y: number, blur: number, color: string];

interface Props {
value: ValueType;
onChange: (value: ValueType) => void;

}

export default function (props: Props) {
const [value,setValue] =useState(props.value);
const onChange = (v, index) => {
const val = value;
val[index] = v;
setValue(val)
props.onChange(val);
}

return (
<div className={styles.stylesFormColumn}>
<div className={styles.stylesFormField}>
<InputWithUnits units={['px']} value={value[0]} max={20} min={-20} type="number"
label="Przesunięcie w osi X" onChange={e => onChange(e, 0)}/>
<InputWithUnits units={['px']} value={value[1]} max={20} min={-20} type="number"
label="Przesunięcie w osi Y" onChange={e => onChange(e, 1)}/>
</div>
<div className={styles.stylesFormField}>
<InputWithUnits units={['px']} value={value[2]} max={20} min={0} type="number" label="Rozmycie"
onChange={e => onChange(e, 2)}/>
<ColorPicker value={value[3]} onChange={e => onChange(e, 3)}/>
</div>
</div>
)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import {Units} from "@/types/units";
import styles from "@/components/Creator/LeftPanel/StylesPanel/StylesPanel.module.scss";
import Slider from "@/components/construction/Slider/Slider";
import {useEffect, useState} from "react";

interface Props {
value: number;
filterId: string;
onChange: (value: number) => void;
}

type FilterDefaults = [id: string, name: string, unit: Units, min: number, max: number];
export default function (props: Props) {
const [filterDefaults, setFilterDefaults] = useState<{ min: number, max: number }>(null);
const [label, setLabel] = useState<string>(null);
const [unit, setUnit] = useState<Units>(null);
const displayValFn = val => `${val}${unit}`;

const filters: FilterDefaults[] = [
['blur', 'Rozmycie', 'px', 0, 100],
['brightness', 'Jasność', '%', 0, 200],
['contrast', 'Kontrast', '%', 0, 200],
['grayscale', 'Skala szarości', '%', 0, 100],
['hue-rotate', 'Obracanie odcienia', 'deg', 0, 360],
['invert', 'Odwrócenie kolorów', '%', 0, 100],
['opacity', 'Nieprzezroczystość', '%', 0, 100],
['saturate', 'Saturacja', '%', 0, 100],
['sepia', 'Sepia', '%', 0, 100],
];

const getSingleFilterDefaults = (filterId: string): FilterDefaults => {
return filters.find(([id, ..._]) => id === filterId)
}

useEffect(() => {
const [, _name, _unit, min, max] = getSingleFilterDefaults(props.filterId);
setLabel(_name);
setUnit(_unit);
setFilterDefaults({min, max});
}, [props.filterId])

return (
<div className={styles.stylesFormField}>
{filterDefaults ? <Slider label={label}
displayValueFn={displayValFn}
min={filterDefaults?.min}
max={filterDefaults?.max}
onChange={props.onChange}
value={props.value}/> : ''}
</div>
)

}
3 changes: 2 additions & 1 deletion src/components/Creator/LeftPanel/StylesPanel/StylesPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import TextColumns from "@/components/Creator/LeftPanel/StylesPanel/TextColumns/
import Text from "@/components/Creator/LeftPanel/StylesPanel/Text/Text";
import TextShadow from "@/components/Creator/LeftPanel/StylesPanel/TextShadow/TextShadow";
import Background from "@/components/Creator/LeftPanel/StylesPanel/Background/Background";
import Filter from "@/components/Creator/LeftPanel/StylesPanel/Filter/Filter";

export default function () {
const selectedBlock = useSelector((state: any) => state.structure.selectedBlock);
Expand Down Expand Up @@ -52,7 +53,7 @@ export default function () {
['quote', <AccordionItem key={'quote'} title="Cytat"><Quote onChange={styleChange}/></AccordionItem>],
['margin', <AccordionItem key={'margin'} title="Marginesy zewnętrzne"><Margin onChange={styleChange}/></AccordionItem>],
['padding', <AccordionItem key={'padding'} title="Marginesy wewnętrzne"><Padding onChange={styleChange}/></AccordionItem>],
// ['filter', <AccordionItem key={'filter'} title="Filtry"><Layout onChange={styleChange}/></AccordionItem>],
['filter', <AccordionItem key={'filter'} title="Filtry"><Filter onChange={styleChange}/></AccordionItem>],
// ['animations', <AccordionItem key={'animations'} title="Animacje"><Layout onChange={styleChange}/></AccordionItem>],
]
const canShow = ([id,c]) => {
Expand Down
2 changes: 1 addition & 1 deletion src/store/functions/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export const setAttributesFn = (state: StructureState, {payload}) => {


export const duplicateBlockFn = (state: StructureState, {payload}: PayloadAction<BlockInterface>) => {
const {structure, selectedBlock} = state;
const {structure} = state;

state.structure = duplicateBlk(structure, payload.id);
};
Expand Down

0 comments on commit 79fb514

Please sign in to comment.