diff --git a/components/board/BoardCanvas.module.css b/components/board/BoardCanvas.module.css
index 37d4491..157042b 100644
--- a/components/board/BoardCanvas.module.css
+++ b/components/board/BoardCanvas.module.css
@@ -397,7 +397,7 @@
transform 0.15s ease,
background-color 0.15s ease;
z-index: 10;
- background: radial-gradient(circle, var(--secondary) 30%, transparent 30%);
+ background: radial-gradient(circle, white 30%, transparent 30%);
}
.connection_handle::before {
@@ -408,7 +408,7 @@
width: 16px;
height: 16px;
transform: translate(-50%, -50%);
- border: 2px solid var(--secondary);
+ border: 2px solid white;
border-radius: 50%;
opacity: 0.6;
}
@@ -419,7 +419,7 @@
.connection_handle:hover {
transform: scale(1.2);
- background: radial-gradient(circle, var(--secondary) 40%, transparent 40%);
+ background: radial-gradient(circle, white 40%, transparent 40%);
}
.connection_handle:hover::before {
@@ -449,6 +449,6 @@
.card_connecting:hover {
box-shadow:
- 0 0 0 3px var(--secondary),
+ 0 0 0 3px white,
0 4px 16px rgba(0, 0, 0, 0.2);
}
diff --git a/components/editor/sidebar/CommentSidebarItem.tsx b/components/editor/sidebar/CommentSidebarItem.tsx
new file mode 100644
index 0000000..a8d3efc
--- /dev/null
+++ b/components/editor/sidebar/CommentSidebarItem.tsx
@@ -0,0 +1,62 @@
+"use client";
+
+import { memo, useCallback, useContext } from "react";
+import { ProjectContext } from "@src/context/ProjectContext";
+import { Comment } from "@src/lib/utils/types";
+import { getCommentPositions } from "@src/lib/screenplay/extensions/comment-highlight-extension";
+import { focusOnPosition } from "@src/lib/screenplay/editor";
+import { join } from "@src/lib/utils/misc";
+import nav_item from "./SidebarItem.module.css";
+
+type CommentSidebarItemProps = {
+ comment: Comment;
+ isActive: boolean;
+ onActivate: () => void;
+};
+
+const CommentSidebarItem = memo(({ comment, isActive, onActivate }: CommentSidebarItemProps) => {
+ const { editor } = useContext(ProjectContext);
+
+ const handleDoubleClick = useCallback(() => {
+ if (!editor) return;
+ const positions = getCommentPositions(editor);
+ const pos = positions.get(comment.id);
+ if (pos) {
+ focusOnPosition(editor, pos.from);
+ }
+ }, [comment.id, editor]);
+
+ const handleClick = useCallback(() => {
+ onActivate();
+ }, [onActivate]);
+
+ // Format date similar to other places, keeping it short
+ const date = new Date(comment.createdAt);
+ const dateStr = date.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' });
+
+ const containerClass = join(
+ nav_item.container,
+ isActive ? nav_item.current : "",
+ );
+
+ return (
+
+
+
{comment.text || "Empty comment"}
+
+ );
+});
+
+CommentSidebarItem.displayName = "CommentSidebarItem";
+
+export default CommentSidebarItem;
diff --git a/components/editor/sidebar/CommentSidebarView.tsx b/components/editor/sidebar/CommentSidebarView.tsx
new file mode 100644
index 0000000..ff6ae06
--- /dev/null
+++ b/components/editor/sidebar/CommentSidebarView.tsx
@@ -0,0 +1,58 @@
+"use client";
+
+import { useContext, useMemo } from "react";
+import { useTranslations } from "next-intl";
+import { ProjectContext } from "@src/context/ProjectContext";
+import { SCREENPLAY_EDITOR_CONFIG } from "@src/lib/editor/document-editor-config";
+import { useDocumentComments } from "@src/lib/editor/use-document-comments";
+import { join } from "@src/lib/utils/misc";
+import { MessageSquare } from "lucide-react";
+import CommentSidebarItem from "./CommentSidebarItem";
+
+import form from "./../../utils/Form.module.css";
+import sidebar_nav from "./EditorSidebarNavigation.module.css";
+
+const CommentSidebarView = () => {
+ const t = useTranslations("editorSidebar");
+ const { repository } = useContext(ProjectContext);
+
+ const projectState = repository?.getState();
+ const commentsMap = useMemo(
+ () =>
+ projectState && SCREENPLAY_EDITOR_CONFIG.features.comments
+ ? SCREENPLAY_EDITOR_CONFIG.getCommentsMap(projectState)
+ : null,
+ [projectState],
+ );
+
+ const { comments, activeCommentId, setActiveCommentId } = useDocumentComments(commentsMap, repository);
+
+ const unresolvedComments = useMemo(() => comments.filter((c) => !c.resolved), [comments]);
+
+ return (
+ <>
+
+
+ {unresolvedComments.length !== 0 ? (
+ unresolvedComments.map((comment) => (
+
setActiveCommentId(comment.id)}
+ />
+ ))
+ ) : (
+
+ {t("commentsEmpty")}
+
+ )}
+
+ >
+ );
+};
+
+export default CommentSidebarView;
diff --git a/components/editor/sidebar/EditorSidebarNavigation.module.css b/components/editor/sidebar/EditorSidebarNavigation.module.css
index f4bc011..6587655 100644
--- a/components/editor/sidebar/EditorSidebarNavigation.module.css
+++ b/components/editor/sidebar/EditorSidebarNavigation.module.css
@@ -54,6 +54,18 @@
overflow-x: hidden;
}
+.empty_state {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 20px;
+ text-align: center;
+ color: var(--secondary-text);
+ font-size: 12px;
+}
+
.scene_list {
flex: 1;
}
diff --git a/components/editor/sidebar/EditorSidebarNavigation.tsx b/components/editor/sidebar/EditorSidebarNavigation.tsx
index ad5b68e..dcca095 100644
--- a/components/editor/sidebar/EditorSidebarNavigation.tsx
+++ b/components/editor/sidebar/EditorSidebarNavigation.tsx
@@ -7,9 +7,10 @@ import { ProjectContext } from "@src/context/ProjectContext";
import { useViewContext } from "@src/context/ViewContext";
import { Scene } from "@src/lib/screenplay/scenes";
import { focusOnPosition } from "@src/lib/screenplay/editor";
-import { Archive, Clapperboard } from "lucide-react";
+import { Archive, Clapperboard, MessageSquare } from "lucide-react";
import SidebarSceneItem from "./SidebarSceneItem";
import ShelfSidebarView from "./ShelfSidebarView";
+import CommentSidebarView from "./CommentSidebarView";
import form from "./../../utils/Form.module.css";
import sidebar_nav from "./EditorSidebarNavigation.module.css";
@@ -19,7 +20,7 @@ const EditorSidebarNavigation = () => {
const { scenes, updateScenes, editor } = useContext(ProjectContext);
const { leftSidebarOpen } = useViewContext();
- const [activeTab, setActiveTab] = useState<"scenes" | "shelf">("scenes");
+ const [activeTab, setActiveTab] = useState<"scenes" | "shelf" | "comments">("scenes");
const [dragIndex, setDragIndex] = useState(null);
// indicatorIndex represents the gap where the item will be inserted.
@@ -193,7 +194,7 @@ const EditorSidebarNavigation = () => {
className={join(sidebar_nav.list, sidebar_nav.scene_list)}
onPointerMove={handlePointerMove}
>
- {scenes.length != 0 &&
+ {scenes.length != 0 ?
scenes.map((scene: Scene, index: number) => {
const isNoOp =
dragIndex === null ||
@@ -214,11 +215,17 @@ const EditorSidebarNavigation = () => {
onDoubleClick={handleDoubleClick}
/>
);
- })}
+ }) : (
+
+ {t("scenesEmpty")}
+
+ )}
>
- ) : (
+ ) : activeTab === "shelf" ? (
+ ) : (
+
)}
+