Skip to content

Commit ddff742

Browse files
committed
Add support for task items in the Note Editor
1 parent 4151911 commit ddff742

File tree

6 files changed

+181
-6
lines changed

6 files changed

+181
-6
lines changed

CHANGES.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,10 @@
7878

7979
## 0.1.4
8080

81-
- Persist states through PouchDB - ensuring your data stays connected and is never lost
81+
- Persist states through PouchDB - ensuring your data stays connected and is never lost
82+
83+
## 0.1.5
84+
85+
- Add a confirmation dialog for deleting chat messages
86+
- Add an animation for when a user copies a message
87+
- Add support for task items in the Note Editor

package-lock.json

Lines changed: 32 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "notebit",
33
"description": "Notebit is a cross-platform desktop note-taking application built with Electron, React, and TypeScript.",
4-
"version": "0.1.4",
4+
"version": "0.1.5",
55
"author": {
66
"email": "mikeymooney1991@gmail.com",
77
"name": "Michael Mooney"
@@ -33,7 +33,7 @@
3333
"@legendapp/state": "^2.1.14",
3434
"@radix-ui/react-accordion": "^1.2.8",
3535
"@radix-ui/react-alert-dialog": "^1.1.11",
36-
"@radix-ui/react-checkbox": "^1.2.3",
36+
"@radix-ui/react-checkbox": "^1.3.2",
3737
"@radix-ui/react-collapsible": "^1.1.8",
3838
"@radix-ui/react-context-menu": "^2.2.12",
3939
"@radix-ui/react-dialog": "^1.1.13",
@@ -52,6 +52,8 @@
5252
"@tanstack/react-query": "^4.36.1",
5353
"@tanstack/react-router": "^1.48.4",
5454
"@tiptap/extension-link": "^2.11.9",
55+
"@tiptap/extension-task-item": "^2.12.0",
56+
"@tiptap/extension-task-list": "^2.12.0",
5557
"@tiptap/pm": "^2.11.7",
5658
"@tiptap/react": "^2.11.7",
5759
"@tiptap/starter-kit": "^2.11.7",

src/web/components/ui/checkbox.tsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import * as React from "react"
2+
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
3+
import { CheckIcon } from "lucide-react"
4+
5+
import { cn } from "@/shared/utils/index.ts"
6+
7+
function Checkbox({
8+
className,
9+
...props
10+
}: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
11+
return (
12+
<CheckboxPrimitive.Root
13+
data-slot="checkbox"
14+
className={cn(
15+
"peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
16+
className
17+
)}
18+
{...props}
19+
>
20+
<CheckboxPrimitive.Indicator
21+
data-slot="checkbox-indicator"
22+
className="flex items-center justify-center text-current transition-none"
23+
>
24+
<CheckIcon className="size-3.5" />
25+
</CheckboxPrimitive.Indicator>
26+
</CheckboxPrimitive.Root>
27+
)
28+
}
29+
30+
export { Checkbox }

src/web/features/notes/hooks/useNoteEditor.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { useEditor } from '@tiptap/react';
33
import StarterKit from '@tiptap/starter-kit';
44
import { Markdown } from 'tiptap-markdown';
55
import Link from '@tiptap/extension-link';
6+
import TaskList from '@tiptap/extension-task-list';
7+
import TaskItem from '@tiptap/extension-task-item';
68

79
// State
810
import { setNoteContent } from '@/features/notes/state/notesState';
@@ -34,6 +36,8 @@ export function useNoteEditor(initialContent: string) {
3436
tightListClass: 'tight',
3537
bulletListMarker: '-',
3638
linkify: true,
39+
transformPastedText: true,
40+
transformCopiedText: true,
3741
}),
3842
Link.configure({
3943
openOnClick: false, // Disable default handling so we can use our own
@@ -50,6 +54,17 @@ export function useNoteEditor(initialContent: string) {
5054
{ left: '$', right: '$', display: false },
5155
],
5256
}),
57+
TaskList.configure({
58+
HTMLAttributes: {
59+
class: 'task-list',
60+
},
61+
}),
62+
TaskItem.configure({
63+
nested: true,
64+
HTMLAttributes: {
65+
class: 'task-item',
66+
},
67+
}),
5368
],
5469
content: initialContent,
5570
editorProps: {

src/web/features/notes/styles/tiptap.css

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,96 @@
175175
z-index: 1;
176176
cursor: text;
177177
}
178+
179+
/* Task List Styles */
180+
ul[data-type='taskList'] {
181+
list-style: none;
182+
padding: 0;
183+
margin-top: 0.5em;
184+
margin-bottom: 0.5em;
185+
}
186+
187+
ul[data-type='taskList'] li {
188+
display: flex;
189+
align-items: flex-start;
190+
margin-bottom: 0.2em;
191+
}
192+
193+
ul[data-type='taskList'] li > label {
194+
flex: 0 0 auto;
195+
margin-right: 0.5em;
196+
user-select: none;
197+
position: relative;
198+
}
199+
200+
ul[data-type='taskList'] li > div {
201+
flex: 1 1 auto;
202+
}
203+
204+
ul[data-type='taskList'] li > div > p {
205+
margin-top: 0;
206+
margin-bottom: 0;
207+
}
208+
209+
/* Custom shadcn-style checkbox */
210+
ul[data-type='taskList'] input[type='checkbox'] {
211+
-webkit-appearance: none;
212+
appearance: none;
213+
width: 16px;
214+
height: 16px;
215+
border-radius: 4px;
216+
margin: 0.2em 0.5em 0 0;
217+
border: 1px solid hsl(var(--input));
218+
background-color: transparent;
219+
cursor: pointer;
220+
position: relative;
221+
display: flex;
222+
align-items: center;
223+
justify-content: center;
224+
transition:
225+
border-color 0.2s,
226+
background-color 0.2s;
227+
}
228+
229+
/* Dark mode styles */
230+
.dark ul[data-type='taskList'] input[type='checkbox'] {
231+
background-color: hsl(var(--input) / 0.3);
232+
margin-top: 0.2em;
233+
}
234+
235+
/* Checked state */
236+
ul[data-type='taskList'] input[type='checkbox']:checked {
237+
background-color: hsl(var(--primary));
238+
border-color: hsl(var(--primary));
239+
}
240+
241+
/* Focus state */
242+
ul[data-type='taskList'] input[type='checkbox']:focus-visible {
243+
outline: none;
244+
border-color: hsl(var(--ring));
245+
box-shadow: 0 0 0 3px hsl(var(--ring) / 0.5);
246+
}
247+
248+
/* Checkmark - improved version */
249+
ul[data-type='taskList'] input[type='checkbox']:checked::before {
250+
content: '';
251+
position: absolute;
252+
top: 2px;
253+
left: 5px;
254+
width: 4px;
255+
height: 8px;
256+
border: solid white;
257+
border-width: 0 2px 2px 0;
258+
transform: rotate(45deg);
259+
}
260+
261+
/* Nested task lists */
262+
ul[data-type='taskList'] ul[data-type='taskList'] {
263+
padding-left: 1.5em;
264+
}
265+
266+
/* When a task is checked, style the text */
267+
ul[data-type='taskList'] li[data-checked='true'] > div > p {
268+
color: hsl(var(--muted-foreground));
269+
text-decoration: line-through;
270+
}

0 commit comments

Comments
 (0)