diff --git a/.gitignore b/.gitignore index 64b4f398..b7ec0f03 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ /.history .DS_Store /tsconfig.tsbuildinfo -.env.local \ No newline at end of file +.env.local +.tsconfig.tsbuildinfo \ No newline at end of file diff --git a/src/components/editors/AudioEditor/index.tsx b/src/components/editors/AudioEditor/index.tsx index 13b8055e..4771c303 100644 --- a/src/components/editors/AudioEditor/index.tsx +++ b/src/components/editors/AudioEditor/index.tsx @@ -1,46 +1,39 @@ -import React, { FC, useCallback, useMemo } from 'react'; +import { FC } from 'react'; import { UploadDropzone } from '~/components/upload/UploadDropzone'; -import { UploadType } from '~/constants/uploads'; -import { IFile } from '~/types'; import { NodeEditorProps } from '~/types/node'; import { useUploaderContext } from '~/utils/context/UploaderContextProvider'; -import { values } from '~/utils/ramda'; import { AudioGrid } from '../AudioGrid'; import { ImageGrid } from '../ImageGrid'; import styles from './styles.module.scss'; -type IProps = NodeEditorProps; - -const AudioEditor: FC = () => { - const { pending, filesAudios, filesImages, setFiles, uploadFiles } = useUploaderContext()!; - - const pendingImages = useMemo( - () => values(pending).filter(item => item.type === UploadType.Image), - [pending] - ); - - const pendingAudios = useMemo( - () => values(pending).filter(item => item.type === UploadType.Audio), - [pending] - ); - - const setImages = useCallback((values: IFile[]) => setFiles([...values, ...filesAudios]), [ - setFiles, - filesAudios, - ]); - const setAudios = useCallback((values: IFile[]) => setFiles([...values, ...filesImages]), [ - setFiles, +const AudioEditor: FC = () => { + const { filesImages, - ]); + filesAudios, + uploadFiles, + setImages, + setAudios, + pendingAudios, + pendingImages, + } = useUploaderContext()!; return (
- - + + +
); diff --git a/src/components/editors/RoomEditor/index.tsx b/src/components/editors/RoomEditor/index.tsx new file mode 100644 index 00000000..71fb19a8 --- /dev/null +++ b/src/components/editors/RoomEditor/index.tsx @@ -0,0 +1,42 @@ +import { FC } from 'react'; + +import { UploadDropzone } from '~/components/upload/UploadDropzone'; +import { NodeEditorProps } from '~/types/node'; +import { useUploaderContext } from '~/utils/context/UploaderContextProvider'; + +import { AudioGrid } from '../AudioGrid'; +import { ImageGrid } from '../ImageGrid'; + +import styles from './styles.module.scss'; + +const RoomEditor: FC = () => { + const { + filesImages, + filesAudios, + uploadFiles, + setImages, + setAudios, + pendingAudios, + pendingImages, + } = useUploaderContext()!; + + return ( + +
+ + + +
+
+ ); +}; + +export { RoomEditor }; diff --git a/src/components/editors/RoomEditor/styles.module.scss b/src/components/editors/RoomEditor/styles.module.scss new file mode 100644 index 00000000..68850a77 --- /dev/null +++ b/src/components/editors/RoomEditor/styles.module.scss @@ -0,0 +1,6 @@ +@import "src/styles/variables"; + +.wrap { + padding-bottom: $upload_button_height + $gap; + min-height: 200px; +} diff --git a/src/constants/node/index.ts b/src/constants/node/index.ts index c9179b1f..b4fd9ad4 100644 --- a/src/constants/node/index.ts +++ b/src/constants/node/index.ts @@ -7,6 +7,7 @@ import { EditorImageUploadButton } from '~/components/editors/EditorImageUploadB import { EditorPublicSwitch } from '~/components/editors/EditorPublicSwitch'; import { EditorUploadCoverButton } from '~/components/editors/EditorUploadCoverButton'; import { ImageEditor } from '~/components/editors/ImageEditor'; +import { RoomEditor } from '~/components/editors/RoomEditor'; import { TextEditor } from '~/components/editors/TextEditor'; import { VideoEditor } from '~/components/editors/VideoEditor'; import { LabAudio } from '~/components/lab/LabAudioBlock'; @@ -49,6 +50,7 @@ export const NODE_TYPES = { AUDIO: 'audio', VIDEO: 'video', TEXT: 'text', + ROOM: 'room', }; export type INodeComponentProps = { @@ -56,12 +58,22 @@ export type INodeComponentProps = { isLoading: boolean; }; -export type INodeComponents = Record, FC>; +export type INodeComponents = Record< + ValueOf, + FC +>; export const LAB_PREVIEW_LAYOUT: Record[]> = { [NODE_TYPES.IMAGE]: [LabImage, LabPad, LabNodeTitle, LabDescription], [NODE_TYPES.VIDEO]: [LabVideo, LabPad, LabNodeTitle, LabDescription], - [NODE_TYPES.AUDIO]: [LabPad, LabNodeTitle, LabPad, NodeAudioImageBlock, LabAudio, LabPad], + [NODE_TYPES.AUDIO]: [ + LabPad, + LabNodeTitle, + LabPad, + NodeAudioImageBlock, + LabAudio, + LabPad, + ], [NODE_TYPES.TEXT]: [LabPad, LabNodeTitle, LabPad, LabText, LabPad], }; @@ -94,11 +106,23 @@ export const NODE_EDITORS: Record< [NODE_TYPES.TEXT]: TextEditor, [NODE_TYPES.VIDEO]: VideoEditor, [NODE_TYPES.AUDIO]: AudioEditor, + [NODE_TYPES.ROOM]: RoomEditor, }; -export const NODE_PANEL_COMPONENTS: Record[]> = { - [NODE_TYPES.TEXT]: [EditorFiller, EditorUploadCoverButton, EditorPublicSwitch], - [NODE_TYPES.VIDEO]: [EditorFiller, EditorUploadCoverButton, EditorPublicSwitch], +export const NODE_PANEL_COMPONENTS: Record< + string, + FC[] +> = { + [NODE_TYPES.TEXT]: [ + EditorFiller, + EditorUploadCoverButton, + EditorPublicSwitch, + ], + [NODE_TYPES.VIDEO]: [ + EditorFiller, + EditorUploadCoverButton, + EditorPublicSwitch, + ], [NODE_TYPES.IMAGE]: [ EditorImageUploadButton, EditorFiller, @@ -112,6 +136,11 @@ export const NODE_PANEL_COMPONENTS: Record[]> EditorUploadCoverButton, EditorPublicSwitch, ], + [NODE_TYPES.ROOM]: [ + EditorAudioUploadButton, + EditorImageUploadButton, + EditorFiller, + ], }; export const NODE_EDITOR_DATA: Record< diff --git a/src/containers/main/BottomContainer/styles.module.scss b/src/containers/main/BottomContainer/styles.module.scss index 9a4f2c44..55ff8f4a 100644 --- a/src/containers/main/BottomContainer/styles.module.scss +++ b/src/containers/main/BottomContainer/styles.module.scss @@ -1,4 +1,4 @@ -@import "src/styles/variables"; +@import 'src/styles/variables'; .wrap { position: sticky; diff --git a/src/hooks/data/useUploader.ts b/src/hooks/data/useUploader.ts index 1d0b5004..b0e4702c 100644 --- a/src/hooks/data/useUploader.ts +++ b/src/hooks/data/useUploader.ts @@ -13,7 +13,7 @@ import { keys } from '~/utils/ramda'; export const useUploader = ( subject: UploadSubject, target: UploadTarget, - initialFiles?: IFile[] + initialFiles?: IFile[], ) => { const store = useLocalObservable(() => new UploaderStore(initialFiles)); @@ -26,8 +26,14 @@ export const useUploader = ( // TODO: cancel all uploads on unmount const pending = await store.addPending(id, file); - const onProgress = ({ loaded, total }) => store.updateProgress(id, loaded, total); - const result = await apiUploadFile({ file, target, type: pending.type, onProgress }); + const onProgress = ({ loaded, total }) => + store.updateProgress(id, loaded, total); + const result = await apiUploadFile({ + file, + target, + type: pending.type, + onProgress, + }); store.removePending(id); store.addFile(result); @@ -38,14 +44,14 @@ export const useUploader = ( showErrorToast(error); } }, - [store, target] + [store, target], ); const uploadFiles = useCallback( async (files: File[]) => { - await Promise.any(files.map(file => uploadFile(file))); + await Promise.any(files.map((file) => uploadFile(file))); }, - [uploadFile] + [uploadFile], ); const isUploading = keys(store.pending).length > 0; @@ -61,5 +67,7 @@ export const useUploader = ( pendingAudios: store.pendingAudios, isUploading, setFiles: store.setFiles, + setImages: store.setImages, + setAudios: store.setAudios, }; }; diff --git a/src/layouts/RoomLayout/index.tsx b/src/layouts/RoomLayout/index.tsx index ab7ad460..ef66c4e2 100644 --- a/src/layouts/RoomLayout/index.tsx +++ b/src/layouts/RoomLayout/index.tsx @@ -1,51 +1,76 @@ import React, { FC } from 'react'; +import { Button } from '~/components/input/Button'; +import { Role } from '~/constants/auth'; +import { Dialog } from '~/constants/modal'; +import { NODE_TYPES } from '~/constants/node'; import { Container } from '~/containers/main/Container'; +import { useAuth } from '~/hooks/auth/useAuth'; +import { useShowModal } from '~/hooks/modal/useShowModal'; import markdown from '~/styles/common/markdown.module.scss'; import styles from './styles.module.scss'; interface RoomLayoutProps {} -const RoomLayout: FC = () => ( -
-
- -
-
-

Рум

+const RoomLayout: FC = () => { + const createNode = useShowModal(Dialog.CreateNode); + const { user } = useAuth(); -

- Пока ещё концепт, над которым я размышляю, ты видишь его, потому - что включил суперсилы в Борисе. -

+ return ( +
+
+ +
+
+

Рум

-

- Все идеи насчёт этого раздела можно посмотреть{' '} - - на гитхабе - - . -

+

+ Пока ещё концепт, над которым я размышляю, ты видишь его, потому + что включил суперсилы в Борисе. +

-

- Здесь, скорее всего, будет возможность добавить несколько песен и - картинок для слайдшоу. -

+

+ Все идеи насчёт этого раздела можно посмотреть{' '} + + на гитхабе + + . +

-

- Если помните einsam.ru или раздел Nowhere на старой версии сайта, - то будет что-то такое. -

+

+ Здесь, скорее всего, будет возможность добавить несколько песен + и картинок для слайдшоу. +

+ +

+ Если помните einsam.ru или раздел Nowhere на старой версии + сайта, то будет что-то такое. +

+ + {user.role === Role.Admin && ( +

+
+ + +

+ )} +
-
- + +
+
-
-
-); + ); +}; export { RoomLayout }; diff --git a/src/pages/boris.tsx b/src/pages/boris.tsx index d4425475..ac8154d4 100644 --- a/src/pages/boris.tsx +++ b/src/pages/boris.tsx @@ -17,6 +17,7 @@ const BorisPage: VFC = observer(() => { const { node, isLoading, update } = useLoadNode(BORIS_NODE_ID); const onShowImageModal = useImageModal(); + const { onLoadMoreComments, onDelete: onDeleteComment, @@ -26,6 +27,7 @@ const BorisPage: VFC = observer(() => { isLoading: isLoadingComments, isLoadingMore, } = useNodeComments(BORIS_NODE_ID); + const { title, stats, isLoadingStats } = useBoris(comments); return ( diff --git a/src/store/uploader/UploaderStore.ts b/src/store/uploader/UploaderStore.ts index dc20fa45..591e6f77 100644 --- a/src/store/uploader/UploaderStore.ts +++ b/src/store/uploader/UploaderStore.ts @@ -23,7 +23,21 @@ export class UploaderStore { } addFile = (file: IFile) => this.files.push(file); - setFiles = (files: IFile[]) => (this.files = files); + + // replaces all files + setFiles = (files: IFile[]) => { + this.files = files; + }; + + // refreshes only images, keeping audios as they was + setImages = (newImages: IFile[]) => { + this.files = [...newImages, ...this.filesAudios]; + }; + + // refreshes only audios, keeping audios as they was + setAudios = (newAudios: IFile[]) => { + this.files = [...newAudios, ...this.filesImages]; + }; /** adds pending from file */ addPending = async (id: string, file: File) => { @@ -60,21 +74,25 @@ export class UploaderStore { /** returns only image files */ get filesImages() { - return this.files.filter(file => file && file.type === UploadType.Image); + return this.files.filter((file) => file && file.type === UploadType.Image); } /** returns only image pending */ get pendingImages() { - return values(this.pending).filter(item => item.type === UploadType.Image); + return values(this.pending).filter( + (item) => item.type === UploadType.Image, + ); } /** returns only audio files */ get filesAudios() { - return this.files.filter(file => file && file.type === UploadType.Audio); + return this.files.filter((file) => file && file.type === UploadType.Audio); } /** returns only audio pending */ get pendingAudios() { - return values(this.pending).filter(item => item.type === UploadType.Audio); + return values(this.pending).filter( + (item) => item.type === UploadType.Audio, + ); } } diff --git a/src/utils/context/UploaderContextProvider.tsx b/src/utils/context/UploaderContextProvider.tsx index 251ba1c3..dbe3d6cb 100644 --- a/src/utils/context/UploaderContextProvider.tsx +++ b/src/utils/context/UploaderContextProvider.tsx @@ -17,6 +17,8 @@ const UploaderContext = createContext({ pendingImages: [], isUploading: false, setFiles: (files: IFile[]) => files, + setImages: (files: IFile[]) => files, + setAudios: (files: IFile[]) => files, }); export const UploaderContextProvider: FC<{