summaryrefslogtreecommitdiff
path: root/src/components/upload
diff options
context:
space:
mode:
authorl3wdfut4pwr <l3wdfut4pwr@gmail.com>2025-12-30 13:46:39 +0200
committerl3wdfut4pwr <l3wdfut4pwr@gmail.com>2025-12-30 13:46:39 +0200
commitc3dcb9c827df6d80ad1b0b1a7c6155561527b39d (patch)
tree76d8b9e706f9e8fcf7acc157a633905ff16c6b74 /src/components/upload
init
Diffstat (limited to 'src/components/upload')
-rw-r--r--src/components/upload/Dropzone.tsx45
-rw-r--r--src/components/upload/SourceInput.tsx20
-rw-r--r--src/components/upload/TagsInput.tsx83
-rw-r--r--src/components/upload/UploadMenu.tsx11
-rw-r--r--src/components/upload/index.ts4
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';