A local-first note taking app
0

Configure Feed

Select the types of activity you want to include in your feed.

Create initial editor component

Ethan Graf (May 5, 2026, 10:23 PM EDT) 26acc632 a21e009d

+815 -32
+679 -3
package-lock.json
··· 9 9 "version": "1.0.0", 10 10 "license": "MIT", 11 11 "dependencies": { 12 + "@tiptap/extension-placeholder": "^3.22.5", 13 + "@tiptap/markdown": "^3.22.5", 14 + "@tiptap/react": "^3.22.5", 15 + "@tiptap/starter-kit": "^3.22.5", 12 16 "electron-squirrel-startup": "^1.0.1", 13 17 "react": "^19.2.5", 14 18 "react-dom": "^19.2.5", ··· 966 970 "engines": { 967 971 "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 968 972 } 973 + }, 974 + "node_modules/@floating-ui/core": { 975 + "version": "1.7.5", 976 + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", 977 + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", 978 + "license": "MIT", 979 + "optional": true, 980 + "dependencies": { 981 + "@floating-ui/utils": "^0.2.11" 982 + } 983 + }, 984 + "node_modules/@floating-ui/dom": { 985 + "version": "1.7.6", 986 + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", 987 + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", 988 + "license": "MIT", 989 + "optional": true, 990 + "dependencies": { 991 + "@floating-ui/core": "^1.7.5", 992 + "@floating-ui/utils": "^0.2.11" 993 + } 994 + }, 995 + "node_modules/@floating-ui/utils": { 996 + "version": "0.2.11", 997 + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", 998 + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", 999 + "license": "MIT", 1000 + "optional": true 969 1001 }, 970 1002 "node_modules/@gar/promisify": { 971 1003 "version": "1.1.3", ··· 2204 2236 "vite": "^5.2.0 || ^6 || ^7 || ^8" 2205 2237 } 2206 2238 }, 2239 + "node_modules/@tiptap/core": { 2240 + "version": "3.22.5", 2241 + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.22.5.tgz", 2242 + "integrity": "sha512-L1lhWz6ujGny8LduTJ7MBWYhzigwOvfUJUrJ7IzOJSuy3+OAzisdGDD1GV7LEO/hU0Hr2Mkm1wajRIHExvS9HQ==", 2243 + "license": "MIT", 2244 + "funding": { 2245 + "type": "github", 2246 + "url": "https://github.com/sponsors/ueberdosis" 2247 + }, 2248 + "peerDependencies": { 2249 + "@tiptap/pm": "3.22.5" 2250 + } 2251 + }, 2252 + "node_modules/@tiptap/extension-blockquote": { 2253 + "version": "3.22.5", 2254 + "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-3.22.5.tgz", 2255 + "integrity": "sha512-ajyP5W8fG5Hrru47T/eF3xMKOpNvWofgNJqBTeNuGl02sYxsy9a4EunyFxudsaZP9WW3VOD4SaIWr5+MqpbnOQ==", 2256 + "license": "MIT", 2257 + "funding": { 2258 + "type": "github", 2259 + "url": "https://github.com/sponsors/ueberdosis" 2260 + }, 2261 + "peerDependencies": { 2262 + "@tiptap/core": "3.22.5" 2263 + } 2264 + }, 2265 + "node_modules/@tiptap/extension-bold": { 2266 + "version": "3.22.5", 2267 + "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-3.22.5.tgz", 2268 + "integrity": "sha512-l/uDtpJISiFFyfctvnODNWBN/XPZI1jVZRacTRDDnSn8+x6KQ7G2qgFYueU7KvVJGDFVT39Iio56mcFRG/Pozg==", 2269 + "license": "MIT", 2270 + "funding": { 2271 + "type": "github", 2272 + "url": "https://github.com/sponsors/ueberdosis" 2273 + }, 2274 + "peerDependencies": { 2275 + "@tiptap/core": "3.22.5" 2276 + } 2277 + }, 2278 + "node_modules/@tiptap/extension-bubble-menu": { 2279 + "version": "3.22.5", 2280 + "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.22.5.tgz", 2281 + "integrity": "sha512-yrNlFQQJY5MmhBpmD8tnmaSmyUQrEvgyPKa3bzVeWEhDSG1CW4A0ZSMx3hrA9yFO0HWfw3IJmvSCycEZQBalpQ==", 2282 + "license": "MIT", 2283 + "optional": true, 2284 + "dependencies": { 2285 + "@floating-ui/dom": "^1.0.0" 2286 + }, 2287 + "funding": { 2288 + "type": "github", 2289 + "url": "https://github.com/sponsors/ueberdosis" 2290 + }, 2291 + "peerDependencies": { 2292 + "@tiptap/core": "3.22.5", 2293 + "@tiptap/pm": "3.22.5" 2294 + } 2295 + }, 2296 + "node_modules/@tiptap/extension-bullet-list": { 2297 + "version": "3.22.5", 2298 + "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-3.22.5.tgz", 2299 + "integrity": "sha512-cf54fG9AybU8NgPMv1TOcoqAkELeRc/VpnSCt/rIJZphWQx9nsFmrtkrlCatrIcCaGtNZYwlHlMnC5LVVMu0uA==", 2300 + "license": "MIT", 2301 + "funding": { 2302 + "type": "github", 2303 + "url": "https://github.com/sponsors/ueberdosis" 2304 + }, 2305 + "peerDependencies": { 2306 + "@tiptap/extension-list": "3.22.5" 2307 + } 2308 + }, 2309 + "node_modules/@tiptap/extension-code": { 2310 + "version": "3.22.5", 2311 + "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-3.22.5.tgz", 2312 + "integrity": "sha512-mwDNOJC9rYbDu/JcqrN4dbUQRklJU8Fuk2raxD/IvFw9qUIcPCmxQ2XT9UTKmZz/Ju7Kdy72fss6XpgWv6gLAQ==", 2313 + "license": "MIT", 2314 + "funding": { 2315 + "type": "github", 2316 + "url": "https://github.com/sponsors/ueberdosis" 2317 + }, 2318 + "peerDependencies": { 2319 + "@tiptap/core": "3.22.5" 2320 + } 2321 + }, 2322 + "node_modules/@tiptap/extension-code-block": { 2323 + "version": "3.22.5", 2324 + "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-3.22.5.tgz", 2325 + "integrity": "sha512-d123kCfLdJTi4fue1m0+TNFztDkmIRSZGZmGu6H9KqwG5Q7IzjT9o8lzRsz+pXxYqHvqgYmXoEpM6srbzXx/Ag==", 2326 + "license": "MIT", 2327 + "funding": { 2328 + "type": "github", 2329 + "url": "https://github.com/sponsors/ueberdosis" 2330 + }, 2331 + "peerDependencies": { 2332 + "@tiptap/core": "3.22.5", 2333 + "@tiptap/pm": "3.22.5" 2334 + } 2335 + }, 2336 + "node_modules/@tiptap/extension-document": { 2337 + "version": "3.22.5", 2338 + "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.22.5.tgz", 2339 + "integrity": "sha512-8NJERd+pCtvSuEP4C4WMGYmRRCV12ePZL7bC+QUdFlbdXg+kNZS0zZ7hh879tYA0Kidbi8rWWD1Tx+H2ezkmMw==", 2340 + "license": "MIT", 2341 + "funding": { 2342 + "type": "github", 2343 + "url": "https://github.com/sponsors/ueberdosis" 2344 + }, 2345 + "peerDependencies": { 2346 + "@tiptap/core": "3.22.5" 2347 + } 2348 + }, 2349 + "node_modules/@tiptap/extension-dropcursor": { 2350 + "version": "3.22.5", 2351 + "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-3.22.5.tgz", 2352 + "integrity": "sha512-Mp40DaFrY3sEUVtFqmxrR0BmU4G3k8GCYYNGqNa9OqWv7BrcFDC03V2n3okESDKt4MKkzhQQmypq+ouLy8dLfA==", 2353 + "license": "MIT", 2354 + "funding": { 2355 + "type": "github", 2356 + "url": "https://github.com/sponsors/ueberdosis" 2357 + }, 2358 + "peerDependencies": { 2359 + "@tiptap/extensions": "3.22.5" 2360 + } 2361 + }, 2362 + "node_modules/@tiptap/extension-floating-menu": { 2363 + "version": "3.22.5", 2364 + "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-3.22.5.tgz", 2365 + "integrity": "sha512-dhem4sTPhyQgQ+pFp2Oud4k4FSQz9PVMgeQAC9288SmGwxBkJNveDAw6sKTMrumqDvwkJrtslXIupq9TZYQnzg==", 2366 + "license": "MIT", 2367 + "optional": true, 2368 + "funding": { 2369 + "type": "github", 2370 + "url": "https://github.com/sponsors/ueberdosis" 2371 + }, 2372 + "peerDependencies": { 2373 + "@floating-ui/dom": "^1.0.0", 2374 + "@tiptap/core": "3.22.5", 2375 + "@tiptap/pm": "3.22.5" 2376 + } 2377 + }, 2378 + "node_modules/@tiptap/extension-gapcursor": { 2379 + "version": "3.22.5", 2380 + "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-3.22.5.tgz", 2381 + "integrity": "sha512-4WkMu7qqjbsm8hCQS+8X+la1wjriN0SKoRdvpfKH33qM50MB34tYJuGLAO+y7TTh4MMMco3AZCKPBL5JVMqNIg==", 2382 + "license": "MIT", 2383 + "funding": { 2384 + "type": "github", 2385 + "url": "https://github.com/sponsors/ueberdosis" 2386 + }, 2387 + "peerDependencies": { 2388 + "@tiptap/extensions": "3.22.5" 2389 + } 2390 + }, 2391 + "node_modules/@tiptap/extension-hard-break": { 2392 + "version": "3.22.5", 2393 + "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-3.22.5.tgz", 2394 + "integrity": "sha512-n0R2mUVYZU2AVbJhg/WcY9+zx690wVwvsItHJf0DrYbf1tCYHx+PRHUt/AoXk6u8BSmnkb8/FDziS8m3mjfpSg==", 2395 + "license": "MIT", 2396 + "funding": { 2397 + "type": "github", 2398 + "url": "https://github.com/sponsors/ueberdosis" 2399 + }, 2400 + "peerDependencies": { 2401 + "@tiptap/core": "3.22.5" 2402 + } 2403 + }, 2404 + "node_modules/@tiptap/extension-heading": { 2405 + "version": "3.22.5", 2406 + "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-3.22.5.tgz", 2407 + "integrity": "sha512-hjyEG4947PAhMBfP1G6B0QAh6+y9mp2C5BQmNjprA05/lQzDAT7KFZzNh8ZVp3ol6aICKq/N1gFOW9Dc/9FUOw==", 2408 + "license": "MIT", 2409 + "funding": { 2410 + "type": "github", 2411 + "url": "https://github.com/sponsors/ueberdosis" 2412 + }, 2413 + "peerDependencies": { 2414 + "@tiptap/core": "3.22.5" 2415 + } 2416 + }, 2417 + "node_modules/@tiptap/extension-horizontal-rule": { 2418 + "version": "3.22.5", 2419 + "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.22.5.tgz", 2420 + "integrity": "sha512-vUV0/ugIbXOc8SJib0h8UMhgcqZXWu/dkEhlswZN4VVven1o5enkfxEiDw+OyIJHi5rUkrdhsQ/KTxG/Xb7X8A==", 2421 + "license": "MIT", 2422 + "funding": { 2423 + "type": "github", 2424 + "url": "https://github.com/sponsors/ueberdosis" 2425 + }, 2426 + "peerDependencies": { 2427 + "@tiptap/core": "3.22.5", 2428 + "@tiptap/pm": "3.22.5" 2429 + } 2430 + }, 2431 + "node_modules/@tiptap/extension-italic": { 2432 + "version": "3.22.5", 2433 + "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-3.22.5.tgz", 2434 + "integrity": "sha512-4T8baSiLkeIymTgEwirxDFt5YgYofkP3m1+MGYdGy2HKcOK+1vpvlPhEO1X5qtZngtJW5S4+njKjinRg52A4PA==", 2435 + "license": "MIT", 2436 + "funding": { 2437 + "type": "github", 2438 + "url": "https://github.com/sponsors/ueberdosis" 2439 + }, 2440 + "peerDependencies": { 2441 + "@tiptap/core": "3.22.5" 2442 + } 2443 + }, 2444 + "node_modules/@tiptap/extension-link": { 2445 + "version": "3.22.5", 2446 + "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-3.22.5.tgz", 2447 + "integrity": "sha512-d671MvF3GPKoS2OVxjIlQ7hIE7MS3hREdR+d4cvnnoiLLD+ZJ6KgDnxmWqF0a1s4qxLWK2KxKRSOIfYGE31QWQ==", 2448 + "license": "MIT", 2449 + "dependencies": { 2450 + "linkifyjs": "^4.3.2" 2451 + }, 2452 + "funding": { 2453 + "type": "github", 2454 + "url": "https://github.com/sponsors/ueberdosis" 2455 + }, 2456 + "peerDependencies": { 2457 + "@tiptap/core": "3.22.5", 2458 + "@tiptap/pm": "3.22.5" 2459 + } 2460 + }, 2461 + "node_modules/@tiptap/extension-list": { 2462 + "version": "3.22.5", 2463 + "resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.22.5.tgz", 2464 + "integrity": "sha512-cVO3ZHCgxAWZ4zrFSs81FO2nyCk1wb2EHkpLpW98FzbJLkN9rDkazhW99P3HRWy/CvUldOT+8ecI1YrQtBojMg==", 2465 + "license": "MIT", 2466 + "funding": { 2467 + "type": "github", 2468 + "url": "https://github.com/sponsors/ueberdosis" 2469 + }, 2470 + "peerDependencies": { 2471 + "@tiptap/core": "3.22.5", 2472 + "@tiptap/pm": "3.22.5" 2473 + } 2474 + }, 2475 + "node_modules/@tiptap/extension-list-item": { 2476 + "version": "3.22.5", 2477 + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-3.22.5.tgz", 2478 + "integrity": "sha512-W7uTmyKLhlsvuTPLv+8WwnsY+mlikBFIoLSvVcBaFt4MwpsZ+DeB6KQg02Y7tbtaAnG7rXu9Fvw2QORh2P728A==", 2479 + "license": "MIT", 2480 + "funding": { 2481 + "type": "github", 2482 + "url": "https://github.com/sponsors/ueberdosis" 2483 + }, 2484 + "peerDependencies": { 2485 + "@tiptap/extension-list": "3.22.5" 2486 + } 2487 + }, 2488 + "node_modules/@tiptap/extension-list-keymap": { 2489 + "version": "3.22.5", 2490 + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-keymap/-/extension-list-keymap-3.22.5.tgz", 2491 + "integrity": "sha512-cGUnxJ0y515e1bVHNjUmbx7oWHoEon59w6BA5N2KwV9iW2mZZchlTX4yxJSOX+ixeVRChsa7YwC3Z1jUZ6AMEg==", 2492 + "license": "MIT", 2493 + "funding": { 2494 + "type": "github", 2495 + "url": "https://github.com/sponsors/ueberdosis" 2496 + }, 2497 + "peerDependencies": { 2498 + "@tiptap/extension-list": "3.22.5" 2499 + } 2500 + }, 2501 + "node_modules/@tiptap/extension-ordered-list": { 2502 + "version": "3.22.5", 2503 + "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-3.22.5.tgz", 2504 + "integrity": "sha512-OXdh4k4CNrukwiSdWdEQ49uvgnqvR0Z9aNSP4HI5/kZQ/Te1NtRtYCpUrzWyO/7CtjcCisXHti0o9C/TV8YMbQ==", 2505 + "license": "MIT", 2506 + "funding": { 2507 + "type": "github", 2508 + "url": "https://github.com/sponsors/ueberdosis" 2509 + }, 2510 + "peerDependencies": { 2511 + "@tiptap/extension-list": "3.22.5" 2512 + } 2513 + }, 2514 + "node_modules/@tiptap/extension-paragraph": { 2515 + "version": "3.22.5", 2516 + "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-3.22.5.tgz", 2517 + "integrity": "sha512-52KCto4+XKpnBWpIufspWLyq4UWxAWC72ANPdGuIhbi72NRTabiTbTVN40uwGSPkyakeESG0/vKdWJCVvB4f0g==", 2518 + "license": "MIT", 2519 + "funding": { 2520 + "type": "github", 2521 + "url": "https://github.com/sponsors/ueberdosis" 2522 + }, 2523 + "peerDependencies": { 2524 + "@tiptap/core": "3.22.5" 2525 + } 2526 + }, 2527 + "node_modules/@tiptap/extension-placeholder": { 2528 + "version": "3.22.5", 2529 + "resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-3.22.5.tgz", 2530 + "integrity": "sha512-MZAohQ3FCS763BkhGXgaWRya6WruZjwRwEAkXP8vkxbERzl2OJRjniS4uXCWzAlRb3ttE103SnY7LMdM8FvsXw==", 2531 + "license": "MIT", 2532 + "funding": { 2533 + "type": "github", 2534 + "url": "https://github.com/sponsors/ueberdosis" 2535 + }, 2536 + "peerDependencies": { 2537 + "@tiptap/extensions": "3.22.5" 2538 + } 2539 + }, 2540 + "node_modules/@tiptap/extension-strike": { 2541 + "version": "3.22.5", 2542 + "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-3.22.5.tgz", 2543 + "integrity": "sha512-42WrrFK5gOom/0znH85x12Mw5IQ/6O6DWdyUWoRIrNA/qJpuHtU8oVU+bIgU2tuomMGHruRjIzgBQv5sBjEtww==", 2544 + "license": "MIT", 2545 + "funding": { 2546 + "type": "github", 2547 + "url": "https://github.com/sponsors/ueberdosis" 2548 + }, 2549 + "peerDependencies": { 2550 + "@tiptap/core": "3.22.5" 2551 + } 2552 + }, 2553 + "node_modules/@tiptap/extension-text": { 2554 + "version": "3.22.5", 2555 + "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-3.22.5.tgz", 2556 + "integrity": "sha512-bzpDOdAEo1JeoVZDIyV0oY0jGXkEG+AzF70SzHoRSjOvFDtKWunyXf9eO1OnOr2/fmMcckT2qwUBNBMQplWBzw==", 2557 + "license": "MIT", 2558 + "funding": { 2559 + "type": "github", 2560 + "url": "https://github.com/sponsors/ueberdosis" 2561 + }, 2562 + "peerDependencies": { 2563 + "@tiptap/core": "3.22.5" 2564 + } 2565 + }, 2566 + "node_modules/@tiptap/extension-underline": { 2567 + "version": "3.22.5", 2568 + "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.22.5.tgz", 2569 + "integrity": "sha512-9ut09rJD0iEbS6sk7yd2j6IwuFDLTNmDEGTDLodvqAfi+bq7ddsTDv0YviXoZaA9sdHAdTEVr2ITy2m6WK5jpA==", 2570 + "license": "MIT", 2571 + "funding": { 2572 + "type": "github", 2573 + "url": "https://github.com/sponsors/ueberdosis" 2574 + }, 2575 + "peerDependencies": { 2576 + "@tiptap/core": "3.22.5" 2577 + } 2578 + }, 2579 + "node_modules/@tiptap/extensions": { 2580 + "version": "3.22.5", 2581 + "resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.22.5.tgz", 2582 + "integrity": "sha512-Ifg4MzKCj3uRqe3ieTwYnomu2y4p7EXr2avVSKZYfh12i2dyWe2Gkn1KuZDREANVE+gHqFlQjJRYzhJFwzSCrg==", 2583 + "license": "MIT", 2584 + "funding": { 2585 + "type": "github", 2586 + "url": "https://github.com/sponsors/ueberdosis" 2587 + }, 2588 + "peerDependencies": { 2589 + "@tiptap/core": "3.22.5", 2590 + "@tiptap/pm": "3.22.5" 2591 + } 2592 + }, 2593 + "node_modules/@tiptap/markdown": { 2594 + "version": "3.22.5", 2595 + "resolved": "https://registry.npmjs.org/@tiptap/markdown/-/markdown-3.22.5.tgz", 2596 + "integrity": "sha512-lLuAySaY5EYNYLe7e4507B9yQMAEDJdOKy0g85UNFV8giorYLQx56aV2O94Qb9gv3egs5inkwVRNfeJzOWAwig==", 2597 + "license": "MIT", 2598 + "dependencies": { 2599 + "marked": "^17.0.1" 2600 + }, 2601 + "funding": { 2602 + "type": "github", 2603 + "url": "https://github.com/sponsors/ueberdosis" 2604 + }, 2605 + "peerDependencies": { 2606 + "@tiptap/core": "3.22.5", 2607 + "@tiptap/pm": "3.22.5" 2608 + } 2609 + }, 2610 + "node_modules/@tiptap/pm": { 2611 + "version": "3.22.5", 2612 + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.22.5.tgz", 2613 + "integrity": "sha512-Cr9Mv4igxvI2tKMiahw48sZxva3PfDzypErH8IB82N+9qa9n9ygVMt0BOaDg53hLKxEEVeYr2S/wCcJIVFgBTw==", 2614 + "license": "MIT", 2615 + "dependencies": { 2616 + "prosemirror-changeset": "^2.3.0", 2617 + "prosemirror-commands": "^1.6.2", 2618 + "prosemirror-dropcursor": "^1.8.1", 2619 + "prosemirror-gapcursor": "^1.3.2", 2620 + "prosemirror-history": "^1.4.1", 2621 + "prosemirror-keymap": "^1.2.2", 2622 + "prosemirror-model": "^1.24.1", 2623 + "prosemirror-schema-list": "^1.5.0", 2624 + "prosemirror-state": "^1.4.3", 2625 + "prosemirror-tables": "^1.6.4", 2626 + "prosemirror-transform": "^1.10.2", 2627 + "prosemirror-view": "^1.38.1" 2628 + }, 2629 + "funding": { 2630 + "type": "github", 2631 + "url": "https://github.com/sponsors/ueberdosis" 2632 + } 2633 + }, 2634 + "node_modules/@tiptap/react": { 2635 + "version": "3.22.5", 2636 + "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-3.22.5.tgz", 2637 + "integrity": "sha512-36WHEs+vPmB//V1ff7Ujcnpz7Ey5g8lhpI/0+hoanSbdiPMTQ7qZVWwMovIkMKDlqWVp2fxBgeYM1861jyFzTw==", 2638 + "license": "MIT", 2639 + "dependencies": { 2640 + "@types/use-sync-external-store": "^0.0.6", 2641 + "fast-equals": "^5.3.3", 2642 + "use-sync-external-store": "^1.4.0" 2643 + }, 2644 + "funding": { 2645 + "type": "github", 2646 + "url": "https://github.com/sponsors/ueberdosis" 2647 + }, 2648 + "optionalDependencies": { 2649 + "@tiptap/extension-bubble-menu": "^3.22.5", 2650 + "@tiptap/extension-floating-menu": "^3.22.5" 2651 + }, 2652 + "peerDependencies": { 2653 + "@tiptap/core": "3.22.5", 2654 + "@tiptap/pm": "3.22.5", 2655 + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", 2656 + "@types/react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0", 2657 + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", 2658 + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" 2659 + } 2660 + }, 2661 + "node_modules/@tiptap/starter-kit": { 2662 + "version": "3.22.5", 2663 + "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-3.22.5.tgz", 2664 + "integrity": "sha512-LZ/LYbwH6rnDi5DnRyagkuNsYAVyhM+yJvvz+ZuYA0JkPiTXJV86J5PWSKew8M0gVfMHcNVtKjfQCvViFCeIgw==", 2665 + "license": "MIT", 2666 + "dependencies": { 2667 + "@tiptap/core": "^3.22.5", 2668 + "@tiptap/extension-blockquote": "^3.22.5", 2669 + "@tiptap/extension-bold": "^3.22.5", 2670 + "@tiptap/extension-bullet-list": "^3.22.5", 2671 + "@tiptap/extension-code": "^3.22.5", 2672 + "@tiptap/extension-code-block": "^3.22.5", 2673 + "@tiptap/extension-document": "^3.22.5", 2674 + "@tiptap/extension-dropcursor": "^3.22.5", 2675 + "@tiptap/extension-gapcursor": "^3.22.5", 2676 + "@tiptap/extension-hard-break": "^3.22.5", 2677 + "@tiptap/extension-heading": "^3.22.5", 2678 + "@tiptap/extension-horizontal-rule": "^3.22.5", 2679 + "@tiptap/extension-italic": "^3.22.5", 2680 + "@tiptap/extension-link": "^3.22.5", 2681 + "@tiptap/extension-list": "^3.22.5", 2682 + "@tiptap/extension-list-item": "^3.22.5", 2683 + "@tiptap/extension-list-keymap": "^3.22.5", 2684 + "@tiptap/extension-ordered-list": "^3.22.5", 2685 + "@tiptap/extension-paragraph": "^3.22.5", 2686 + "@tiptap/extension-strike": "^3.22.5", 2687 + "@tiptap/extension-text": "^3.22.5", 2688 + "@tiptap/extension-underline": "^3.22.5", 2689 + "@tiptap/extensions": "^3.22.5", 2690 + "@tiptap/pm": "^3.22.5" 2691 + }, 2692 + "funding": { 2693 + "type": "github", 2694 + "url": "https://github.com/sponsors/ueberdosis" 2695 + } 2696 + }, 2207 2697 "node_modules/@tootallnate/once": { 2208 2698 "version": "2.0.1", 2209 2699 "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.1.tgz", ··· 2340 2830 "version": "19.2.14", 2341 2831 "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", 2342 2832 "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", 2343 - "dev": true, 2344 2833 "license": "MIT", 2345 2834 "dependencies": { 2346 2835 "csstype": "^3.2.2" ··· 2350 2839 "version": "19.2.3", 2351 2840 "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", 2352 2841 "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", 2353 - "dev": true, 2354 2842 "license": "MIT", 2355 2843 "peerDependencies": { 2356 2844 "@types/react": "^19.2.0" ··· 2365 2853 "dependencies": { 2366 2854 "@types/node": "*" 2367 2855 } 2856 + }, 2857 + "node_modules/@types/use-sync-external-store": { 2858 + "version": "0.0.6", 2859 + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", 2860 + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", 2861 + "license": "MIT" 2368 2862 }, 2369 2863 "node_modules/@types/wrap-ansi": { 2370 2864 "version": "3.0.0", ··· 4220 4714 "version": "3.2.3", 4221 4715 "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", 4222 4716 "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", 4223 - "dev": true, 4224 4717 "license": "MIT" 4225 4718 }, 4226 4719 "node_modules/data-view-buffer": { ··· 5903 6396 "dev": true, 5904 6397 "license": "MIT" 5905 6398 }, 6399 + "node_modules/fast-equals": { 6400 + "version": "5.4.0", 6401 + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz", 6402 + "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==", 6403 + "license": "MIT", 6404 + "engines": { 6405 + "node": ">=6.0.0" 6406 + } 6407 + }, 5906 6408 "node_modules/fast-glob": { 5907 6409 "version": "3.3.3", 5908 6410 "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", ··· 7756 8258 "url": "https://opencollective.com/parcel" 7757 8259 } 7758 8260 }, 8261 + "node_modules/linkifyjs": { 8262 + "version": "4.3.2", 8263 + "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.3.2.tgz", 8264 + "integrity": "sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==", 8265 + "license": "MIT" 8266 + }, 7759 8267 "node_modules/listr2": { 7760 8268 "version": "7.0.2", 7761 8269 "resolved": "https://registry.npmjs.org/listr2/-/listr2-7.0.2.tgz", ··· 7979 8487 "node": ">=6" 7980 8488 } 7981 8489 }, 8490 + "node_modules/marked": { 8491 + "version": "17.0.6", 8492 + "resolved": "https://registry.npmjs.org/marked/-/marked-17.0.6.tgz", 8493 + "integrity": "sha512-gB0gkNafnonOw0obSTEGZTT86IuhILt2Wfx0mWH/1Au83kybTayroZ/V6nS25mN7u8ASy+5fMhgB3XPNrOZdmA==", 8494 + "license": "MIT", 8495 + "bin": { 8496 + "marked": "bin/marked.js" 8497 + }, 8498 + "engines": { 8499 + "node": ">= 20" 8500 + } 8501 + }, 7982 8502 "node_modules/matcher": { 7983 8503 "version": "3.0.0", 7984 8504 "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", ··· 8658 9178 "node": ">=8" 8659 9179 } 8660 9180 }, 9181 + "node_modules/orderedmap": { 9182 + "version": "2.1.1", 9183 + "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz", 9184 + "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==", 9185 + "license": "MIT" 9186 + }, 8661 9187 "node_modules/os-tmpdir": { 8662 9188 "version": "1.0.2", 8663 9189 "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", ··· 9138 9664 "node": ">=10" 9139 9665 } 9140 9666 }, 9667 + "node_modules/prosemirror-changeset": { 9668 + "version": "2.4.1", 9669 + "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.4.1.tgz", 9670 + "integrity": "sha512-96WBLhOaYhJ+kPhLg3uW359Tz6I/MfcrQfL4EGv4SrcqKEMC1gmoGrXHecPE8eOwTVCJ4IwgfzM8fFad25wNfw==", 9671 + "license": "MIT", 9672 + "dependencies": { 9673 + "prosemirror-transform": "^1.0.0" 9674 + } 9675 + }, 9676 + "node_modules/prosemirror-commands": { 9677 + "version": "1.7.1", 9678 + "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz", 9679 + "integrity": "sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==", 9680 + "license": "MIT", 9681 + "dependencies": { 9682 + "prosemirror-model": "^1.0.0", 9683 + "prosemirror-state": "^1.0.0", 9684 + "prosemirror-transform": "^1.10.2" 9685 + } 9686 + }, 9687 + "node_modules/prosemirror-dropcursor": { 9688 + "version": "1.8.2", 9689 + "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.2.tgz", 9690 + "integrity": "sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==", 9691 + "license": "MIT", 9692 + "dependencies": { 9693 + "prosemirror-state": "^1.0.0", 9694 + "prosemirror-transform": "^1.1.0", 9695 + "prosemirror-view": "^1.1.0" 9696 + } 9697 + }, 9698 + "node_modules/prosemirror-gapcursor": { 9699 + "version": "1.4.1", 9700 + "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.4.1.tgz", 9701 + "integrity": "sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw==", 9702 + "license": "MIT", 9703 + "dependencies": { 9704 + "prosemirror-keymap": "^1.0.0", 9705 + "prosemirror-model": "^1.0.0", 9706 + "prosemirror-state": "^1.0.0", 9707 + "prosemirror-view": "^1.0.0" 9708 + } 9709 + }, 9710 + "node_modules/prosemirror-history": { 9711 + "version": "1.5.0", 9712 + "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.5.0.tgz", 9713 + "integrity": "sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==", 9714 + "license": "MIT", 9715 + "dependencies": { 9716 + "prosemirror-state": "^1.2.2", 9717 + "prosemirror-transform": "^1.0.0", 9718 + "prosemirror-view": "^1.31.0", 9719 + "rope-sequence": "^1.3.0" 9720 + } 9721 + }, 9722 + "node_modules/prosemirror-keymap": { 9723 + "version": "1.2.3", 9724 + "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.3.tgz", 9725 + "integrity": "sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==", 9726 + "license": "MIT", 9727 + "dependencies": { 9728 + "prosemirror-state": "^1.0.0", 9729 + "w3c-keyname": "^2.2.0" 9730 + } 9731 + }, 9732 + "node_modules/prosemirror-model": { 9733 + "version": "1.25.4", 9734 + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.4.tgz", 9735 + "integrity": "sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==", 9736 + "license": "MIT", 9737 + "dependencies": { 9738 + "orderedmap": "^2.0.0" 9739 + } 9740 + }, 9741 + "node_modules/prosemirror-schema-list": { 9742 + "version": "1.5.1", 9743 + "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz", 9744 + "integrity": "sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==", 9745 + "license": "MIT", 9746 + "dependencies": { 9747 + "prosemirror-model": "^1.0.0", 9748 + "prosemirror-state": "^1.0.0", 9749 + "prosemirror-transform": "^1.7.3" 9750 + } 9751 + }, 9752 + "node_modules/prosemirror-state": { 9753 + "version": "1.4.4", 9754 + "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.4.tgz", 9755 + "integrity": "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==", 9756 + "license": "MIT", 9757 + "dependencies": { 9758 + "prosemirror-model": "^1.0.0", 9759 + "prosemirror-transform": "^1.0.0", 9760 + "prosemirror-view": "^1.27.0" 9761 + } 9762 + }, 9763 + "node_modules/prosemirror-tables": { 9764 + "version": "1.8.5", 9765 + "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.8.5.tgz", 9766 + "integrity": "sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==", 9767 + "license": "MIT", 9768 + "dependencies": { 9769 + "prosemirror-keymap": "^1.2.3", 9770 + "prosemirror-model": "^1.25.4", 9771 + "prosemirror-state": "^1.4.4", 9772 + "prosemirror-transform": "^1.10.5", 9773 + "prosemirror-view": "^1.41.4" 9774 + } 9775 + }, 9776 + "node_modules/prosemirror-transform": { 9777 + "version": "1.12.0", 9778 + "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.12.0.tgz", 9779 + "integrity": "sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w==", 9780 + "license": "MIT", 9781 + "dependencies": { 9782 + "prosemirror-model": "^1.21.0" 9783 + } 9784 + }, 9785 + "node_modules/prosemirror-view": { 9786 + "version": "1.41.8", 9787 + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.8.tgz", 9788 + "integrity": "sha512-TnKDdohEatgyZNGCDWIdccOHXhYloJwbwU+phw/a23KBvJIR9lWQWW7WHHK3vBdOLDNuF7TaX98GObUZOWkOnA==", 9789 + "license": "MIT", 9790 + "dependencies": { 9791 + "prosemirror-model": "^1.20.0", 9792 + "prosemirror-state": "^1.0.0", 9793 + "prosemirror-transform": "^1.1.0" 9794 + } 9795 + }, 9141 9796 "node_modules/pump": { 9142 9797 "version": "3.0.4", 9143 9798 "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", ··· 9656 10311 "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.17", 9657 10312 "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17" 9658 10313 } 10314 + }, 10315 + "node_modules/rope-sequence": { 10316 + "version": "1.3.4", 10317 + "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz", 10318 + "integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==", 10319 + "license": "MIT" 9659 10320 }, 9660 10321 "node_modules/run-parallel": { 9661 10322 "version": "1.2.0", ··· 11032 11693 "punycode": "^2.1.0" 11033 11694 } 11034 11695 }, 11696 + "node_modules/use-sync-external-store": { 11697 + "version": "1.6.0", 11698 + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", 11699 + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", 11700 + "license": "MIT", 11701 + "peerDependencies": { 11702 + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" 11703 + } 11704 + }, 11035 11705 "node_modules/username": { 11036 11706 "version": "5.1.0", 11037 11707 "resolved": "https://registry.npmjs.org/username/-/username-5.1.0.tgz", ··· 11154 11824 "funding": { 11155 11825 "url": "https://github.com/sponsors/jonschlinkert" 11156 11826 } 11827 + }, 11828 + "node_modules/w3c-keyname": { 11829 + "version": "2.2.8", 11830 + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", 11831 + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", 11832 + "license": "MIT" 11157 11833 }, 11158 11834 "node_modules/watchpack": { 11159 11835 "version": "2.5.1",
+4
package.json
··· 46 46 "vite": "^8.0.10" 47 47 }, 48 48 "dependencies": { 49 + "@tiptap/extension-placeholder": "^3.22.5", 50 + "@tiptap/markdown": "^3.22.5", 51 + "@tiptap/react": "^3.22.5", 52 + "@tiptap/starter-kit": "^3.22.5", 49 53 "electron-squirrel-startup": "^1.0.1", 50 54 "react": "^19.2.5", 51 55 "react-dom": "^19.2.5",
+25 -23
src/App.tsx
··· 28 28 29 29 return ( 30 30 <MemoryRouter initialEntries={['/']}> 31 - <header className="border-border mb-6 flex flex-wrap items-center justify-between gap-4 border-b pb-4"> 32 - <nav className="flex flex-wrap gap-2"> 33 - <NavLink to="/" end className={navLinkClass}> 34 - Home 35 - </NavLink> 36 - <NavLink to="/about" className={navLinkClass}> 37 - About 38 - </NavLink> 39 - </nav> 40 - <button 41 - type="button" 42 - className="border-border bg-background text-foreground hover:bg-border/30 rounded border px-3 py-1.5 text-sm" 43 - onClick={() => setTheme((t) => (t === 'light' ? 'dark' : 'light'))} 44 - > 45 - Theme: {theme} 46 - </button> 47 - </header> 48 - <main> 49 - <Routes> 50 - <Route path="/" element={<HomePage />} /> 51 - <Route path="/about" element={<AboutPage />} /> 52 - </Routes> 53 - </main> 31 + <div className="flex min-h-svh flex-col"> 32 + <header className="border-border mb-6 flex flex-wrap items-center justify-between gap-4 border-b pb-4"> 33 + <nav className="flex flex-wrap gap-2"> 34 + <NavLink to="/" end className={navLinkClass}> 35 + Home 36 + </NavLink> 37 + <NavLink to="/about" className={navLinkClass}> 38 + About 39 + </NavLink> 40 + </nav> 41 + <button 42 + type="button" 43 + className="border-border bg-background text-foreground hover:bg-border/30 rounded border px-3 py-1.5 text-sm" 44 + onClick={() => setTheme((t) => (t === 'light' ? 'dark' : 'light'))} 45 + > 46 + Theme: {theme} 47 + </button> 48 + </header> 49 + <main className="flex min-h-0 flex-1 flex-col"> 50 + <Routes> 51 + <Route path="/" element={<HomePage />} /> 52 + <Route path="/about" element={<AboutPage />} /> 53 + </Routes> 54 + </main> 55 + </div> 54 56 </MemoryRouter> 55 57 ); 56 58 }
+79
src/components/EditPad.tsx
··· 1 + import { Markdown } from '@tiptap/markdown'; 2 + import Placeholder from '@tiptap/extension-placeholder'; 3 + import { EditorContent, useEditor } from '@tiptap/react'; 4 + import { StarterKit } from '@tiptap/starter-kit'; 5 + import { useEffect, useRef } from 'react'; 6 + 7 + const proseClass = 8 + 'ProseMirror min-h-[12rem] w-full px-3 py-2 text-[15px] leading-relaxed text-foreground outline-none ' + 9 + 'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[color:var(--semantic-accent)] ' + 10 + '[&_blockquote]:border-border [&_blockquote]:mb-3 [&_blockquote]:border-l-2 [&_blockquote]:pl-3 [&_blockquote]:italic ' + 11 + '[&_code]:rounded [&_code]:border [&_code]:border-border/50 [&_code]:bg-border/35 [&_code]:px-1 [&_code]:py-0.5 [&_code]:text-[0.9em] ' + 12 + '[&_h1]:mb-3 [&_h1]:mt-6 [&_h1]:text-2xl [&_h1]:font-semibold [&_h1]:first:mt-0 ' + 13 + '[&_h2]:mb-2 [&_h2]:mt-5 [&_h2]:text-xl [&_h2]:font-semibold [&_h2]:first:mt-0 ' + 14 + '[&_li]:my-1 [&_ol]:mb-3 [&_ol]:list-decimal [&_ol]:pl-6 ' + 15 + '[&_pre]:my-3 [&_pre]:overflow-x-auto [&_pre]:rounded-md [&_pre]:border [&_pre]:border-border [&_pre]:bg-border/25 [&_pre]:p-3 [&_pre]:text-sm ' + 16 + '[&_p]:mb-3 [&_strong]:font-semibold [&_a]:text-accent [&_a]:underline [&_ul]:mb-3 [&_ul]:list-disc [&_ul]:pl-6 ' + 17 + '[&_p.is-empty:first-child]:before:float-left [&_p.is-empty:first-child]:before:text-foreground/40 [&_p.is-empty:first-child]:before:content-[attr(data-placeholder)]'; 18 + 19 + export type EditPadProps = { 20 + value: string; 21 + onChange: (value: string) => void; 22 + className?: string; 23 + /** Shown when the document is empty */ 24 + placeholder?: string; 25 + }; 26 + 27 + /** Markdown via `@tiptap/markdown`; for Yjs later, add `@tiptap/extension-collaboration` with a synced Y.Doc fragment (TipTap collaboration guide). */ 28 + export function EditPad({ 29 + value, 30 + onChange, 31 + className, 32 + placeholder: placeholderText, 33 + }: EditPadProps) { 34 + const onChangeRef = useRef(onChange); 35 + onChangeRef.current = onChange; 36 + 37 + const editor = useEditor( 38 + { 39 + extensions: [ 40 + StarterKit, 41 + Markdown.configure({ 42 + markedOptions: { gfm: true }, 43 + }), 44 + ...(placeholderText 45 + ? [Placeholder.configure({ placeholder: placeholderText })] 46 + : []), 47 + ], 48 + content: value, 49 + contentType: 'markdown', 50 + editorProps: { 51 + attributes: { 52 + class: proseClass, 53 + }, 54 + }, 55 + onUpdate: ({ editor: instance }) => { 56 + onChangeRef.current(instance.getMarkdown()); 57 + }, 58 + }, 59 + [placeholderText], 60 + ); 61 + 62 + useEffect(() => { 63 + if (!editor) return; 64 + const current = editor.getMarkdown(); 65 + if (current === value) return; 66 + editor.commands.setContent(value, { 67 + contentType: 'markdown', 68 + emitUpdate: false, 69 + }); 70 + }, [editor, value]); 71 + 72 + return ( 73 + <div 74 + className={`border-border bg-background flex min-h-[16rem] min-w-0 flex-1 flex-col overflow-auto rounded-md border ${className ?? ''}`} 75 + > 76 + <EditorContent editor={editor} /> 77 + </div> 78 + ); 79 + }
+28 -6
src/pages/HomePage.tsx
··· 1 + import { useState } from 'react'; 2 + import { EditPad } from '../components/EditPad'; 3 + 4 + const INITIAL_NOTE = `# Welcome to Textile 5 + 6 + This is a **local-first** note. The editor uses Markdown and is built for a smooth typing experience. 7 + 8 + - Edit this buffer freely — it stays in memory until you wire up a vault on disk. 9 + - Later you can plug in CRDT sync without throwing away the editor surface. 10 + `; 11 + 1 12 export function HomePage() { 13 + const [note, setNote] = useState(INITIAL_NOTE); 14 + 2 15 return ( 3 - <section className="space-y-2"> 4 - <h1 className="text-foreground text-2xl font-semibold">Home</h1> 5 - <p className="text-foreground/90"> 6 - Renderer is running React inside Electron. 7 - </p> 8 - </section> 16 + <div className="flex min-h-0 flex-1 flex-col gap-3"> 17 + <div> 18 + <h1 className="text-foreground text-2xl font-semibold">Notes</h1> 19 + <p className="text-foreground/80 text-sm"> 20 + Rich Markdown via TipTap (round-trips with <code>.md</code> using{' '} 21 + <code>@tiptap/markdown</code>). The ProseMirror model lines up with 22 + Yjs + <code>@tiptap/extension-collaboration</code> when you add sync. 23 + </p> 24 + </div> 25 + <EditPad 26 + value={note} 27 + onChange={setNote} 28 + placeholder="Start writing…" 29 + /> 30 + </div> 9 31 ); 10 32 }