index.tsx raw
1 import {
2 Dialog,
3 DialogContent,
4 DialogDescription,
5 DialogHeader,
6 DialogTitle
7 } from '@/components/ui/dialog'
8 import {
9 Sheet,
10 SheetContent,
11 SheetDescription,
12 SheetHeader,
13 SheetTitle
14 } from '@/components/ui/sheet'
15 import { useVisualViewportHeight } from '@/hooks/useVisualViewportHeight'
16 import { usePrimaryPage } from '@/PageManager'
17 import { useScreenSize } from '@/providers/ScreenSizeProvider'
18 import postEditor from '@/services/post-editor.service'
19 import { ArrowLeft, X } from 'lucide-react'
20 import { Event } from 'nostr-tools'
21 import { Dispatch, useMemo, useRef } from 'react'
22 import { useTranslation } from 'react-i18next'
23 import PostContent, { TPostContentHandle } from './PostContent'
24 import Title from './Title'
25
26 export default function PostEditor({
27 defaultContent = '',
28 parentStuff,
29 open,
30 setOpen,
31 highlightedText,
32 inline = false
33 }: {
34 defaultContent?: string
35 parentStuff?: Event | string
36 open: boolean
37 setOpen: Dispatch<boolean>
38 highlightedText?: string
39 inline?: boolean
40 }) {
41 const { t } = useTranslation()
42 const { isSmallScreen } = useScreenSize()
43 const { navigate } = usePrimaryPage()
44 const viewportHeight = useVisualViewportHeight()
45 const contentRef = useRef<TPostContentHandle>(null)
46
47 const handleReset = () => {
48 contentRef.current?.reset()
49 }
50
51 const content = useMemo(() => {
52 return (
53 <PostContent
54 ref={contentRef}
55 defaultContent={defaultContent}
56 parentStuff={parentStuff}
57 close={() => {
58 setOpen(false)
59 navigate('home')
60 }}
61 highlightedText={highlightedText}
62 />
63 )
64 }, [highlightedText, navigate])
65
66 if (inline) {
67 if (!open) return null
68 return (
69 <div className="border-t border-b bg-card animate-in slide-in-from-top-2 fade-in duration-200">
70 <div className="flex items-center h-10 px-3 border-b shrink-0">
71 <div className="flex-1 text-sm font-medium truncate">
72 {highlightedText ? t('Create Highlight') : <Title parentStuff={parentStuff} />}
73 </div>
74 <div className="flex items-center gap-1">
75 <button
76 onClick={handleReset}
77 className="flex items-center justify-center w-8 h-8 rounded hover:bg-accent transition-colors text-sm"
78 aria-label="Reset"
79 >
80 🧹
81 </button>
82 <button
83 onClick={() => setOpen(false)}
84 className="flex items-center justify-center w-8 h-8 rounded hover:bg-accent transition-colors"
85 aria-label="Close"
86 >
87 <X className="w-4 h-4" />
88 </button>
89 </div>
90 </div>
91 <div className="px-4 py-3">{content}</div>
92 </div>
93 )
94 }
95
96 if (isSmallScreen) {
97 return (
98 <Sheet open={open} onOpenChange={setOpen}>
99 <SheetContent
100 className="w-full p-0 border-none flex flex-col"
101 style={{ height: `${viewportHeight}px` }}
102 side="bottom"
103 hideClose
104 onEscapeKeyDown={(e) => {
105 if (postEditor.isSuggestionPopupOpen) {
106 e.preventDefault()
107 postEditor.closeSuggestionPopup()
108 }
109 }}
110 >
111 <div className="flex items-center h-12 border-b shrink-0">
112 <button
113 onClick={() => setOpen(false)}
114 className="flex items-center justify-center w-10 h-full hover:bg-accent transition-colors"
115 aria-label="Close"
116 >
117 <ArrowLeft className="w-5 h-5" />
118 </button>
119 <SheetHeader className="flex-1">
120 <SheetTitle className="text-start text-base font-medium">
121 {highlightedText ? t('Create Highlight') : <Title parentStuff={parentStuff} />}
122 </SheetTitle>
123 <SheetDescription className="hidden" />
124 </SheetHeader>
125 <button
126 onClick={handleReset}
127 className="flex items-center justify-center w-10 h-full hover:bg-accent transition-colors"
128 aria-label="Reset"
129 >
130 🧹
131 </button>
132 </div>
133 <div className="flex flex-col flex-1 min-h-0 px-4 py-4">{content}</div>
134 </SheetContent>
135 </Sheet>
136 )
137 }
138
139 return (
140 <Dialog open={open} onOpenChange={setOpen}>
141 <DialogContent
142 className="p-0 max-w-2xl flex flex-col overflow-hidden"
143 style={{ maxHeight: `${Math.min(viewportHeight * 0.9, viewportHeight)}px` }}
144 withoutClose
145 onEscapeKeyDown={(e) => {
146 if (postEditor.isSuggestionPopupOpen) {
147 e.preventDefault()
148 postEditor.closeSuggestionPopup()
149 }
150 }}
151 >
152 <div className="px-6 pt-6 pb-2 shrink-0">
153 <DialogHeader className="flex flex-row items-center justify-between">
154 <DialogTitle>
155 {highlightedText ? t('Create Highlight') : <Title parentStuff={parentStuff} />}
156 </DialogTitle>
157 <button
158 onClick={handleReset}
159 className="flex items-center justify-center w-8 h-8 rounded hover:bg-accent transition-colors"
160 aria-label="Reset"
161 >
162 🧹
163 </button>
164 <DialogDescription className="hidden" />
165 </DialogHeader>
166 </div>
167 <div className="flex-1 min-h-0 overflow-y-auto px-6 pb-6">
168 {content}
169 </div>
170 </DialogContent>
171 </Dialog>
172 )
173 }
174