File size: 4,152 Bytes
05f86a6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7be508e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import React, { useState, useMemo } from 'react';
import { MessageSender } from '../types';
import { FileText, Edit3, Eye, Code, Copy, Check } from 'lucide-react';
import { marked } from 'marked';
import DOMPurify from 'dompurify';

interface NotepadProps {
  content: string;
  lastUpdatedBy?: MessageSender | null;
  isLoading: boolean;
}

const Notepad: React.FC<NotepadProps> = ({ content, lastUpdatedBy, isLoading }) => {
  const [isPreviewMode, setIsPreviewMode] = useState(false);
  const [isCopied, setIsCopied] = useState(false);

  const getSenderColor = (sender?: MessageSender | null) => {
    if (sender === MessageSender.Cognito) return 'text-green-400';
    if (sender === MessageSender.Muse) return 'text-purple-400';
    return 'text-gray-400';
  };

  const processedHtml = useMemo(() => {
    if (isPreviewMode) {
      const rawHtml = marked.parse(content) as string;
      return DOMPurify.sanitize(rawHtml);
    }
    return '';
  }, [content, isPreviewMode]);

  const handleCopyNotepad = async () => {
    try {
      await navigator.clipboard.writeText(content);
      setIsCopied(true);
      setTimeout(() => setIsCopied(false), 2000);
    } catch (err) {
      console.error('无法复制记事本内容: ', err);
      // Optionally, display an error message to the user
    }
  };

  return (
    <div className="h-full flex flex-col bg-slate-800 border-l border-gray-700">

      <header className="p-3 border-b border-gray-700 flex items-center justify-between bg-slate-900">

        <div className="flex items-center">

          <FileText size={20} className="mr-2 text-sky-400" />

          <h2 className="text-lg font-semibold text-sky-400">记事本</h2>

        </div>

        <div className="flex items-center space-x-2">

          {isLoading && <span className="text-xs text-gray-400 italic">AI 思考中...</span>}

          <button

            onClick={handleCopyNotepad}

            className="p-1.5 text-gray-400 hover:text-sky-400 transition-colors duration-150 focus:outline-none focus:ring-1 focus:ring-sky-500 rounded-md"

            title={isCopied ? "已复制!" : "复制记事本内容"}

            aria-label={isCopied ? "已复制记事本内容到剪贴板" : "复制记事本内容"}

          >

            {isCopied ? <Check size={18} className="text-green-400" /> : <Copy size={18} />}

          </button>

          <button

            onClick={() => setIsPreviewMode(!isPreviewMode)}

            className="p-1.5 text-gray-400 hover:text-sky-400 transition-colors duration-150 focus:outline-none focus:ring-1 focus:ring-sky-500 rounded-md"

            title={isPreviewMode ? "查看原始内容" : "预览 Markdown"}

            aria-label={isPreviewMode ? "Switch to raw text view" : "Switch to Markdown preview"}

          >

            {isPreviewMode ? <Code size={18} /> : <Eye size={18} />}

          </button>

        </div>

      </header>

      <div className="flex-grow overflow-y-auto relative">

        {isPreviewMode ? (

          <div

            className="markdown-preview" // Styles defined in index.html

            dangerouslySetInnerHTML={{ __html: processedHtml }}

            aria-label="Markdown 预览"

          />

        ) : (

          <textarea

            readOnly

            value={content}

            className="w-full h-full p-3 bg-slate-800 text-gray-300 resize-none border-none focus:ring-0 font-mono text-sm leading-relaxed"

            aria-label="共享记事本内容 (原始内容)"

          />

        )}

      </div>

      <footer className="p-2 border-t border-gray-700 text-xs text-gray-500 bg-slate-900">

        {lastUpdatedBy ? (

          <div className="flex items-center">

            <Edit3 size={14} className={`mr-1.5 ${getSenderColor(lastUpdatedBy)}`} />

            最后更新者: <span className={`font-medium ml-1 ${getSenderColor(lastUpdatedBy)}`}>{lastUpdatedBy}</span>

          </div>

        ) : (

          <span>记事本内容未被 AI 修改过。</span>

        )}

      </footer>

    </div>
  );
};

export default Notepad;