Skip to content

Commit

Permalink
Merge branch 'release/0.1.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
pipisebastian committed Nov 28, 2024
2 parents 6f85af1 + 7741288 commit fb07e2b
Show file tree
Hide file tree
Showing 21 changed files with 523 additions and 118 deletions.
1 change: 1 addition & 0 deletions @noctaCrdt/Interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export interface RemotePageDeleteOperation {
type: "pageDelete";
clientId: number;
workspaceId: string;
pageTitle: string;
pageId: string;
}

Expand Down
2 changes: 2 additions & 0 deletions @noctaCrdt/LinkedList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,8 @@ export class BlockLinkedList extends LinkedList<Block> {
if (targetNode.prev) {
const prevNode = this.getNode(targetNode.prev);
if (prevNode) prevNode.next = targetNode.next;
} else {
this.head = targetNode.next;
}

if (targetNode.next) {
Expand Down
33 changes: 33 additions & 0 deletions client/src/components/Toast/Toast.style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { css } from "@styled-system/css";

export const ToastWrapper = css({
display: "flex",
// position: "relative", // progress barλ₯Ό μœ„ν•œ position μ„€μ •
gap: "2",
alignItems: "center",
borderRadius: "lg",
width: "fit-content",
paddingBlock: "2",
paddingInline: "4",
color: "white",
backgroundColor: "gray.700",
boxShadow: "lg",
// overflow: "hidden", // progress barκ°€ λ„˜μΉ˜μ§€ μ•Šλ„λ‘
transition: "all",
transitionDuration: "300ms",
});

export const CloseItemBox = css({
width: "15px",
height: "15px",
});

export const ToastProgress = css({
position: "absolute",
left: "0px",
bottom: "0px",
borderRadius: "lg",
width: "100%",
height: "6px",
backgroundColor: "blue",
});
59 changes: 59 additions & 0 deletions client/src/components/Toast/Toast.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { motion } from "framer-motion";
import { useState, useEffect } from "react";
import CloseIcon from "@assets/icons/close.svg?react";
import { ToastWrapper, CloseItemBox, ToastProgress } from "./Toast.style";

interface ToastProps {
message: string;
duration?: number;
onClose: () => void;
}

export const Toast = ({ message, duration = 3000, onClose }: ToastProps) => {
const [isVisible, setIsVisible] = useState(true);
const [isClosing, setIsClosing] = useState(false);

useEffect(() => {
const timer = setTimeout(() => {
setIsClosing(true);
setTimeout(() => {
setIsVisible(false);
onClose();
}, 300);
}, duration);

return () => clearTimeout(timer);
}, [duration, onClose]);

const handleClose = () => {
setIsClosing(true);
setTimeout(() => {
setIsVisible(false);
onClose();
}, 300);
};
if (!isVisible) return null;
return (
<motion.div
className={ToastWrapper}
style={{
opacity: isClosing ? 0 : 1,
transform: isClosing ? "translateY(100%)" : "translateY(0)",
transition: "all 0.3s ease-in-out",
}}
exit={{ opacity: 0 }}
>
<motion.div
initial={{ width: "0%" }}
animate={{ width: "100%" }}
transition={{ duration: duration / 1000, ease: "easeOut" }}
className={ToastProgress}
/>

<span className="text-sm">{message}</span>
<div className={CloseItemBox} onClick={handleClose}>
<CloseIcon />
</div>
</motion.div>
);
};
11 changes: 11 additions & 0 deletions client/src/components/Toast/ToastContainer.style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { css } from "@styled-system/css";

export const ToastContainerStyle = css({
display: "flex",
zIndex: "9999",
position: "fixed",
right: "6",
bottom: "6",
gap: "2",
flexDirection: "column-reverse",
});
23 changes: 23 additions & 0 deletions client/src/components/Toast/ToastContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { AnimatePresence } from "framer-motion";
import { useToastStore } from "@stores/useToastStore";
import { Toast } from "./Toast";
import { ToastContainerStyle } from "./ToastContainer.style";

export const ToastContainer = () => {
const { toasts, removeToast } = useToastStore();

return (
<div className={ToastContainerStyle}>
<AnimatePresence>
{toasts.map((toast) => (
<Toast
key={toast.id}
message={toast.message}
duration={toast.duration}
onClose={() => removeToast(toast.id)}
/>
))}
</AnimatePresence>
</div>
);
};
1 change: 1 addition & 0 deletions client/src/components/sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export const Sidebar = ({
sendPageDeleteOperation({
type: "pageDelete",
workspaceId: "default",
pageTitle: pageToDelete!.title,
pageId,
clientId,
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { PageIconType } from "@noctaCrdt/Interfaces";
import { useState } from "react";
import { useEffect, useState } from "react";
import CloseIcon from "@assets/icons/close.svg?react";
import { useModal } from "@src/components/modal/useModal";
import { PageIconButton } from "../pageIconButton/PageIconButton";
Expand Down Expand Up @@ -29,7 +29,11 @@ export const PageItem = ({
}: PageItemProps) => {
const { isOpen, openModal, closeModal } = useModal();
const [pageIcon, setPageIcon] = useState<PageIconType>(icon);
// μ‚­μ œ λ²„νŠΌ 클릭 ν•Έλ“€λŸ¬

useEffect(() => {
setPageIcon(icon);
}, [icon]);

const handleDelete = (e: React.MouseEvent) => {
e.stopPropagation(); // μƒμœ„ μš”μ†Œλ‘œμ˜ 이벀트 μ „νŒŒ 쀑단
onDelete?.(id);
Expand Down
27 changes: 21 additions & 6 deletions client/src/features/editor/Editor.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DndContext } from "@dnd-kit/core";
import { DndContext, DragEndEvent } from "@dnd-kit/core";
import { SortableContext, verticalListSortingStrategy } from "@dnd-kit/sortable";
import { EditorCRDT } from "@noctaCrdt/Crdt";
import { BlockLinkedList } from "@noctaCrdt/LinkedList";
Expand Down Expand Up @@ -44,10 +44,16 @@ export const Editor = ({ onTitleChange, pageId, pageTitle, serializedEditorData
sendBlockUpdateOperation,
} = useSocketStore();
const { clientId } = useSocketStore();
const [displayTitle, setDisplayTitle] = useState(pageTitle);
const [dragBlockList, setDragBlockList] = useState<string[]>([]);

const [displayTitle, setDisplayTitle] = useState(
pageTitle === "μƒˆλ‘œμš΄ νŽ˜μ΄μ§€" || pageTitle === "" ? "" : pageTitle,
);
useEffect(() => {
if (pageTitle === "μƒˆλ‘œμš΄ νŽ˜μ΄μ§€" || pageTitle === "") {
setDisplayTitle("");
} else {
setDisplayTitle(pageTitle);
}
}, [pageTitle]);

const editorCRDTInstance = useMemo(() => {
let newEditorCRDT;
Expand Down Expand Up @@ -80,7 +86,7 @@ export const Editor = ({ onTitleChange, pageId, pageTitle, serializedEditorData
addNewBlock,
} = useEditorOperation({ editorCRDT, pageId, setEditorState });

const { sensors, handleDragEnd } = useBlockDragAndDrop({
const { sensors, handleDragEnd, handleDragStart } = useBlockDragAndDrop({
editorCRDT: editorCRDT.current,
editorState,
setEditorState,
Expand Down Expand Up @@ -272,7 +278,15 @@ export const Editor = ({ onTitleChange, pageId, pageTitle, serializedEditorData
className={editorTitle}
/>
<div style={{ height: "36px" }}></div>
<DndContext sensors={sensors} onDragEnd={handleDragEnd}>
<DndContext
onDragEnd={(event: DragEndEvent) => {
handleDragEnd(event, dragBlockList, () => setDragBlockList([]));
}}
onDragStart={(event) => {
handleDragStart(event, setDragBlockList);
}}
sensors={sensors}
>
<SortableContext
items={editorState.linkedList
.spread()
Expand All @@ -298,6 +312,7 @@ export const Editor = ({ onTitleChange, pageId, pageTitle, serializedEditorData
onTextStyleUpdate={onTextStyleUpdate}
onTextColorUpdate={onTextColorUpdate}
onTextBackgroundColorUpdate={onTextBackgroundColorUpdate}
dragBlockList={dragBlockList}
/>
))}
</SortableContext>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const iconStyle = cva({
variants: {
type: {
ul: {
fontSize: "20px", // bullet point size
fontSize: "6px", // bullet point size
},
ol: {
paddingRight: "4px",
Expand Down
11 changes: 9 additions & 2 deletions client/src/features/editor/components/IconBlock/IconBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,20 @@ import { iconContainerStyle, iconStyle } from "./IconBlock.style";
interface IconBlockProps {
type: ElementType;
index: number | undefined;
indent?: number;
}

export const IconBlock = ({ type, index = 1 }: IconBlockProps) => {
export const IconBlock = ({ type, index = 1, indent = 0 }: IconBlockProps) => {
const getIcon = () => {
switch (type) {
case "ul":
return <span className={iconStyle({ type: "ul" })}>β€’</span>;
return (
<span className={iconStyle({ type: "ul" })}>
{indent === 0 && "●"}
{indent === 1 && "β—‹"}
{indent === 2 && "β– "}
</span>
);
case "ol":
return <span className={iconStyle({ type: "ol" })}>{`${index}.`}</span>;
case "checkbox":
Expand Down
27 changes: 27 additions & 0 deletions client/src/features/editor/components/block/Block.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,30 @@ export const textContainerStyle = cva({
type: "p",
},
});

export const dropIndicatorStyle = cva({
base: {
zIndex: "10",
position: "absolute",
height: "2px",
},
variants: {
indent: {
first: {
left: "0",
width: "100%",
backgroundColor: "#ADADFF",
},
second: {
left: "10px",
width: "calc(100% - 10px)",
backgroundColor: "#9B9BFF ",
},
third: {
left: "20px",
width: "calc(100% - 20px)",
backgroundColor: "#8989FF",
},
},
},
});
Loading

0 comments on commit fb07e2b

Please sign in to comment.