Init(Core): add to repo and add seeders

This commit is contained in:
2026-04-28 22:48:42 +03:30
commit be6b699ff0
205 changed files with 22524 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
export default function ApplicationLogo(props) {
return (
<svg {...props} viewBox="0 0 316 316" xmlns="http://www.w3.org/2000/svg">
<path d="M305.8 81.125C305.77 80.995 305.69 80.885 305.65 80.755C305.56 80.525 305.49 80.285 305.37 80.075C305.29 79.935 305.17 79.815 305.07 79.685C304.94 79.515 304.83 79.325 304.68 79.175C304.55 79.045 304.39 78.955 304.25 78.845C304.09 78.715 303.95 78.575 303.77 78.475L251.32 48.275C249.97 47.495 248.31 47.495 246.96 48.275L194.51 78.475C194.33 78.575 194.19 78.725 194.03 78.845C193.89 78.955 193.73 79.045 193.6 79.175C193.45 79.325 193.34 79.515 193.21 79.685C193.11 79.815 192.99 79.935 192.91 80.075C192.79 80.285 192.71 80.525 192.63 80.755C192.58 80.875 192.51 80.995 192.48 81.125C192.38 81.495 192.33 81.875 192.33 82.265V139.625L148.62 164.795V52.575C148.62 52.185 148.57 51.805 148.47 51.435C148.44 51.305 148.36 51.195 148.32 51.065C148.23 50.835 148.16 50.595 148.04 50.385C147.96 50.245 147.84 50.125 147.74 49.995C147.61 49.825 147.5 49.635 147.35 49.485C147.22 49.355 147.06 49.265 146.92 49.155C146.76 49.025 146.62 48.885 146.44 48.785L93.99 18.585C92.64 17.805 90.98 17.805 89.63 18.585L37.18 48.785C37 48.885 36.86 49.035 36.7 49.155C36.56 49.265 36.4 49.355 36.27 49.485C36.12 49.635 36.01 49.825 35.88 49.995C35.78 50.125 35.66 50.245 35.58 50.385C35.46 50.595 35.38 50.835 35.3 51.065C35.25 51.185 35.18 51.305 35.15 51.435C35.05 51.805 35 52.185 35 52.575V232.235C35 233.795 35.84 235.245 37.19 236.025L142.1 296.425C142.33 296.555 142.58 296.635 142.82 296.725C142.93 296.765 143.04 296.835 143.16 296.865C143.53 296.965 143.9 297.015 144.28 297.015C144.66 297.015 145.03 296.965 145.4 296.865C145.5 296.835 145.59 296.775 145.69 296.745C145.95 296.655 146.21 296.565 146.45 296.435L251.36 236.035C252.72 235.255 253.55 233.815 253.55 232.245V174.885L303.81 145.945C305.17 145.165 306 143.725 306 142.155V82.265C305.95 81.875 305.89 81.495 305.8 81.125ZM144.2 227.205L100.57 202.515L146.39 176.135L196.66 147.195L240.33 172.335L208.29 190.625L144.2 227.205ZM244.75 114.995V164.795L226.39 154.225L201.03 139.625V89.825L219.39 100.395L244.75 114.995ZM249.12 57.105L292.81 82.265L249.12 107.425L205.43 82.265L249.12 57.105ZM114.49 184.425L96.13 194.995V85.305L121.49 70.705L139.85 60.135V169.815L114.49 184.425ZM91.76 27.425L135.45 52.585L91.76 77.745L48.07 52.585L91.76 27.425ZM43.67 60.135L62.03 70.705L87.39 85.305V202.545V202.555V202.565C87.39 202.735 87.44 202.895 87.46 203.055C87.49 203.265 87.49 203.485 87.55 203.695V203.705C87.6 203.875 87.69 204.035 87.76 204.195C87.84 204.375 87.89 204.575 87.99 204.745C87.99 204.745 87.99 204.755 88 204.755C88.09 204.905 88.22 205.035 88.33 205.175C88.45 205.335 88.55 205.495 88.69 205.635L88.7 205.645C88.82 205.765 88.98 205.855 89.12 205.965C89.28 206.085 89.42 206.225 89.59 206.325C89.6 206.325 89.6 206.325 89.61 206.335C89.62 206.335 89.62 206.345 89.63 206.345L139.87 234.775V285.065L43.67 229.705V60.135ZM244.75 229.705L148.58 285.075V234.775L219.8 194.115L244.75 179.875V229.705ZM297.2 139.625L253.49 164.795V114.995L278.85 100.395L297.21 89.825V139.625H297.2Z" />
</svg>
);
}

View File

@@ -0,0 +1,5 @@
export default function Button({ onClick, children, className, disabled }) {
return (
<button disabled={ disabled } onClick={ onClick } className={"rounded-lg shadow-sm children-white p-2 active:outline active:animate-pulse " + className}>{children}</button>
);
}

View File

@@ -0,0 +1,10 @@
export default function CategoryAddItemButton({ onClick }){
return (
<button className="flex flex-col items-center h-full bg-gray-200 p-6 rounded-lg">
<span className="text-lg">افزودن محصول</span>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" className="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 6v12m6-6H6" />
</svg>
</button>
)
}

View File

@@ -0,0 +1,22 @@
import CategoryItemCard from "@/Components/CategoryItemCard"
export default function CategoryCard({ category }){
return (
<div className="flex bg-white rounded-lg col-span-2 lg:col-span-1 h-full p-6 justify-between">
<div className="flex flex-col">
<span className="text-xl font-semibold">{category.title}</span>
<span className="text-gray-600">{category.products.length } محصول</span>
<span className="text-gray-600">{category.description}</span>
</div>
<div className="flex">
{category.products[0] ? <CategoryItemCard item={ category.products[0] } /> : null}
<button className="flex flex-col items-center h-full bg-gray-200 p-6 rounded-lg z-40">
<span className="text-lg">افزودن محصول</span>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" className="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 6v12m6-6H6" />
</svg>
</button>
</div>
</div>
)
}

View File

@@ -0,0 +1,38 @@
import Input from '@/Components/Input'
import TextArea from '@/Components/TextArea'
import Button from '@/Components/Button'
import { useState } from 'react'
import { router } from '@inertiajs/react'
export default function CategoryForm({ onCancel, onSubmit }) {
let [title, setTitle] = useState();
let [description, setDescription] = useState();
let [step, setStep] = useState(1);
function handleSubmit(){
let data = {
title: title,
description: description,
}
router.post('/categories/store', data);
onCancel();
}
if(step == 1){
return (
<div className="bg-white rounded-lg w-full max-w-lg h-fit p-8 space-y-4">
<span className="pb-4 text-lg font-semibold">دسته بندی جدید</span>
<Input label="عنوان" className="w-full ml-6" onChange={(e) => {setTitle(e.target.value)}} />
<TextArea label="توضیحات (اختیاری)" className="" onChange={(e) => {setDescription(e.target.value)}}/>
<div className="flex">
<Button onClick={ onCancel } className="bg-white text-black border-gray-300 border-2 w-full transition hover:bg-zinc-100 ml-4 shadow-none">لغو</Button>
<Button onClick={ e => setStep(2) } className="w-full text-white bg-zinc-800 transition hover:bg-zinc-700">ایجاد</Button>
</div>
</div>
);
}
return("step2");
}

View File

@@ -0,0 +1,9 @@
export default function CategoryCard({ item, h }){
console.log(item);
return (
<div className={"ml-[-52px] w-32 h-full first:scale-[90%] z-30 my-auto bg-red-300 rounded-lg transition duration-600 hover:z-50 hover:scale-100"}>
{item.title}
<img src={item.images[0] ? item.images[0].thumbnail : null} alt={item.images[0] ? item.images[0].alt : null} />
</div>
)
}

View File

@@ -0,0 +1,12 @@
export default function Checkbox({ className = '', ...props }) {
return (
<input
{...props}
type="checkbox"
className={
'rounded border-gray-300 text-indigo-600 shadow-sm focus:ring-indigo-500 ' +
className
}
/>
);
}

View File

@@ -0,0 +1,11 @@
export default function CreateButton({ onClick, title }){
return (
<button onClick={ onClick } className="bg-zinc-900 text-white rounded-lg w-fit h-full py-2 px-6 flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" className="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 6v12m6-6H6" />
</svg>
<span className="pr-4 leading-none">{ title }</span>
</button>
)
}

View File

@@ -0,0 +1,15 @@
export default function DangerButton({ className = '', disabled, children, ...props }) {
return (
<button
{...props}
className={
`inline-flex items-center px-4 py-2 bg-red-600 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-red-500 active:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 transition ease-in-out duration-150 ${
disabled && 'opacity-25'
} ` + className
}
disabled={disabled}
>
{children}
</button>
);
}

View File

@@ -0,0 +1,91 @@
import { useState, createContext, useContext, Fragment } from 'react';
import { Link } from '@inertiajs/react';
import { Transition } from '@headlessui/react';
const DropDownContext = createContext();
const Dropdown = ({ children }) => {
const [open, setOpen] = useState(false);
const toggleOpen = () => {
setOpen((previousState) => !previousState);
};
return (
<DropDownContext.Provider value={{ open, setOpen, toggleOpen }}>
<div className="relative">{children}</div>
</DropDownContext.Provider>
);
};
const Trigger = ({ children }) => {
const { open, setOpen, toggleOpen } = useContext(DropDownContext);
return (
<>
<div onClick={toggleOpen}>{children}</div>
{open && <div className="fixed inset-0 z-40" onClick={() => setOpen(false)}></div>}
</>
);
};
const Content = ({ align = 'right', width = '48', contentClasses = 'py-1 bg-white', children }) => {
const { open, setOpen } = useContext(DropDownContext);
let alignmentClasses = 'origin-top';
if (align === 'left') {
alignmentClasses = 'origin-top-left left-0';
} else if (align === 'right') {
alignmentClasses = 'origin-top-right right-0';
}
let widthClasses = '';
if (width === '48') {
widthClasses = 'w-48';
}
return (
<>
<Transition
as={Fragment}
show={open}
enter="transition ease-out duration-200"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<div
className={`absolute z-50 mt-2 rounded-md shadow-lg ${alignmentClasses} ${widthClasses}`}
onClick={() => setOpen(false)}
>
<div className={`rounded-md ring-1 ring-black ring-opacity-5 ` + contentClasses}>{children}</div>
</div>
</Transition>
</>
);
};
const DropdownLink = ({ className = '', children, ...props }) => {
return (
<Link
{...props}
className={
'block w-full px-4 py-2 text-left text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out ' +
className
}
>
{children}
</Link>
);
};
Dropdown.Trigger = Trigger;
Dropdown.Content = Content;
Dropdown.Link = DropdownLink;
export default Dropdown;

View File

@@ -0,0 +1,7 @@
export default function Header(){
return (
<div className="bg-white h-16 w-full rounded-lg">
Hello
</div>
)
}

View File

@@ -0,0 +1,22 @@
export default function TextArea({ image, onChange, id, label, className, placeholder=null }) {
return (
<div className={"flex flex-col h-full" + " " + className}>
<label className="pr-3 pb-0.5">{ label }</label>
<div class="flex items-center justify-center w-full h-full">
<label for="dropzone-file" class="flex flex-col items-center justify-center w-full h-full border border-gray-300 rounded-lg cursor-pointer">
<div class="w-full h-full flex flex-col items-center justify-center p-6">
{ image ? image : (
<div className="flex justify-center items-center bg-gray-200 rounded-lg w-full h-52">
<svg class="w-8 h-8 mb-4 text-gray-500 dark:text-gray-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 16">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 13h3a3 3 0 0 0 0-6h-.025A5.56 5.56 0 0 0 16 6.5 5.5 5.5 0 0 0 5.207 5.021C5.137 5.017 5.071 5 5 5a4 4 0 0 0 0 8h2.167M10 15V6m0 0L8 8m2-2 2 2"/>
</svg>
</div>
)}
<span className="pt-4">برای آپلود عکس کلیک کنید</span>
</div>
<input onChange={ onChange } id="dropzone-file" type="file" class="hidden" />
</label>
</div>
</div>
);
}

View File

@@ -0,0 +1,9 @@
export default function Input({ error, onChange, id, label, className, placeholder=null, value }) {
return (
<div className={"flex flex-col" + " " + className}>
<label className="pr-3 pb-0.5">{ label }</label>
<input onChange={ onChange } id={id} type="text" className="w-full border-gray-300 rounded-lg" placeholder={placeholder} value={value}/>
{error && <span className="text-sm text-red-600 pt-0.5 pr-3">{error}</span>}
</div>
);
}

View File

@@ -0,0 +1,7 @@
export default function InputError({ message, className = '', ...props }) {
return message ? (
<p {...props} className={'text-sm text-red-600 ' + className}>
{message}
</p>
) : null;
}

View File

@@ -0,0 +1,7 @@
export default function InputLabel({ value, className = '', children, ...props }) {
return (
<label {...props} className={`block font-medium text-sm text-gray-700 ` + className}>
{value ? value : children}
</label>
);
}

View File

@@ -0,0 +1,57 @@
import { Fragment } from 'react';
import { Dialog, Transition } from '@headlessui/react';
export default function Modal({ children, show = false, maxWidth = '2xl', closeable = true, onClose = () => {} }) {
const close = () => {
if (closeable) {
onClose();
}
};
const maxWidthClass = {
sm: 'sm:max-w-sm',
md: 'sm:max-w-md',
lg: 'sm:max-w-lg',
xl: 'sm:max-w-xl',
'2xl': 'sm:max-w-2xl',
}[maxWidth];
return (
<Transition show={show} as={Fragment} leave="duration-200">
<Dialog
as="div"
id="modal"
className="fixed inset-0 flex overflow-y-auto px-4 py-6 sm:px-0 items-center z-50 transform transition-all"
onClose={close}
>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="absolute inset-0 bg-gray-500/75" />
</Transition.Child>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel
className={`mb-6 bg-white rounded-lg overflow-hidden shadow-xl transform transition-all sm:w-full sm:mx-auto ${maxWidthClass}`}
>
{children}
</Dialog.Panel>
</Transition.Child>
</Dialog>
</Transition>
);
}

View File

@@ -0,0 +1,18 @@
import { Link } from '@inertiajs/react';
export default function NavLink({ active = false, className = '', children, ...props }) {
return (
<Link
{...props}
className={
'inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium leading-5 transition duration-150 ease-in-out focus:outline-none ' +
(active
? 'border-indigo-400 text-gray-900 focus:border-indigo-700 '
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:text-gray-700 focus:border-gray-300 ') +
className
}
>
{children}
</Link>
);
}

View File

@@ -0,0 +1,15 @@
export default function PrimaryButton({ className = '', disabled, children, ...props }) {
return (
<button
{...props}
className={
`inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 focus:bg-gray-700 active:bg-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition ease-in-out duration-150 ${
disabled && 'opacity-25'
} ` + className
}
disabled={disabled}
>
{children}
</button>
);
}

View File

@@ -0,0 +1,88 @@
import Input from '@/Components/Input'
import TextArea from '@/Components/TextArea'
import Button from '@/Components/Button'
import ImageInput from '@/Components/ImageInput'
import SelectInput from '@/Components/SelectInput'
import { useState } from 'react'
import { router } from '@inertiajs/react'
export default function ProductForm({ onCancel, onSubmit, categories, preselectedCategory=null }) {
categories = categories.map((category) => ({value: category.id, label: category.title}));
let [title, setTitle] = useState();
let [description, setDescription] = useState();
let [price, setPrice] = useState(0);
let [inventory, setInventory] = useState(-1);
let [selectedImage, setSelectedImage] = useState(null);
let [createCategoryOpen, setCreateCategoryOpen] = useState(false);
let [selectedCategory, setSelectedCategory] = useState(preselectedCategory ?? (categories[0] ?? null));
function handleSubmit(){
let data = {
title: title,
description: description,
price: price,
inventory: inventory,
image: selectedImage,
}
console.log(selectedCategory);
router.post('/products/store/'+String(selectedCategory.value), data);
onCancel();
}
function handleCreateCategoryOpen(inputValue){
setCategoryTitle(inputValue);
setCreateCategoryOpen(true);
}
function handleModalCancel(){
setCreateCategoryOpen(false);
setCreateTagOpen(false);
}
function handleCategoryModalSubmit(){
setCreateCategoryOpen(false);
setData('category', {value: categoryTitle, label: categoryTitle});
}
return (
<div className="flex flex-col bg-white rounded-lg w-full max-w-4xl h-fit p-8 space-y-8">
<span className="pb-4 text-lg font-semibold">محصول جدید</span>
<SelectInput value={ selectedCategory } setValue={e => setSelectedCategory(e) } options={ categories } onCreateOption={ handleCreateCategoryOpen } label="دسته بندی" className="w-full"/>
<div className="flex flex-col lg:flex-row">
<div className="w-full pl-4 flex flex-col space-y-4">
<Input label="عنوان" className="w-full ml-6" onChange={(e) => {setTitle(e.target.value)}} />
<div className="flex justify-between">
<Input label="قیمت" className="w-full ml-6" onChange={(e) => {setPrice(e.target.value)}} />
<Input label="موجودی" className="w-full" onChange={(e) => {setInventory(e.target.value)}} />
</div>
<TextArea label="توضیحات (اختیاری)" className="" onChange={(e) => {setDescription(e.target.value)}}/>
</div>
<div className="w-full pr-4 h-full">
<ImageInput id="image" image={selectedImage && (
<div className="flex flex-col justify-center w-full h-52 rounded-2xl">
<img
alt="not found"
className="h-52 object-scale-down"
src={URL.createObjectURL(selectedImage)}
/>
<button class="z-10" onClick={() => setSelectedImage(null)}>حذف</button>
</div>
)} onChange={(event) => {
setSelectedImage(event.target.files[0]);
}} label="تصویر" />
</div>
</div>
<div className="flex">
<Button onClick={ onCancel } className="bg-white text-black border-gray-300 border-2 w-full transition hover:bg-zinc-100 ml-4 shadow-none">لغو</Button>
<Button onClick={ handleSubmit } className="w-full text-white bg-zinc-800 transition hover:bg-zinc-700">ایجاد</Button>
</div>
</div>
);
}

View File

@@ -0,0 +1,57 @@
import { Link } from '@inertiajs/react'
import { useState, useEffect } from 'react'
import { router } from '@inertiajs/react'
export default function ProductTable({ items, title, links}) {
console.log(items);
const items_list = items.map(items => {
return (
<tr key={items.id} className="border-y text-right font-normal">
<td className="py-2">{ items.id }</td>
<td className="py-2">{ items.images[0] ? <img className="z-0 w-16 h-16 rounded-lg shadow-inner p-1" src={ items.images[0].thumbnail } alt={ items.images[0].alt } /> : null }</td>
<td className="py-2 text-lg">{ items.title }</td>
<td className="py-2">{ items.price }</td>
<td className="py-2">{ items.inventory }</td>
</tr>
)}
);
return (
<div className="h-full">
<div className="flex flex-col bg-white p-4 rounded-lg shadow-md hover:shadow-lg transition overflow-auto max-h-full">
<div className="w-full px-3">
<table className="table-auto border-collapse w-full text-right">
<th className="text-sm font-normal w-12">
<span>
آیدی
</span>
</th>
<th className="text-sm font-normal w-20">
<span>
عکس
</span>
</th>
<th className="text-sm font-normal">
<span>
عنوان
</span>
</th>
<th className="text-sm font-normal">
<span>
قیمت
</span>
</th>
<th className="text-sm font-normal">
<span>
موجودی
</span>
</th>
{items_list}
</table>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,16 @@
import { Link } from '@inertiajs/react';
export default function ResponsiveNavLink({ active = false, className = '', children, ...props }) {
return (
<Link
{...props}
className={`w-full flex items-start pl-3 pr-4 py-2 border-l-4 ${
active
? 'border-indigo-400 text-indigo-700 bg-indigo-50 focus:text-indigo-800 focus:bg-indigo-100 focus:border-indigo-700'
: 'border-transparent text-gray-600 hover:text-gray-800 hover:bg-gray-50 hover:border-gray-300 focus:text-gray-800 focus:bg-gray-50 focus:border-gray-300'
} text-base font-medium focus:outline-none transition duration-150 ease-in-out ${className}`}
>
{children}
</Link>
);
}

View File

@@ -0,0 +1,12 @@
export default function Searchbar({ onSearch, value }) {
return (
<div class="relative h-fit">
<div class="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none">
<svg aria-hidden="true" class="w-5 h-5 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg>
</div>
<input type="search" id="default-search" class="block w-52 p-2 pr-10 pl-2 rounded-lg border-gray-200 focus:border-red-200 focus:ring-red-200" placeholder="جستجو..." />
</div>
);
}

View File

@@ -0,0 +1,16 @@
export default function SecondaryButton({ type = 'button', className = '', disabled, children, ...props }) {
return (
<button
{...props}
type={type}
className={
`inline-flex items-center px-4 py-2 bg-white border border-gray-300 rounded-md font-semibold text-xs text-gray-700 uppercase tracking-widest shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 disabled:opacity-25 transition ease-in-out duration-150 ${
disabled && 'opacity-25'
} ` + className
}
disabled={disabled}
>
{children}
</button>
);
}

View File

@@ -0,0 +1,13 @@
import CreatableSelect from 'react-select/creatable';
import { useState } from 'react'
export default function Input({ options, value, setValue, onCreateOption, id, label, className, placeholder=null, isMulti=false}) {
return (
<div className={"relative flex flex-col" + " " + className}>
<label className="pr-3 pb-0.5">{ label }</label>
<CreatableSelect isClearable value={ value } onChange={(newValue) => setValue(newValue)} onCreateOption={(e) => onCreateOption(e) } formatCreateLabel={(inputValue) => "ایجاد " + label + ' "' + inputValue + '"'} placeholder={placeholder} options={options} isMulti={isMulti}/>
</div>
);
}

View File

@@ -0,0 +1,17 @@
import SidebarItem from '@/Components/SidebarItem'
export default function Sidebar() {
return (
<div className="flex flex-col w-60 h-full bg-white">
<div className="p-6 border-b text-2xl">
<span>پنل مدیریت</span>
</div>
<div>
<SidebarItem title="دشبورد" href="/dashboard" />
<SidebarItem title="محصولات" href="/products" />
<SidebarItem title="دسته بندی ها" href="/categories" />
<SidebarItem title="مشخصه ها" href="/properties" />
</div>
</div>
)
}

View File

@@ -0,0 +1,8 @@
import { Link } from '@inertiajs/react'
export default function SidebarItem({ title, href }) {
return (
<div className="flex border-b hover:border-l hover:border-l-black transition duration-600 hover:bg-gradient-to-r from-gray-200 to-gray-50">
<Link className="w-full h-full p-4" href={href}>{title}</Link>
</div>
)
}

View File

@@ -0,0 +1,8 @@
export default function TextArea({ onChange, id, label, className, placeholder=null }) {
return (
<div className={"flex flex-col" + " " + className}>
<label className="pr-3 pb-0.5">{ label }</label>
<textarea onChange={ onChange } id={id} type="text" placeholder={placeholder} className="w-full border-gray-300 rounded-lg"></textarea>
</div>
);
}

View File

@@ -0,0 +1,23 @@
import { forwardRef, useEffect, useRef } from 'react';
export default forwardRef(function TextInput({ type = 'text', className = '', isFocused = false, ...props }, ref) {
const input = ref ? ref : useRef();
useEffect(() => {
if (isFocused) {
input.current.focus();
}
}, []);
return (
<input
{...props}
type={type}
className={
'border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm ' +
className
}
ref={input}
/>
);
});