• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SNApp-notes / web / 19396077261

15 Nov 2025 09:53PM UTC coverage: 56.102% (-6.5%) from 62.6%
19396077261

push

github

jcubic
fix unit/integration tests

341 of 639 branches covered (53.36%)

Branch coverage included in aggregate %.

629 of 1090 relevant lines covered (57.71%)

197.6 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.73
/src/components/notes/MiddlePanel.tsx
1
/**
2
 * Middle panel component for note editing and content display.
3
 *
4
 * @remarks
5
 * Dependencies: Chakra UI v3, React, Editor component
6
 *
7
 * **Features:**
8
 * - Note title display
9
 * - Real-time save status indicator
10
 * - CodeMirror-based markdown editor
11
 * - Line selection support
12
 * - Empty state for no selected note
13
 * - Editor reference callback for parent control
14
 *
15
 * **Save Status:**
16
 * - idle: No indicator shown
17
 * - saving: Blue "Saving..." text
18
 * - saved: Green "Saved" text
19
 * - error: Red "Save failed" text
20
 *
21
 * **Performance:**
22
 * - Memoized component and computed values
23
 * - useCallback for event handlers
24
 *
25
 * @example
26
 * ```tsx
27
 * <MiddlePanel
28
 *   note={currentNote}
29
 *   content={noteContent}
30
 *   saveStatus="saved"
31
 *   selectedLine={42}
32
 *   onContentChange={handleChange}
33
 *   onEditorReady={(ref) => editorRef.current = ref}
34
 * />
35
 * ```
36
 *
37
 * @public
38
 */
39
'use client';
40

41
import { Box, Text, Flex } from '@chakra-ui/react';
42
import { memo, useMemo, useCallback } from 'react';
43
import type { NoteTreeNode } from '@/types/tree';
44
import type { SaveStatus } from '@/types/notes';
45
import type { EditorRef } from '@/types/editor';
46
import Editor from '@/components/Editor';
47

48
/**
49
 * Props for the MiddlePanel component.
50
 *
51
 * @public
52
 */
53
interface MiddlePanelProps {
54
  /** Currently selected note or null if none selected */
55
  note: NoteTreeNode | null;
56
  /** Current content of the note */
57
  content: string;
58
  /** Current save status of the note */
59
  saveStatus: SaveStatus;
60
  /** Optional line number to highlight in editor */
61
  selectedLine?: number;
62
  /** Callback invoked when content changes */
63
  onContentChange: (content: string) => void;
64
  /** Optional callback invoked when editor is ready */
65
  onEditorReady?: (editorRef: EditorRef) => void;
66
}
67

68
/**
69
 * Renders the middle panel with note editor and status bar.
70
 *
71
 * @param props - Component props
72
 * @param props.note - Currently selected note
73
 * @param props.content - Note content string
74
 * @param props.saveStatus - Current save status
75
 * @param props.selectedLine - Line number to highlight
76
 * @param props.onContentChange - Handler for content changes
77
 * @param props.onEditorReady - Handler for editor initialization
78
 * @returns Memoized middle panel component
79
 *
80
 * @remarks
81
 * Displays empty state when no note is selected.
82
 * Save status bar shows note name and color-coded status.
83
 *
84
 * @public
85
 */
86
const MiddlePanel = memo(function MiddlePanel({
36✔
87
  note,
88
  content,
89
  saveStatus,
90
  selectedLine,
91
  onContentChange,
92
  onEditorReady
93
}: MiddlePanelProps) {
94
  const saveStatusText = useMemo(() => {
930✔
95
    switch (saveStatus) {
106!
96
      case 'saving':
97
        return 'Saving...';
2✔
98
      case 'saved':
99
        return 'Saved';
2✔
100
      case 'error':
101
        return 'Save failed';
×
102
      default:
103
        return '';
102✔
104
    }
105
  }, [saveStatus]);
106

107
  const saveStatusColor = useMemo(() => {
930✔
108
    switch (saveStatus) {
106!
109
      case 'saving':
110
        return 'blue.500';
2✔
111
      case 'saved':
112
        return 'green.500';
2✔
113
      case 'error':
114
        return 'red.500';
×
115
      default:
116
        return 'gray.500';
102✔
117
    }
118
  }, [saveStatus]);
119

120
  const handleContentChange = useCallback(
930✔
121
    (value: string | undefined) => {
122
      onContentChange(value || '');
322!
123
    },
124
    [onContentChange]
125
  );
126

127
  return (
×
128
    <Box as="main" h="100%" display="flex" flexDirection="column">
129
      {/* Save status bar */}
130
      <Flex
131
        justify="space-between"
132
        align="center"
133
        p={4}
134
        borderBottom="1px solid"
135
        borderColor="border"
136
      >
137
        <Text fontSize="lg" fontWeight="semibold">
138
          {note?.name || 'Select a note'}
1,046✔
139
        </Text>
140
        {saveStatus !== 'idle' && (
930!
141
          <Text fontSize="sm" color={saveStatusColor}>
142
            {saveStatusText}
143
          </Text>
144
        )}
145
      </Flex>
146

147
      {/* Editor area */}
148
      <Box flex={1} overflow="hidden" position="relative" minH={0}>
149
        {note ? (
×
150
          <Editor
814✔
151
            value={content}
152
            onChange={handleContentChange}
153
            selectedLine={selectedLine}
154
            onEditorReady={onEditorReady}
155
            placeholder="Start writing your note..."
156
          />
157
        ) : (
158
          <Flex h="100%" align="center" justify="center">
159
            <Text color="fg.muted">Select or create a note to start editing</Text>
160
          </Flex>
161
        )}
162
      </Box>
163
    </Box>
164
  );
165
});
166

167
export default MiddlePanel;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc