Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified apps/desktop/bun.lockb
Binary file not shown.
5 changes: 3 additions & 2 deletions apps/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@
"@tauri-apps/api": "^2",
"@tauri-apps/plugin-fs": "^2.0.3",
"@tauri-apps/plugin-shell": "^2",
"@tauri-apps/plugin-stronghold": "^2.0.0",
"@tauri-apps/plugin-updater": "^2.0.0",
"@tiptap/extension-highlight": "^2.10.3",
"@tiptap/extension-typography": "^2.10.3",
"@tiptap/pm": "^2.10.3",
"@tiptap/react": "^2.10.3",
"@tiptap/starter-kit": "^2.10.3",
"cmdk": "^1.0.4",
"date-fns": "^4.1.0",
"lucide-react": "^0.468.0",
"@tauri-apps/plugin-stronghold": "^2.0.0",
"@tauri-apps/plugin-updater": "^2.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-resizable-panels": "^2.1.7",
Expand Down
50 changes: 40 additions & 10 deletions apps/desktop/src/components/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ export default function NavBar() {
const [isSearchOpen, setIsSearchOpen] = useState(false);
const [isProfileMenuOpen, setIsProfileMenuOpen] = useState(false);
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
const [isExportMenuOpen, setIsExportMenuOpen] = useState(false);
const searchRef = useRef<HTMLDivElement>(null);
const profileRef = useRef<HTMLDivElement>(null);
const exportRef = useRef<HTMLDivElement>(null);
const navigate = useNavigate();
const location = useLocation();

Expand All @@ -26,6 +28,10 @@ export default function NavBar() {
setIsProfileMenuOpen(false);
});

useClickOutside(exportRef, () => {
setIsExportMenuOpen(false);
});

const handleNewNote = () => {
const noteId = crypto.randomUUID();
navigate(`/note/${noteId}`);
Expand Down Expand Up @@ -87,7 +93,7 @@ export default function NavBar() {
{isProfileMenuOpen && (
<div className="absolute left-0 mt-2 w-64 rounded-lg border bg-white shadow-lg">
<div className="space-y-1 border-b p-4">
<div className="font-medium">홍길동</div>
<div className="font-medium">John Snow</div>
<div className="text-sm text-gray-500">
hong@example.com
</div>
Expand Down Expand Up @@ -163,16 +169,40 @@ export default function NavBar() {
</button>
</div>

{/* Share Link Button - Only show on note page */}
{/* Share Link Button - Changed to Export dropdown */}
{isNotePage && (
<button
onClick={() => {
/* 공유 링크 생성 로직 */
}}
className="rounded-md border px-2.5 py-2 text-xs text-gray-700 hover:bg-gray-100"
>
링크 공유
</button>
<div className="relative" ref={exportRef}>
<button
onClick={() => setIsExportMenuOpen(!isExportMenuOpen)}
className="rounded-md border px-2.5 py-2 text-xs text-gray-700 hover:bg-gray-100"
>
Export
</button>
{isExportMenuOpen && (
<div className="absolute right-0 mt-2 w-48 rounded-lg border bg-white shadow-lg">
<div className="py-1">
<button
onClick={() => {
/* MD 다운로드 로직 */
setIsExportMenuOpen(false);
}}
className="w-full px-4 py-2 text-left text-sm text-gray-700 hover:bg-gray-100"
>
Markdown으로 내보내기
</button>
<button
onClick={() => {
/* PDF 다운로드 로직 */
setIsExportMenuOpen(false);
}}
className="w-full px-4 py-2 text-left text-sm text-gray-700 hover:bg-gray-100"
>
PDF로 내보내기
</button>
</div>
</div>
)}
</div>
)}

{/* New Note Button */}
Expand Down
49 changes: 0 additions & 49 deletions apps/desktop/src/components/note/LiveCaptionDock.tsx

This file was deleted.

48 changes: 30 additions & 18 deletions apps/desktop/src/components/note/NoteEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,27 +46,39 @@ export default function NoteEditor({ content, onChange }: NoteEditorProps) {
}, [content, editor]);

return (
<div
className="h-full w-full p-4 px-6"
onClick={(e) => {
if (!editor) return;
<div className="relative flex flex-1 flex-col overflow-hidden">
<div className="absolute inset-4 inset-x-6 overflow-y-scroll">
<EditorContent
editor={editor}
className="h-full w-full"
onClick={(e) => {
if (!editor) return;

// 클릭한 위치의 Y 좌표
const clickY = e.clientY;
// 에디터의 마지막 위치의 Y 좌표
const editorRect = editor.view.dom.getBoundingClientRect();
const lastLineY = editorRect.bottom;
// 클릭한 위치의 Y 좌표
const clickY = e.clientY;
// 에디터의 마지막 위치의 Y 좌표
const editorRect = editor.view.dom.getBoundingClientRect();
const lastLineY = editorRect.bottom;

// 클릭 위치가 마지막 줄보다 아래인 경우 새로운 줄 추가
if (clickY > lastLineY) {
editor.commands.setTextSelection(editor.state.doc.content.size);
editor.commands.enter();
}
// 클릭 위치가 마지막 줄보다 아래인 경우
if (clickY > lastLineY) {
// 마지막 위치로 커서 이동
editor.commands.setTextSelection(editor.state.doc.content.size);

editor.commands.focus();
}}
>
<EditorContent editor={editor} />
// 마지막 노드가 빈 텍스트 블록이 아닌 경우에만 새 줄 추가
const lastNode = editor.state.doc.lastChild;
if (
lastNode &&
(!lastNode.isTextblock || lastNode.content.size > 0)
) {
editor.commands.enter();
}
}

editor.commands.focus();
}}
/>
</div>
</div>
);
}
39 changes: 17 additions & 22 deletions apps/desktop/src/components/note/NoteHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Note, CalendarEvent } from "../../types";
import type { Note } from "../../types";
import { formatMeetingTime } from "../../utils/time";
import NoteControl from "./NoteControl";

interface NoteHeaderProps {
Expand Down Expand Up @@ -28,24 +29,8 @@ export default function NoteHeader({
onStartRecording,
onPauseResume,
}: NoteHeaderProps) {
const formatMeetingTime = (start: CalendarEvent["start"]) => {
const now = new Date();
const startTime = start.dateTime
? new Date(start.dateTime)
: start.date
? new Date(start.date)
: null;

if (!startTime) return "";

const diff = Math.floor((now.getTime() - startTime.getTime()) / 1000);
const mins = Math.floor(diff / 60);
const secs = diff % 60;
return `${mins}:${secs.toString().padStart(2, "0")}`;
};

return (
<div className="sticky top-0 z-10 border-b bg-white p-4 px-6">
<div className="border-b bg-white p-4 px-6">
<div className="flex items-center justify-between">
<div className="flex-1">
<input
Expand All @@ -55,8 +40,8 @@ export default function NoteHeader({
placeholder={isNew ? "제목 없음" : ""}
className="w-full text-lg font-medium focus:outline-none"
/>
{note?.calendarEvent && (
<div className="mt-1 flex items-center text-sm">
<div className="mt-1 flex flex-wrap items-center gap-2 text-sm">
{note?.calendarEvent && (
<div className="inline-flex items-center rounded-full bg-blue-50 px-2.5 py-0.5 text-blue-600">
<span>{note.calendarEvent.summary}</span>
<div className="mx-2 h-4 w-px bg-blue-300" />
Expand All @@ -65,8 +50,18 @@ export default function NoteHeader({
{formatMeetingTime(note.calendarEvent.end)}
</span>
</div>
</div>
)}
)}
{note?.tags &&
note.tags.length > 0 &&
note.tags.map((tag) => (
<span
key={tag}
className="rounded-full bg-gray-100 px-2.5 py-0.5 text-gray-600"
>
{tag}
</span>
))}
</div>
</div>

<NoteControl
Expand Down
15 changes: 9 additions & 6 deletions apps/desktop/src/mocks/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ export const mockNotes: Note[] = [
displayName: "User Name",
},
start: {
dateTime: "2024-03-20T10:00:00Z",
dateTime: "2024-03-20T14:30:00Z",
},
end: {
dateTime: "2024-03-20T11:00:00Z",
dateTime: "2024-03-20T15:30:00Z",
},
},
voiceRecording: "recording1.mp3",
tags: ["회의", "제품", "개발"],
createdAt: "2024-03-20T09:00:00Z",
updatedAt: "2024-03-20T09:32:15Z",
},
Expand All @@ -53,13 +54,14 @@ export const mockNotes: Note[] = [
displayName: "User Name",
},
start: {
dateTime: "2024-03-19T10:00:00Z",
dateTime: "2024-03-19T14:00:00Z",
},
end: {
dateTime: "2024-03-19T10:30:00Z",
dateTime: "2024-03-19T14:30:00Z",
},
},
voiceRecording: "recording2.mp3",
tags: ["회의", "스크럼", "개발"],
createdAt: "2024-03-19T09:00:00Z",
updatedAt: "2024-03-19T09:15:45Z",
},
Expand All @@ -84,13 +86,14 @@ export const mockNotes: Note[] = [
displayName: "User Name",
},
start: {
dateTime: "2024-03-18T10:00:00Z",
dateTime: "2024-03-18T15:00:00Z",
},
end: {
dateTime: "2024-03-18T11:00:00Z",
dateTime: "2024-03-18T16:00:00Z",
},
},
voiceRecording: "recording3.mp3",
tags: ["인터뷰", "사용자", "피드백"],
createdAt: "2024-03-18T09:00:00Z",
updatedAt: "2024-03-18T09:45:30Z",
},
Expand Down
14 changes: 5 additions & 9 deletions apps/desktop/src/pages/NotePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { useSpeechRecognition } from "../hooks/useSpeechRecognition";
import SidePanel from "../components/note/SidePanel";
import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels";
import { useUI } from "../contexts/UIContext";
import LiveCaptionDock from "../components/note/LiveCaptionDock";
import NoteHeader from "../components/note/NoteHeader";
import NoteEditor from "../components/note/NoteEditor";
import { useNoteState } from "../hooks/useNoteState";
Expand Down Expand Up @@ -70,7 +69,7 @@ export default function NotePage() {
<main className="flex-1">
<PanelGroup direction="horizontal">
<Panel defaultSize={100} minSize={50}>
<div className="flex h-full flex-col overflow-auto">
<div className="flex h-full flex-col overflow-hidden">
<NoteHeader
note={state.note}
isNew={state.isNew}
Expand All @@ -85,13 +84,10 @@ export default function NotePage() {
onPauseResume={handlePauseResumeClick}
/>

<div className="relative flex flex-1 flex-col">
<NoteEditor
content={state.content}
onChange={(content) => updateState({ content })}
/>
<LiveCaptionDock currentTranscript={currentTranscript} />
</div>
<NoteEditor
content={state.content}
onChange={(content) => updateState({ content })}
/>
</div>
</Panel>

Expand Down
Loading
Loading