first commit

master
Reza_ashrafi 3 years ago
parent f77ba5b349
commit d3c7962a15
  1. 10
      craco.config.js
  2. 15
      package.json
  3. 21
      src/App.css
  4. 45
      src/App.js
  5. 30
      src/components/Checkbox/index.js
  6. 97
      src/components/Checkbox/index.scss
  7. BIN
      src/components/Input/danger.png
  8. 162
      src/components/Input/index.js
  9. 60
      src/components/Input/index.scss
  10. BIN
      src/components/Input/tick.png
  11. 13
      src/components/Radio/index.js
  12. 58
      src/components/Radio/index.scss
  13. 31
      src/components/Search/index.js
  14. BIN
      src/components/Search/search.png
  15. BIN
      src/components/SelectCheckbox/arrow-top.png
  16. 108
      src/components/SelectCheckbox/index.js
  17. BIN
      src/components/SelectRadio/arrow-top.png
  18. 100
      src/components/SelectRadio/index.js
  19. BIN
      src/components/SelectRadio/x.png
  20. 9
      src/components/SidebarCategoryHover/Col.js
  21. 1492
      src/components/SidebarCategoryHover/data.js
  22. 66
      src/components/SidebarCategoryHover/index.js
  23. 11
      src/components/Switch/index.js
  24. 52
      src/components/Switch/index.scss
  25. BIN
      src/components/VerticalExpandableProductFilter/arrow-top.png
  26. 170
      src/components/VerticalExpandableProductFilter/index.js
  27. BIN
      src/components/VerticalExpandableProductFilter/search.png
  28. 88
      src/components/search-with-suggest/index.js
  29. BIN
      src/components/search-with-suggest/search.png
  30. 3
      src/index.css
  31. 1
      src/react-app-env.d.ts
  32. 11
      tailwind.config.js
  33. 3472
      yarn.lock

@ -0,0 +1,10 @@
module.exports = {
style: {
postcss: {
plugins: [
require('tailwindcss'),
require('autoprefixer'),
],
},
},
}

@ -3,18 +3,22 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@craco/craco": "^6.4.0",
"@headlessui/react": "^1.4.1",
"@testing-library/jest-dom": "^5.11.4", "@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0", "@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10", "@testing-library/user-event": "^12.1.10",
"lodash": "^4.17.21",
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-scripts": "4.0.3", "react-scripts": "4.0.3",
"sass": "^1.43.4",
"web-vitals": "^1.0.1" "web-vitals": "^1.0.1"
}, },
"scripts": { "scripts": {
"start": "react-scripts start", "start": "craco start",
"build": "react-scripts build", "build": "craco build",
"test": "react-scripts test", "test": "craco test",
"eject": "react-scripts eject" "eject": "react-scripts eject"
}, },
"eslintConfig": { "eslintConfig": {
@ -34,5 +38,10 @@
"last 1 firefox version", "last 1 firefox version",
"last 1 safari version" "last 1 safari version"
] ]
},
"devDependencies": {
"autoprefixer": "^9.8.8",
"postcss": "^7.0.39",
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.17"
} }
} }

@ -1,5 +1,7 @@
.App { .App {
text-align: center; text-align: center;
direction: rtl;
padding: 10px;
} }
.App-logo { .App-logo {
@ -7,12 +9,31 @@
pointer-events: none; pointer-events: none;
} }
.en {
direction: ltr;
text-align: left;
}
.fa {
direction: rtl;
text-align: right;
}
@media (prefers-reduced-motion: no-preference) { @media (prefers-reduced-motion: no-preference) {
.App-logo { .App-logo {
animation: App-logo-spin infinite 20s linear; animation: App-logo-spin infinite 20s linear;
} }
} }
/* clears the ‘X’ from Internet Explorer */
input[type=search]::-ms-clear { display: none; width : 0; height: 0; }
input[type=search]::-ms-reveal { display: none; width : 0; height: 0; }
/* clears the ‘X’ from Chrome */
input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-results-button,
input[type="search"]::-webkit-search-results-decoration { display: none; }
.App-header { .App-header {
background-color: #282c34; background-color: #282c34;
min-height: 100vh; min-height: 100vh;

@ -1,23 +1,38 @@
import logo from './logo.svg'; import Search from './components/Search';
import SearchWithSuggest from './components/search-with-suggest';
import Input from './components/Input';
import Radio from './components/Radio';
import Checkbox from './components/Checkbox';
import SelectRadio from './components/SelectRadio';
import SelectCheckbox from './components/SelectCheckbox';
import Switch from './components/Switch';
import VerticalExpandableProductFilter from './components/VerticalExpandableProductFilter';
import SidebarCategoryHover from './components/SidebarCategoryHover';
import './App.css'; import './App.css';
function App() { function App() {
return ( return (
<div className="App"> <div className="App">
<header className="App-header"> <Search />
<img src={logo} className="App-logo" alt="logo" /> <hr className="my-2" />
<p> <SearchWithSuggest lang="en" />
Edit <code>src/App.js</code> and save to reload. <hr className="my-2" />
</p> <Input status={false} label={'نام خانوادگی'} lang="fa" maxLength="30" inputMode="numeric" message="خطا" />
<a <hr className="my-2" />
className="App-link" <Radio />
href="https://reactjs.org" <hr className="my-2" />
target="_blank" <Checkbox />
rel="noopener noreferrer" <hr className="my-2" />
> <SelectRadio />
Learn React <hr className="my-2" />
</a> <SelectCheckbox />
</header> <hr className="my-2" />
<Switch />
<hr className="my-2" />
<VerticalExpandableProductFilter />
<hr className="my-2" />
<SidebarCategoryHover />
</div> </div>
); );
} }

@ -0,0 +1,30 @@
import React from "react";
import './index.scss';
export default function Checkbox(props) {
return (
<div>
<svg className="checkbox-symbol">
<symbol id="check" viewBox="0 0 12 10">
<polyline
points="1.5 6 4.5 9 10.5 1"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
></polyline>
</symbol>
</svg>
<div className="checkbox-container">
<input className="checkbox-input" id="apples" type="checkbox" checked={props.checked} />
<label className="checkbox" htmlFor="apples">
<span>
<svg width="12px" height="10px">
<use xlinkHref="#check"></use>
</svg>
</span>
</label>
</div>
</div>
);
}

@ -0,0 +1,97 @@
.checkbox-symbol {
position: absolute;
width: 0;
height: 0;
pointer-events: none;
user-select: none;
}
.checkbox-container {
box-sizing: border-box;
color: #222;
height: 30px;
display: flex;
justify-content: center;
align-items: center;
flex-flow: row wrap;
}
.checkbox-container * {
box-sizing: border-box;
}
.checkbox-input {
position: absolute;
visibility: hidden;
}
.checkbox {
user-select: none;
cursor: pointer;
padding: 6px 8px;
border-radius: 6px;
overflow: hidden;
transition: all 0.3s ease;
display: flex;
}
.checkbox:not(:last-child) {
margin-right: 6px;
}
.checkbox:hover {
background: inherit;
}
.checkbox span {
vertical-align: middle;
transform: translate3d(0, 0, 0);
}
.checkbox span:first-child {
position: relative;
flex: 0 0 18px;
width: 18px;
height: 18px;
border-radius: 4px;
transform: scale(1);
border: 1px solid #cccfdb;
transition: all 0.3s ease;
}
.checkbox span:first-child svg {
position: absolute;
top: 3px;
left: 2px;
fill: none;
stroke: #fff;
stroke-dasharray: 16px;
stroke-dashoffset: 16px;
transition: all 0.3s ease;
transform: translate3d(0, 0, 0);
}
.checkbox span:last-child {
padding-left: 8px;
line-height: 18px;
}
.checkbox:hover span:first-child {
border-color: #0077ff;
}
.checkbox-input:checked + .checkbox span:first-child {
background: #0077ff;
border-color: #0077ff;
animation: zoom-in-out 0.3s ease;
}
.checkbox-input:checked + .checkbox span:first-child svg {
stroke-dashoffset: 0;
}
@keyframes zoom-in-out {
50% {
transform: scale(0.9);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 860 B

@ -0,0 +1,162 @@
import React, { useState } from "react";
import _ from "lodash";
import "./index.scss";
import tick from "./tick.png";
import danger from "./danger.png";
const langDetector = (lang, option1, option2) => {
return lang === "fa" ? option1 : option2;
};
const inputStatusHandler = (value, focus, status, primary, success, danger) => {
if (!focus) {
return "";
} else {
if (!value) {
return primary;
} else {
if (status) {
return success;
} else {
return danger;
}
}
}
};
export default function Input(props) {
const [value, setValue] = useState("");
const [focusToggle, setFocusToggle] = useState(false);
const { lang, theme, inputMode, label, status, maxLength, message } = props;
const onChange = (val) => {
setValue(val);
};
return (
<div
className={_.join(
["input flex flex-col relative mb-6", langDetector(lang, "fa", "en")],
" "
)}
>
<label
className={_.join(
[
"absolute top-1/2 transform -translate-y-1/2 text-gray-500 bg-white px-2 text-xs transition-all duration-300",
langDetector(lang, "right-2", "left-2"),
inputStatusHandler(
value,
focusToggle,
status,
"input__labelFocus",
"input__labelSuccess",
"input__labelDanger"
),
],
" "
)}
onClick={() => setFocusToggle(true)}
>
{label}
</label>
<input
type="text"
inputMode={inputMode}
className={_.join(
[
"flex-1 border rounded-sm outline-none p-2",
inputStatusHandler(
value,
focusToggle,
status,
"input__inputActive",
"input__inputSuccess",
"input__inputDanger"
),
"transition",
],
" "
)}
onChange={(e) => onChange(e.target.value)}
value={value}
onFocus={() => setFocusToggle(true)}
onBlur={() => !value ? setFocusToggle(false) : setFocusToggle(true)}
maxLength={maxLength}
/>
{!status && value && (
<img
src={danger}
alt={langDetector(lang, "اشتباه", "wrong")}
className={_.join(
[
"w-4 h-4 absolute top-1/2 transform -translate-y-1/2",
langDetector(lang, "left-2", "right-2"),
],
" "
)}
/>
)}
{status && value && (
<img
src={tick}
alt={langDetector(lang, "درست", "right")}
className={_.join(
[
"w-4 h-4 absolute top-1/2 transform -translate-y-1/2",
langDetector(lang, "left-2", "right-2"),
],
" "
)}
/>
)}
{value && !status && (
<span
className={_.join(
[
"input__message text-xs absolute -bottom-5",
langDetector(lang, "right-2", "left-2"),
inputStatusHandler(
value,
focusToggle,
status,
"",
"input__messageSuccess",
"input__messageDanger"
),
"transition",
],
" "
)}
>
{message}
</span>
)}
{value && (
<span
className={_.join(
[
"input__length absolute -bottom-5 text-xs",
langDetector(lang, "left-2", "right-2"),
inputStatusHandler(
value,
focusToggle,
status,
"",
"input__lengthSuccess",
"input__lengthDanger"
),
"transition",
],
" "
)}
>
{value.length + "/" + maxLength}
</span>
)}
</div>
);
}

@ -0,0 +1,60 @@
$primary: #06BACE;
$gray: #dbdbdb;
$danger: #E00A0A;
$success: #23C933;
.input {
&__labelFocus{
top: 0px !important;
font-size: 9px !important;
color: $primary !important;
}
&__labelDanger{
top: 0px !important;
font-size: 9px !important;
color: $danger !important;
}
&__labelSuccess{
top: 0px !important;
font-size: 9px !important;
color: $success !important;
}
&__inputActive{
border-color: $primary !important;
}
&__inputSuccess{
border-color: $success !important;
}
&__inputDanger{
border-color: $danger !important;
}
&__message{
&Success{
color: $success;
}
&Danger{
color: $danger;
}
}
&__length{
&Success{
color: $success;
}
&Danger{
color: $danger;
}
}
}
.en {
direction: ltr;
text-align: left;
}
.fa {
direction: rtl;
text-align: right;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 B

@ -0,0 +1,13 @@
import React from "react";
import './index.scss';
export default function Radio(props) {
return (
<div className="container">
<div className="radio flex items-center">
<input id="radio-1" name={props.name} type="radio" />
<label htmlFor="radio-1" className="radio-label text-xs">{props.label}</label>
</div>
</div>
);
}

@ -0,0 +1,58 @@
$color1: #f4f4f4;
$color2: #3197EE;
.radio {
input[type="radio"] {
position: absolute;
opacity: 0;
+ .radio-label {
&:before {
content: '';
background: $color1;
border-radius: 100%;
border: 1px solid darken($color1, 25%);
display: inline-block;
width: 1.4em;
height: 1.4em;
position: relative;
vertical-align: top;
margin-left: 0.5em;
cursor: pointer;
text-align: center;
transition: all 250ms ease;
}
}
&:checked {
+ .radio-label {
&:before {
background-color: $color2;
box-shadow: inset 0 0 0 4px $color1;
}
}
}
&:focus {
+ .radio-label {
&:before {
outline: none;
border-color: $color2;
}
}
}
&:disabled {
+ .radio-label {
&:before {
box-shadow: inset 0 0 0 4px $color1;
border-color: darken($color1, 25%);
background: darken($color1, 25%);
}
}
}
+ .radio-label {
&:empty {
&:before {
margin-right: 0;
}
}
}
}
}

@ -0,0 +1,31 @@
import React from "react";
import _ from "lodash";
import searchIcon from "./search.png";
const langDetector = (lang = 'fa', option1, option2) => {
return lang === "fa" ? option1 : option2;
};
export default function Search(props) {
return (
<div className="flex items-center justify-center w-full">
<div className="relative text-gray-600 focus-within:text-gray-400 w-full">
<span className={_.join(["absolute inset-y-0 flex items-center pl-2", langDetector(props.lang, "left-0", "right-0")], " ")}>
<button
type="submit"
className="p-1 focus:outline-none focus:shadow-outline"
>
<img src={searchIcon} className="w-6 h-6" alt="" />
</button>
</span>
<input
type="search"
name="q"
className="w-full py-2 text-sm text-white border rounded-sm pr-5 outline-none focus:ring-1 focus:text-gray-900"
placeholder={_.join([langDetector(props.lang , "جستجو...", "Search...")], " ")}
autocomplete="off"
/>
</div>
</div>
);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 857 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

@ -0,0 +1,108 @@
import React, { useState } from "react";
import _ from "lodash";
import Checkbox from "../Checkbox";
import arrowIcon from "./arrow-top.png";
const langDetector = (lang, option1, option2) => {
return lang === "fa" ? option1 : option2;
};
export default function SelectCheckbox(props) {
const [selectedItem, setSelectedItem] = useState("");
const [value, setValue] = useState("");
const [toggle, setToggle] = useState(false);
const { lang, theme, list, label } = props;
const onChangeItem = (val) => {
setSelectedItem(val);
};
const onChangeText = (val) => {
setValue(val);
};
return (
<div
className={_.join(
["select-search flex flex-col relative", langDetector(lang, "fa", "en")],
" "
)}
>
<div
className={_.join(
["search flex flex-column relative", langDetector(lang, "fa", "en")],
" "
)}
onClick={() => setToggle(() => !toggle)}
>
<input
type="search"
className="w-full py-3 px-3 text-xs border rounded-sm bg-transparent placeholder-gray-500"
onChange={(e) => onChangeText(e.target.value)}
placeholder={langDetector(lang, "تنظیمات", "setting")}
disabled
/>
<img
src={arrowIcon}
alt=""
className={_.join(
[
"cursor-pointer w-5 absolute top-1/2 transform -translate-y-1/2 transition-all duration-300",
langDetector(lang, "left-3", "right-3"),
toggle ? '-rotate-180' : '',
],
" "
)}
/>
</div>
{toggle && (
<div
className={_.join(
[
"select-search__list absolute top-12 left-0 flex flex-col px-5 border rounded-sm w-full bg-white z-20",
toggle ? "select-search__listActive" : "",
"transition",
],
" "
)}
>
<ul className="list-none p-0 divide-y divide-gray-200 w-full">
{list?.map((item, i) => (
<>
<li key={i} className="w-full py-1 text-gray-700 flex items-start flex-col">
<div className="flex items-center">
<Checkbox checked={false} />
<span className="text-xs">{item?.name}</span>
</div>
<ul className="w-full p-0 mx-auto my-0">
{item.sublist?.map((item1, j) => (
<>
<li className="flex flex-row flex-1 pt-1 px-5 pb-0 items-center" key={j}>
<Checkbox checked={false} />
<span className="text-xs">{item1?.name}</span>
</li>
</>
))}
</ul>
</li>
</>
))}
</ul>
</div>
)}
</div>
);
}
SelectCheckbox.defaultProps = {
lang: "fa",
theme: "light",
label: "کشور خود را انتخاب کنید",
list: [
{ name: "وسایل آشپزخانه", sublist: [{ name: "اتو" }] },
{ name: "غریق نجات از تمام جهات" },
{ name: "قاشق و چنگال" },
{ name: "وسایل آشپزخانه" },
],
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

@ -0,0 +1,100 @@
import React, { useState } from "react";
import _ from "lodash";
import Radio from "../Radio";
import xIcon from "./x.png";
import arrowIcon from "./arrow-top.png";
const langDetector = (lang, option1, option2) => {
return lang === "fa" ? option1 : option2;
};
export default function SelectRadio(props) {
const [selectedItem, setSelectedItem] = useState("");
const [value, setValue] = useState("");
const [toggle, setToggle] = useState(false);
const { lang, theme, list, label } = props;
const onChangeItem = (val) => {
setSelectedItem(val);
};
const onChangeText = (val) => {
setValue(val);
};
return (
<div
className={_.join(
[
"flex flex-col relative",
langDetector(lang, "fa", "en"),
],
" "
)}
>
<div
className={_.join(
["flex flex-col relative", langDetector(lang, "fa", "en")],
" "
)}
onClick={() => setToggle(() => !toggle)}
>
<input
type="search"
className="py-3 px-3 text-xs border rounded-sm bg-transparent focus:ring-1 outline-none focus:placeholder-blue-500 placeholder-gray-500"
onChange={(e) => onChangeText(e.target.value)}
placeholder={langDetector(lang, "تنظیمات", "setting")}
disabled
/>
<img
src={arrowIcon}
alt=""
className={_.join(
[
"w-5 absolute top-1/2 transform -translate-y-1/2 cursor-pointer transition-all duration-300",
langDetector(lang, "left-3", "right-3"),
toggle ? '-rotate-180' : ''
],
" "
)}
/>
</div>
{toggle && (
<div
className={_.join(
[
"w-full absolute top-12 left-0 flex flex-col border rounded-sm bg-white z-20",
toggle ? "select-search__listActive" : "",
],
" "
)}
>
<ul className="list-none divide-y divide-gray-200 py-1 text-gray-700 w-full px-3">
{list?.map((item, i) => (
<>
<li key={i} className="transition w-full text-gray-700 items-center py-3 flex-col justify-center">
<Radio label={item?.name} name="reza" />
</li>
</>
))}
</ul>
</div>
)}
</div>
);
}
SelectRadio.defaultProps = {
lang: "fa",
theme: "light",
label: "کشور خود را انتخاب کنید",
list: [
{ name: "وسایل آشپزخانه", sublist: [{ name: "اتو" }] },
{ name: "غریق نجات از تمام جهات" },
{ name: "قاشق و چنگال" },
{ name: "وسایل آشپزخانه" },
],
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 346 B

@ -0,0 +1,9 @@
import React from 'react'
export default function Col() {
return (
<div>
</div>
)
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,66 @@
import React, { useState } from "react";
import category from "./data";
import _ from "lodash";
export default function SidebarCategoryHover() {
const [activeItem, setActiveItem] = useState(null);
const arrayLength = category.length;
return (
<div className="flex flex-col w-60 relative" onMouseOut={() => setActiveItem(null)}>
<ul className="list-none w-full divide-y border divide-gray-200">
{category.map((item, i) => (
<>
<li
className="p-4 w-full text-gray-500 font-normal text-sm hover:bg-blue-100 text-right"
key={i}
onMouseOver={() => setActiveItem(item.id)}
>
{item.name}
</li>
<ul
className={_.join(
[
"absolute right-60 top-0 h-full border flex-row divide-x divide-gray-200",
activeItem === item.id ? "flex" : "hidden",
],
" "
)}
onMouseOver={() => setActiveItem(item.id)}
// style={{width : 1000}}
>
<li className="h-full w-52 bg-red-50 flex flex-col text-right">
<li className="flex items-center" style={{ minHeight: "calc(100% / 9)" }}>
{item.categories[0].name}
</li>
{item.categories[0].list.map((item1, i) => (
<li
key={i}
className="text-normal flex text-sm items-center"
style={{ minHeight: "calc(100% / 9)" }}
>
{item1.name}
</li>
))}
<li className="flex items-center" style={{ minHeight: "calc(100% / 9)" }}>
{item.categories[1].name}
</li>
{item.categories[1].list.map((item1, i) => (
<li key={i} className="flex items-center" style={{ minHeight: "calc(100% / 9)" }}>
{item1.name}
</li>
))}
</li>
<li className="h-full w-52 bg-green-50"></li>
<li className="h-full w-52 bg-blue-50"></li>
<li className="h-full w-52 bg-red-50"></li>
<li className="h-full w-52 bg-green-50"></li>
<li className="h-full w-52 bg-blue-50"></li>
</ul>
</>
))}
</ul>
</div>
);
}

@ -0,0 +1,11 @@
import React from "react";
import "./index.scss";
export default function index() {
return (
<div className="switch">
<input type="checkbox" id="toggle" />
<label for="toggle"></label>
</div>
);
}

@ -0,0 +1,52 @@
// *, *:after, *:before {
// // box-sizing: border-box;
// }
// body {
// min-height: 100vh;
// display: flex;
// align-items: center;
// justify-content: center;
// }
.switch {
position: relative;
input[type="checkbox"] {
visibility: hidden;
position : absolute;
&:checked + label {
transform: rotate(0deg);
background-color: #000;
&:before {
transform: translateX(35.5px);
background-color: #fff;
}
}
}
label {
display: flex;
width: 70px;
height: 34px;
border: 3px solid;
border-radius: 99em;
position: relative;
transition: transform 0.3s ease-in-out;
transform-origin: 50% 50%;
cursor: pointer;
&:before {
transition: transform 0.3s ease;
transition-delay: 0s;
content: "";
display: block;
position: absolute;
width: 24px;
height: 24px;
background-color: #000;
border-radius: 50%;
top: 2px;
left: 3px;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

@ -0,0 +1,170 @@
import React, { useState, useEffect } from "react";
import searchIcon from "./search.png";
import _ from "lodash";
import Checkbox from "../Checkbox";
import arrowIcon from "./arrow-top.png";
const langDetector = (lang = "fa", option1, option2) => {
return lang === "fa" ? option1 : option2;
};
export default function VerticalExpandableProductFilter(props) {
const [text, setText] = useState("");
const [searchResult, setSearchResult] = useState([]);
useEffect(() => {
let fakeSearchResult;
fakeSearchResult = props.list.filter(
(item1) => item1.name.indexOf(text) !== -1
);
setSearchResult(fakeSearchResult);
}, [text]);
return (
<div className="flex flex-col w-full border rounded-md pt-6 bg-transparent max-h-screen">
<strong className="text-md text-gray-500 w-full mb-3 text-right px-3">
دسته بندی
</strong>
<form className="relative w-full px-3 mb-3">
<input
type="text"
placeholder={_.join(
[langDetector(props.lang, "جستجو...", "Search...")],
" "
)}
className="border rounded-sm py-1 px-2 w-full placeholder-gray-300 outline-none text-gray-500"
onChange={(e) => setText(e.target.value)}
/>
<span
className={_.join(
[
"absolute inset-y-0 flex items-center",
langDetector(props.lang, "left-4", "right-4"),
],
" "
)}
>
<button
type="submit"
className="p-1 focus:outline-none focus:shadow-outline"
>
<img src={searchIcon} className="w-5 h-5" alt="" />
</button>
</span>
</form>
<ul className="w-full list-none flex flex-col divide-y divide-gray-100">
{(searchResult.length > 0 ? searchResult : props.list)?.map(
(item1, i) => (
<li
key={i}
className="hover:bg-gray-100 px-3 flex flex-row items-center justify-between py-2"
>
<div className="flex flex-row items-center">
<Checkbox />
<strong className="text-xs font-light text-gray-500">
{item1.name}
</strong>
</div>
{item1.subList?.length > 0 && (
<img
src={arrowIcon}
alt=""
className={_.join(
[
"cursor-pointer w-5 transform transition-all duration-300",
item1.expaneded ? "" : "rotate-180",
],
" "
)}
/>
)}
</li>
)
)}
</ul>
</div>
);
}
VerticalExpandableProductFilter.defaultProps = {
list: [
{
id: 0,
name: "وسایل آشپزخانه",
expaneded: false,
subList: [],
},
{
id: 3,
name: "ماشین و موتور سیکلت",
expaneded: false,
subList: [
{
id: 4,
name: "ماشین",
},
{
id: 5,
name: "موتور",
},
],
},
{
id: 6,
name: "اتاق خواب",
expaneded: false,
subList: [
{
id: 7,
name: "کمد",
},
{
id: 8,
name: "تخت خواب",
},
],
},
{
id: 9,
name: "دکوراسیون و چیدمان",
expaneded: false,
subList: [],
},
{
id: 10,
name: "وسایل بهداشت شخصی",
expaneded: false,
subList: [
{
id: 11,
name: "مسواک",
},
{
id: 12,
name: "حوله",
},
],
},
{
id: 13,
name: "وسایل بهداشت شخصی",
expaneded: false,
subList: [
{
id: 14,
name: "مسواک",
},
{
id: 15,
name: "حوله",
},
],
},
{
id: 16,
name: "وسایل بهداشت شخصی",
expaneded: false,
subList: [],
},
],
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 857 B

@ -0,0 +1,88 @@
import React, { useState } from "react";
import _ from "lodash";
import searchIcon from "./search.png";
const langDetector = (lang, option1, option2) => {
return lang === "fa" ? option1 : option2;
};
export default function PopularSearch(props) {
const [value, setValue] = useState("");
const [popularsToggle, setPopularsToggle] = useState(false);
const { lang, theme, populars } = props;
const onChange = (val) => {
setValue(val);
};
return (
<div
className={_.join(
["flex flex-col relative search", langDetector(lang, "fa", "en")],
" "
)}
>
<input
type="search"
className="transition py-2 pr-4 pl-2 mx-0 border rounded-sm outline-none focus:ring-1 placeholder-gray-500 placeholder-opacity-40 focus:placeholder-blue-300"
onChange={(e) => onChange(e.target.value)}
value={value}
placeholder={langDetector(
lang,
"نام کالا را جستجو کنید",
"search product name"
)}
onFocus={() => setPopularsToggle(true)}
onBlur={() =>
setTimeout(() => {
setPopularsToggle(false);
}, 250)
}
/>
<img
src={searchIcon}
alt={langDetector(lang, "جستجو", "search")}
className={_.join(
[
"search__icon absolute w-6 h-6 top-1/2 transform -translate-y-1/2",
langDetector(lang, "left-3", "right-3"),
],
" "
)}
/>
<div
className={_.join(
[
"search__populars w-full mt-0 border rounded-sm top-12 left-0 absolute z-10 px-4 bg-white",
popularsToggle ? "flex flex-col" : "hidden",
"transition",
],
" "
)}
>
<strong className="py-3">
{langDetector(lang, "جستجوهای پرطرفدار", "Popular search")}
</strong>
<ul className="divide-y divide-gray-200">
{populars?.map((item, i) => (
<>
<li
key={i}
className="transition py-3 px-1 hover:bg-blue-100"
onClick={() => setValue(() => item)}
>
{item}
</li>
</>
))}
</ul>
</div>
</div>
);
}
PopularSearch.defaultProps = {
lang: "fa",
theme: "light",
populars: ["علی", "علیرضا", "محمد", "محمدرضا"],
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 857 B

@ -1,3 +1,6 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
body { body {
margin: 0; margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',

@ -0,0 +1 @@
/// <reference types="react-scripts" />

@ -0,0 +1,11 @@
module.exports = {
purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
darkMode: 'class', // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
}

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save