diff options
| author | l3wdfut4pwr <l3wdfut4pwr@gmail.com> | 2025-12-30 13:46:39 +0200 |
|---|---|---|
| committer | l3wdfut4pwr <l3wdfut4pwr@gmail.com> | 2025-12-30 13:46:39 +0200 |
| commit | c3dcb9c827df6d80ad1b0b1a7c6155561527b39d (patch) | |
| tree | 76d8b9e706f9e8fcf7acc157a633905ff16c6b74 /src/components/upload | |
init
Diffstat (limited to 'src/components/upload')
| -rw-r--r-- | src/components/upload/Dropzone.tsx | 45 | ||||
| -rw-r--r-- | src/components/upload/SourceInput.tsx | 20 | ||||
| -rw-r--r-- | src/components/upload/TagsInput.tsx | 83 | ||||
| -rw-r--r-- | src/components/upload/UploadMenu.tsx | 11 | ||||
| -rw-r--r-- | src/components/upload/index.ts | 4 |
5 files changed, 163 insertions, 0 deletions
diff --git a/src/components/upload/Dropzone.tsx b/src/components/upload/Dropzone.tsx new file mode 100644 index 0000000..6980f5c --- /dev/null +++ b/src/components/upload/Dropzone.tsx @@ -0,0 +1,45 @@ +'use client'; + +import Dropzone from 'react-dropzone'; +import UploadIcon from '@icons/upload.svg'; +import { Button } from '@/components/ui'; +import { useRef, useState } from 'react'; + +export function FileDropzone() { + // const [files, setFiles] = useState<File[]>([]); + const hiddenInputRef = useRef<HTMLInputElement | null>(null); + return ( + <Dropzone + multiple + onDrop={(acceptedFiles: File[]) => { + // setFiles((prev) => [...prev, ...acceptedFiles]); + }} + > + {({ getRootProps, getInputProps }) => ( + <div + {...getRootProps({ + className: + 'w-full h-[460px] justify-between p-7.5 border flex flex-col text-sm items-center rounded-[10px]', + })} + > + <input name="files" type="file" ref={hiddenInputRef} /> + <input {...getInputProps()} /> + + <div className="flex flex-col justify-center items-center h-full w-full gap-2.5"> + <UploadIcon /> + <span> + Выбери файлы на компьютере или перетащи сюда. JPG, + PNG до 20MB. + </span> + <span> + {hiddenInputRef.current?.files?.length ?? 0} + </span> + </div> + <Button size={'lg'} className="justify-self-end"> + Выбрать + </Button> + </div> + )} + </Dropzone> + ); +} diff --git a/src/components/upload/SourceInput.tsx b/src/components/upload/SourceInput.tsx new file mode 100644 index 0000000..c93c4b6 --- /dev/null +++ b/src/components/upload/SourceInput.tsx @@ -0,0 +1,20 @@ +'use client'; +import { Input } from '@/components/ui'; + +export function SourceInput() { + return ( + <div className="flex flex-col gap-2.5 w-full"> + <span>ИСТОЧНИК</span> + <Input + name="source" + onKeyDown={(e) => { + if (e.key === 'Enter') { + e.preventDefault(); + } + }} + className="w-full h-10 py-2.5 px-5 border rounded-4xl" + type="text" + /> + </div> + ); +} diff --git a/src/components/upload/TagsInput.tsx b/src/components/upload/TagsInput.tsx new file mode 100644 index 0000000..1b88fa2 --- /dev/null +++ b/src/components/upload/TagsInput.tsx @@ -0,0 +1,83 @@ +'use client'; + +import React, { useState } from 'react'; +import { Tag, WithContext } from 'react-tag-input'; +import ExclamationIcon from '@icons/exclamation.svg'; +import XIcon from '@icons/x.svg'; +import { Button } from '@/components/ui'; + +export function TagsInput() { + const [tags, setTags] = useState<Tag[]>([]); + + return ( + <div className="flex flex-col w-full gap-2.5"> + <div className="flex gap-2.5 font-semibold"> + <span>ТЕГИ</span> + <span className="text-light-violet">{tags.length}/50</span> + <span className="flex gap-1.25 items-center text-light-violet"> + <ExclamationIcon /> Введите минимум 5 тегов через пробел + </span> + </div> + <div + id="tags-container" + className="w-full min-h-[100px] border p-5 rounded-4xl" + > + <input + name="tags" + className="hidden" + defaultValue={tags.map((tag) => tag.id)} + /> + <WithContext + id="tags-input" + tags={tags} + placeholder={'Введите теги'} + maxTags={50} + handleAddition={(tag) => { + setTags((prev) => { + return [...prev, tag]; + }); + }} + handleDelete={(index: number, e) => { + setTags(tags.filter((_, i) => i !== index)); + }} + handleDrag={(tag: Tag, currPos: number, newPos: number) => { + const newTags = tags.slice(); + + newTags.splice(currPos, 1); + newTags.splice(newPos, 0, tag); + + setTags(newTags); + }} + inputFieldPosition="inline" + classNames={{ + tagInputField: 'outline-none text-light-violet', + tag: 'bg-violet px-2.5 py-1.25 flex gap-1.25 rounded-[10px] w-fit items-center', + selected: 'flex gap-2.5 flex-wrap items-center', + }} + removeComponent={RemoveTag} + /> + </div> + </div> + ); +} + +class RemoveTag extends React.Component { + render(): React.ReactNode { + // @ts-expect-error ... + const { className, onRemove } = this.props; + return ( + <Button + variant={'ghost'} + size={'text'} + onClick={onRemove} + className={className} + onFocus={(e) => { + // Это говно здесь из-за того, что без него после удаления бэкспейсом, фокусится крестик + document.getElementById('tags-input')?.focus(); + }} + > + <XIcon /> + </Button> + ); + } +} diff --git a/src/components/upload/UploadMenu.tsx b/src/components/upload/UploadMenu.tsx new file mode 100644 index 0000000..22ebafd --- /dev/null +++ b/src/components/upload/UploadMenu.tsx @@ -0,0 +1,11 @@ +'use client'; + +import { Button } from '@/components/ui'; + +export function UploadMenu() { + return ( + <div className=""> + <Button variant={'menu'}>АРТЫ</Button> + </div> + ); +} diff --git a/src/components/upload/index.ts b/src/components/upload/index.ts new file mode 100644 index 0000000..022fe11 --- /dev/null +++ b/src/components/upload/index.ts @@ -0,0 +1,4 @@ +export * from './UploadMenu'; +export * from './Dropzone'; +export * from './TagsInput'; +export * from './SourceInput'; |
