a tool for shared writing and social publishing

first pass at mention styling

+37 -22
+31 -20
app/[leaflet_id]/publish/BskyPostEditorProsemirror.tsx
··· 384 384 385 385 if (e.key === "ArrowUp") { 386 386 e.preventDefault(); 387 + e.stopPropagation(); 388 + 387 389 if (suggestionIndex > 0) { 388 390 setSuggestionIndex((i) => i - 1); 389 391 } 390 392 } else if (e.key === "ArrowDown") { 391 393 e.preventDefault(); 394 + e.stopPropagation(); 395 + 392 396 if (suggestionIndex < suggestions.length - 1) { 393 397 setSuggestionIndex((i) => i + 1); 394 398 } ··· 396 400 }; 397 401 398 402 const dom = props.view.current.dom; 399 - dom.addEventListener("keydown", handleKeyDown); 403 + dom.addEventListener("keydown", handleKeyDown, true); 400 404 401 405 return () => { 402 - dom.removeEventListener("keydown", handleKeyDown); 406 + dom.removeEventListener("keydown", handleKeyDown, true); 403 407 }; 404 408 }, [ 405 409 mentionQuery, ··· 412 416 if (!mentionCoords || suggestions.length === 0) return null; 413 417 414 418 // The styles in this component should match the Menu styles in components/Layout.tsx 419 + 420 + let menuItemStyle = `menuItem py-0.5! text-secondary flex-col! gap-0! leading-tight text-sm truncate`; 421 + let menuItemSubtextStyle = `text-tertiary italic text-xs font-normal min-w-0 truncate`; 422 + 423 + let menuItemSelectedStyle = `bg-[var(--accent-light)]`; 424 + 415 425 return ( 416 426 <Popover.Root open> 417 427 {createPortal( ··· 431 441 sideOffset={4} 432 442 collisionPadding={20} 433 443 onOpenAutoFocus={(e) => e.preventDefault()} 434 - className={`dropdownMenu z-20 bg-bg-page flex flex-col py-1 gap-0.5 border border-border rounded-md shadow-md`} 444 + className={`dropdownMenu z-20 bg-bg-page flex flex-col p-1 gap-1 border border-border rounded-md shadow-md sm:max-w-xs w-[1000px]`} 435 445 > 436 446 <ul className="list-none p-0 text-sm"> 437 447 {suggestions.map((result, index) => { ··· 439 449 return ( 440 450 <div 441 451 className={` 442 - MenuItem 443 - font-bold z-10 py-1 px-3 444 - text-left text-secondary 445 - flex gap-2 446 - ${index === suggestionIndex ? "bg-border-light data-[highlighted]:text-secondary" : ""} 447 - hover:bg-border-light hover:text-secondary 448 - outline-none 452 + ${menuItemStyle} 453 + ${index === suggestionIndex ? menuItemSelectedStyle : ""} 454 + 449 455 `} 450 456 key={result.did} 451 457 onClick={() => { ··· 458 464 }} 459 465 onMouseDown={(e) => e.preventDefault()} 460 466 > 461 - @{result.handle} 467 + {result.displayName 468 + ? result.displayName 469 + : `@${result.handle}`} 470 + {result.displayName && ( 471 + <div className={menuItemSubtextStyle}> 472 + @{result.handle} 473 + </div> 474 + )} 462 475 </div> 463 476 ); 464 477 if (result.type == "publication") { 465 478 return ( 466 479 <div 467 480 className={` 468 - text-test 469 - MenuItem 470 - font-bold z-10 py-1 px-3 471 - text-left 472 - flex gap-2 473 - ${index === suggestionIndex ? "bg-border-light data-[highlighted]:text-secondary" : ""} 474 - hover:bg-border-light hover:text-secondary 475 - outline-none 481 + ${menuItemStyle} 482 + ${index === suggestionIndex ? menuItemSelectedStyle : ""} 476 483 `} 477 484 key={result.uri} 478 485 onClick={() => { ··· 486 493 onMouseDown={(e) => e.preventDefault()} 487 494 > 488 495 {result.name} 496 + <div className={menuItemSubtextStyle}> 497 + Leaflet Publication 498 + </div> 489 499 </div> 490 500 ); 491 501 } ··· 498 508 } 499 509 500 510 export type Mention = 501 - | { type: "did"; handle: string; did: string } 511 + | { type: "did"; handle: string; did: string; displayName?: string } 502 512 | { type: "publication"; uri: string; name: string }; 503 513 function useMentionSuggestions(query: string | null) { 504 514 const [suggestionIndex, setSuggestionIndex] = useState(0); ··· 524 534 type: "did" as const, 525 535 handle: actor.handle, 526 536 did: actor.did, 537 + displayName: actor.displayName, 527 538 })), 528 539 ...publications.result.publications.map((p) => ({ 529 540 type: "publication" as const,
+2
app/globals.css
··· 413 413 outline: none !important; 414 414 cursor: pointer; 415 415 background-color: transparent; 416 + display: flex; 417 + gap: 0.5rem; 416 418 417 419 :hover { 418 420 text-decoration: none !important;
+4 -2
components/Blocks/BlockCommandBar.tsx
··· 37 37 const clearCommandSearchText = () => { 38 38 if (!props.entityID) return; 39 39 const entityID = props.entityID; 40 - 40 + 41 41 const existingState = useEditorStates.getState().editorStates[entityID]; 42 42 if (!existingState) return; 43 43 ··· 64 64 setHighlighted(commandResults[0].name); 65 65 } 66 66 }, [commandResults, setHighlighted, highlighted]); 67 + 67 68 useEffect(() => { 68 69 let listener = async (e: KeyboardEvent) => { 69 70 let reverseDir = ref.current?.dataset.side === "top"; ··· 113 114 return; 114 115 } 115 116 }; 117 + 116 118 window.addEventListener("keydown", listener); 117 119 118 120 return () => window.removeEventListener("keydown", listener); ··· 195 197 196 198 return ( 197 199 <button 198 - className={`commandResult text-left flex gap-2 mx-1 pr-2 py-0.5 rounded-md text-secondary ${isHighlighted && "bg-border-light"}`} 200 + className={`commandResult menuItem text-secondary font-normal! py-0.5! mx-1 pl-0! ${isHighlighted && "bg-[var(--accent-light)]"}`} 199 201 onMouseOver={() => { 200 202 props.setHighlighted(props.name); 201 203 }}
components/Mention.tsx

This is a binary file and will not be displayed.