diff --git a/client/src/components/DraggableContainer.tsx b/client/src/components/DraggableContainer.tsx
index 7028911..9333b30 100644
--- a/client/src/components/DraggableContainer.tsx
+++ b/client/src/components/DraggableContainer.tsx
@@ -2,13 +2,15 @@ import { useEffect, useRef, useState } from "react";
import type { ReactNode } from "react";
import clsx from "clsx";
-interface Position {
- top?: number;
- left?: number;
- right?: number;
- bottom?: number;
+export interface Position {
+ top?: number | string;
+ left?: number | string;
+ right?: number | string;
+ bottom?: number | string;
}
+export type Corner = "top-left" | "top-right" | "bottom-left" | "bottom-right";
+
interface DraggableContainerProps {
/** Содержимое контейнера */
children: ReactNode;
@@ -18,10 +20,12 @@ interface DraggableContainerProps {
autoAlign?: boolean;
/** Ограничить перетаскивание границами окна (по умолчанию false) */
constrainToBounds?: boolean;
- /** Начальная позиция контейнера */
+ /** Начальный угол экрана (имеет приоритет над initialPosition) */
+ initialCorner?: Corner;
+ /** Начальная позиция контейнера (используется если не указан initialCorner) */
initialPosition?: Position;
- /** Отступ от краев экрана при снэпинге (по умолчанию 20px) */
- padding?: number;
+ /** Отступ от краев экрана при снэпинге и начальной позиции (по умолчанию "20px"). Можно указать в px, %, vw, vh */
+ padding?: number | string;
/** Дополнительные CSS классы */
className?: string;
/** Колбэк при изменении позиции */
@@ -43,8 +47,20 @@ interface DraggableContainerProps {
*
*
* @example
+ * // С указанием начального угла и отступами в процентах
+ *
+ *
+ *
+ *
+ * @example
+ * // С отступами в vw
+ *
+ *
+ *
+ *
+ * @example
* // С ограничением перетаскивания границами окна
- *
+ *
*
*
*
@@ -59,8 +75,9 @@ export default function DraggableContainer({
enableSnapping = false,
autoAlign = false,
constrainToBounds = false,
- initialPosition = { top: 20, right: 20 },
- padding = 20,
+ initialCorner,
+ initialPosition,
+ padding = "20px",
className = "",
onPositionChange,
}: DraggableContainerProps) {
@@ -72,7 +89,33 @@ export default function DraggableContainer({
initialPosition: { top: 0, left: 0 },
});
- const [position, setPosition] = useState(initialPosition);
+ // Функция для преобразования угла в позицию
+ const getPositionFromCorner = (corner: Corner): Position => {
+ switch (corner) {
+ case "top-left":
+ return { top: padding, left: padding };
+ case "top-right":
+ return { top: padding, right: padding };
+ case "bottom-left":
+ return { bottom: padding, left: padding };
+ case "bottom-right":
+ return { bottom: padding, right: padding };
+ }
+ };
+
+ // Определяем начальную позицию
+ const getInitialPosition = (): Position => {
+ if (initialCorner) {
+ return getPositionFromCorner(initialCorner);
+ }
+ if (initialPosition) {
+ return initialPosition;
+ }
+ // По умолчанию - верхний правый угол
+ return { top: padding, right: padding };
+ };
+
+ const [position, setPosition] = useState(getInitialPosition());
const [isDragging, setIsDragging] = useState(false);
const [dragStartAlignment, setDragStartAlignment] = useState("");
@@ -256,7 +299,9 @@ export default function DraggableContainer({
if (isDragging) {
document.addEventListener("mousemove", handleMouseMove);
document.addEventListener("mouseup", handleMouseUp);
- document.addEventListener("touchmove", handleTouchMove, { passive: false });
+ document.addEventListener("touchmove", handleTouchMove, {
+ passive: false,
+ });
document.addEventListener("touchend", handleTouchEnd);
document.addEventListener("touchcancel", handleTouchEnd);
@@ -277,10 +322,14 @@ export default function DraggableContainer({
zIndex: 1000,
};
- if (position.top !== undefined) style.top = `${position.top}px`;
- if (position.left !== undefined) style.left = `${position.left}px`;
- if (position.right !== undefined) style.right = `${position.right}px`;
- if (position.bottom !== undefined) style.bottom = `${position.bottom}px`;
+ const formatValue = (value: number | string): string => {
+ return typeof value === "number" ? `${value}px` : value;
+ };
+
+ if (position.top !== undefined) style.top = formatValue(position.top);
+ if (position.left !== undefined) style.left = formatValue(position.left);
+ if (position.right !== undefined) style.right = formatValue(position.right);
+ if (position.bottom !== undefined) style.bottom = formatValue(position.bottom);
return style;
};
diff --git a/client/src/components/SessionUsersPanel2.tsx b/client/src/components/SessionUsersPanel2.tsx
index 5c656bb..509271a 100644
--- a/client/src/components/SessionUsersPanel2.tsx
+++ b/client/src/components/SessionUsersPanel2.tsx
@@ -35,8 +35,9 @@ function SessionUsersPanel2() {
{users.map((user) => (