Skip to content

Commit 445658c

Browse files
authored
Merge pull request #8 from Artemia-project/ui-savedMsg
Adjust savedMsg modal
2 parents 4071d12 + ae2d653 commit 445658c

File tree

1 file changed

+177
-31
lines changed

1 file changed

+177
-31
lines changed

src/pages/Index.tsx

Lines changed: 177 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ import {
1414
DialogDescription,
1515
DialogFooter
1616
} from '@/components/ui/dialog';
17-
import { Sparkles, Frame, Eye, Heart, ArrowLeftRight, Trophy } from 'lucide-react';
17+
import { Sparkles, Frame, Eye, Heart, ArrowLeftRight, Trophy, Share2, ChevronDown, ChevronUp } from 'lucide-react';
1818
import { exhibitionsData, type Exhibition } from '@/data/exhibitions';
19+
import { MarkdownRenderer } from '@/components/MarkdownRenderer';
1920
import heroArtwork from '@/assets/hero-artwork.jpg';
2021

2122
interface Artwork {
@@ -41,6 +42,7 @@ const Index = () => {
4142
const [savedMessagesCount, setSavedMessagesCount] = useState(0);
4243
const [savedMessages, setSavedMessages] = useState<Message[]>([]);
4344
const [showSavedModal, setShowSavedModal] = useState(false);
45+
const [expandedMessages, setExpandedMessages] = useState<Set<string>>(new Set());
4446

4547
const exhibitions = exhibitionsData;
4648

@@ -100,6 +102,81 @@ const Index = () => {
100102
setSavedMessages(messages);
101103
};
102104

105+
const handleShareMessage = async (message: Message) => {
106+
const shareText = `Artemia AI 추천:\n\n${message.content}\n\n전시 추천 서비스 - Artemia: Art Curator AI`;
107+
108+
try {
109+
if (navigator.share && navigator.canShare({ text: shareText })) {
110+
await navigator.share({
111+
title: 'Artemia AI 전시 추천',
112+
text: shareText
113+
});
114+
} else {
115+
await navigator.clipboard.writeText(shareText);
116+
// You could add a toast notification here
117+
alert('메시지가 클립보드에 복사되었습니다!');
118+
}
119+
} catch (err) {
120+
console.error('Share failed:', err);
121+
// Fallback to clipboard
122+
try {
123+
await navigator.clipboard.writeText(shareText);
124+
alert('메시지가 클립보드에 복사되었습니다!');
125+
} catch (clipboardErr) {
126+
console.error('Clipboard copy failed:', clipboardErr);
127+
}
128+
}
129+
};
130+
131+
const handleShareAllMessages = async () => {
132+
if (savedMessages.length === 0) return;
133+
134+
const allMessagesText = savedMessages
135+
.map((msg, index) => `${index + 1}. ${msg.content}`)
136+
.join('\n\n');
137+
138+
const shareText = `Artemia AI 저장된 추천들:\n\n${allMessagesText}\n\n전시 추천 서비스 - Artemia: Art Curator AI`;
139+
140+
try {
141+
if (navigator.share && navigator.canShare({ text: shareText })) {
142+
await navigator.share({
143+
title: `Artemia AI 저장된 메시지 ${savedMessages.length}개`,
144+
text: shareText
145+
});
146+
} else {
147+
await navigator.clipboard.writeText(shareText);
148+
alert('모든 메시지가 클립보드에 복사되었습니다!');
149+
}
150+
} catch (err) {
151+
console.error('Share failed:', err);
152+
try {
153+
await navigator.clipboard.writeText(shareText);
154+
alert('모든 메시지가 클립보드에 복사되었습니다!');
155+
} catch (clipboardErr) {
156+
console.error('Clipboard copy failed:', clipboardErr);
157+
}
158+
}
159+
};
160+
161+
const toggleMessageExpansion = (messageId: string) => {
162+
setExpandedMessages(prev => {
163+
const newSet = new Set(prev);
164+
if (newSet.has(messageId)) {
165+
newSet.delete(messageId);
166+
} else {
167+
newSet.add(messageId);
168+
}
169+
return newSet;
170+
});
171+
};
172+
173+
const getMessagePreview = (content: string, maxLength: number = 200) => {
174+
if (content.length <= maxLength) return content;
175+
return content.substring(0, maxLength) + '...';
176+
};
177+
178+
const isLongMessage = (content: string) => content.length > 200;
179+
103180
return (
104181
<div className="h-screen bg-background flex flex-col overflow-hidden">
105182
{/* Hero Section */}
@@ -123,9 +200,6 @@ const Index = () => {
123200
</h1>
124201
</div>
125202

126-
<p className="text-sm sm:text-base lg:text-lg text-primary-foreground/80 mb-3 sm:mb-4 lg:mb-6 leading-relaxed">
127-
전시 추천 주변 관광지 추천 서비스
128-
</p>
129203

130204
<div className="flex flex-wrap justify-center gap-2 sm:gap-3 lg:gap-4">
131205
<Button
@@ -203,40 +277,112 @@ const Index = () => {
203277
/>
204278
)}
205279

206-
{/* Saved Messages Modal */}
280+
{/* Saved Messages Modal - Fullscreen */}
207281
<Dialog open={showSavedModal} onOpenChange={setShowSavedModal}>
208-
<DialogContent className="max-w-lg">
209-
<DialogHeader>
210-
<DialogTitle>Saved Messages</DialogTitle>
211-
<DialogDescription>
212-
These are the messages you've marked as favorite.
282+
<DialogContent className="max-w-none w-full h-full max-h-none p-0 gap-0">
283+
<DialogHeader className="p-4 sm:p-6 border-b text-center">
284+
<DialogTitle className="text-xl sm:text-2xl font-medium text-center">저장된 메시지</DialogTitle>
285+
<DialogDescription className="text-center">
286+
즐겨찾기로 저장한 메시지들을 확인하고 공유할 수 있습니다.
213287
</DialogDescription>
214288
</DialogHeader>
215289

216-
<div className="space-y-3 max-h-[300px] overflow-y-auto">
217-
{savedMessages.length > 0 ? (
218-
savedMessages.map((msg) => (
219-
<div
220-
key={msg.id}
221-
className="p-3 border rounded-lg bg-accent/5 text-sm"
222-
>
223-
{msg.content}
290+
<div className="flex-1 p-4 sm:p-6 overflow-y-auto">
291+
<div className="space-y-4 max-w-4xl mx-auto">
292+
{savedMessages.length > 0 ? (
293+
savedMessages.map((msg) => {
294+
const isExpanded = expandedMessages.has(msg.id);
295+
const isLong = isLongMessage(msg.content);
296+
const contentToShow = isLong && !isExpanded
297+
? getMessagePreview(msg.content)
298+
: msg.content;
299+
300+
return (
301+
<div
302+
key={msg.id}
303+
className={`border rounded-xl bg-gradient-to-r from-card to-accent/5 shadow-sm transition-all duration-300 ${
304+
isLong && !isExpanded
305+
? 'p-3 sm:p-4'
306+
: 'p-4 sm:p-6'
307+
}`}
308+
>
309+
<MarkdownRenderer
310+
content={contentToShow}
311+
className={isLong && !isExpanded ? "text-xs sm:text-sm" : "text-sm sm:text-base"}
312+
/>
313+
314+
{isLong && (
315+
<div className="mt-3">
316+
<Button
317+
variant="ghost"
318+
size="sm"
319+
onClick={() => toggleMessageExpansion(msg.id)}
320+
className="text-xs text-primary hover:text-primary/80 p-0 h-auto"
321+
>
322+
{isExpanded ? (
323+
<>
324+
<ChevronUp className="w-3 h-3 mr-1" />
325+
접기
326+
</>
327+
) : (
328+
<>
329+
<ChevronDown className="w-3 h-3 mr-1" />
330+
더보기
331+
</>
332+
)}
333+
</Button>
334+
</div>
335+
)}
336+
337+
<div className="mt-4 flex items-center justify-between text-xs sm:text-sm text-muted-foreground">
338+
<span>{new Date(msg.timestamp).toLocaleString('ko-KR')}</span>
339+
<Button
340+
variant="ghost"
341+
size="sm"
342+
onClick={() => handleShareMessage(msg)}
343+
className="text-xs"
344+
>
345+
<Share2 className="w-3 h-3 mr-1" />
346+
공유
347+
</Button>
348+
</div>
349+
</div>
350+
);
351+
})
352+
) : (
353+
<div className="text-center py-12">
354+
<Heart className="w-16 h-16 mx-auto text-muted-foreground/20 mb-4" />
355+
<p className="text-muted-foreground text-lg mb-2">
356+
저장된 메시지가 없습니다
357+
</p>
358+
<p className="text-muted-foreground/60 text-sm">
359+
AI 응답에서 ❤️ 버튼을 눌러 메시지를 저장해보세요
360+
</p>
224361
</div>
225-
))
226-
) : (
227-
<p className="text-muted-foreground text-sm">
228-
No saved messages yet.
229-
</p>
230-
)}
362+
)}
363+
</div>
231364
</div>
232365

233-
<DialogFooter>
234-
<Button
235-
variant="secondary"
236-
onClick={() => setShowSavedModal(false)}
237-
>
238-
Close
239-
</Button>
366+
<DialogFooter className="p-4 sm:p-6 border-t">
367+
<div className="flex flex-col sm:flex-row gap-2 sm:gap-4 w-full justify-center">
368+
{savedMessages.length > 0 && (
369+
<Button
370+
variant="outline"
371+
onClick={handleShareAllMessages}
372+
className="flex-1 sm:flex-none"
373+
>
374+
<Share2 className="w-4 h-4 mr-2" />
375+
모든 메시지 공유하기
376+
</Button>
377+
)}
378+
<Button
379+
variant="secondary"
380+
onClick={() => setShowSavedModal(false)}
381+
className="flex-1 sm:flex-none"
382+
>
383+
닫기
384+
</Button>
385+
</div>
240386
</DialogFooter>
241387
</DialogContent>
242388
</Dialog>

0 commit comments

Comments
 (0)