diff --git a/src/components/App/App.tsx b/src/components/App/App.tsx
index 160197e..0fa1453 100644
--- a/src/components/App/App.tsx
+++ b/src/components/App/App.tsx
@@ -4,15 +4,18 @@
* Main application layout
*/
-import { useEffect } from 'react';
+import { useEffect, useState } from 'react';
import { PedigreeCanvas } from '../PedigreeCanvas/PedigreeCanvas';
import { Toolbar } from '../Toolbar/Toolbar';
import { PropertyPanel } from '../PropertyPanel/PropertyPanel';
import { RelationshipPanel } from '../RelationshipPanel/RelationshipPanel';
import { FilePanel } from '../FilePanel/FilePanel';
+import { WelcomeModal } from '../WelcomeModal/WelcomeModal';
import { usePedigreeStore, useTemporalStore } from '@/store/pedigreeStore';
import styles from './App.module.css';
+const WELCOME_DISMISSED_KEY = 'pedigree-draw-welcome-dismissed';
+
export function App() {
const {
clearSelection,
@@ -23,6 +26,15 @@ export function App() {
} = usePedigreeStore();
const temporal = useTemporalStore();
+ // Welcome modal state - check localStorage on init
+ const [showWelcome, setShowWelcome] = useState(() => {
+ return localStorage.getItem(WELCOME_DISMISSED_KEY) !== 'true';
+ });
+
+ const handleCloseWelcome = () => {
+ setShowWelcome(false);
+ };
+
// Keyboard shortcuts
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
@@ -85,6 +97,8 @@ export function App() {
Pedigree Draw - For genetic counselors and bioinformatics professionals
NSGC Standard Symbols
+
+ {showWelcome && }
);
}
diff --git a/src/components/WelcomeModal/WelcomeModal.module.css b/src/components/WelcomeModal/WelcomeModal.module.css
new file mode 100644
index 0000000..d365272
--- /dev/null
+++ b/src/components/WelcomeModal/WelcomeModal.module.css
@@ -0,0 +1,92 @@
+.overlay {
+ position: fixed;
+ inset: 0;
+ background: rgba(0, 0, 0, 0.6);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 1000;
+ padding: 20px;
+}
+
+.modal {
+ background: white;
+ border-radius: 12px;
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
+ max-width: 520px;
+ width: 100%;
+ padding: 32px;
+ max-height: 90vh;
+ overflow-y: auto;
+}
+
+.title {
+ font-size: 24px;
+ font-weight: 600;
+ color: #1976D2;
+ text-align: center;
+ margin: 0 0 24px 0;
+}
+
+.section {
+ margin-bottom: 24px;
+}
+
+.sectionTitle {
+ font-size: 14px;
+ font-weight: 600;
+ color: #666;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ margin: 0 0 12px 0;
+ padding-bottom: 8px;
+ border-bottom: 1px solid #eee;
+}
+
+.paragraph {
+ font-size: 14px;
+ line-height: 1.6;
+ color: #333;
+ margin: 0 0 12px 0;
+}
+
+.paragraph:last-child {
+ margin-bottom: 0;
+}
+
+.button {
+ display: block;
+ width: 100%;
+ padding: 14px 24px;
+ background: #1976D2;
+ color: white;
+ border: none;
+ border-radius: 8px;
+ font-size: 16px;
+ font-weight: 500;
+ cursor: pointer;
+ transition: background 0.2s ease;
+}
+
+.button:hover {
+ background: #1565C0;
+}
+
+.button:active {
+ background: #0D47A1;
+}
+
+/* Responsive design */
+@media (max-width: 600px) {
+ .modal {
+ padding: 24px;
+ }
+
+ .title {
+ font-size: 20px;
+ }
+
+ .paragraph {
+ font-size: 13px;
+ }
+}
diff --git a/src/components/WelcomeModal/WelcomeModal.tsx b/src/components/WelcomeModal/WelcomeModal.tsx
new file mode 100644
index 0000000..5ad5a92
--- /dev/null
+++ b/src/components/WelcomeModal/WelcomeModal.tsx
@@ -0,0 +1,75 @@
+/**
+ * WelcomeModal Component
+ *
+ * Displays author information and privacy policy on first visit.
+ * Uses localStorage to remember dismissal.
+ * Automatically detects browser language for Chinese/English content.
+ */
+
+import styles from './WelcomeModal.module.css';
+
+interface WelcomeModalProps {
+ onClose: () => void;
+}
+
+const isChineseLocale = (): boolean => {
+ const lang = navigator.language || (navigator.languages?.[0]) || 'en';
+ return lang.toLowerCase().startsWith('zh');
+};
+
+export function WelcomeModal({ onClose }: WelcomeModalProps) {
+ const isChinese = isChineseLocale();
+
+ const content = isChinese ? {
+ title: '歡迎使用 Pedigree Draw',
+ aboutTitle: '關於本專案',
+ aboutContent: [
+ '本專案由一位患有 Usher syndrome 的作者所建立。',
+ '建立此工具的動機是為了支援遺傳學、系譜學和 Bioinformatics 領域的研究,並探索視覺化工具如何幫助理解遺傳性疾病。',
+ '作者明確支持與 Usher syndrome 及其他遺傳疾病相關的研究,並希望此專案能以某種方式為 Bioinformatics 研究社群做出貢獻。',
+ ],
+ privacyTitle: '隱私政策',
+ privacyContent: '本網站不搜集任何使用者資料,也不儲存任何資料。所有操作僅在您的瀏覽器中進行,關閉頁面後資料即消失。',
+ buttonText: '我了解,開始使用',
+ } : {
+ title: 'Welcome to Pedigree Draw',
+ aboutTitle: 'About This Project',
+ aboutContent: [
+ 'This project is created by an author with Usher syndrome.',
+ 'The motivation behind this work is to support research in genetics, genealogy, and bioinformatics, and to explore how visualization tools may assist in understanding hereditary conditions.',
+ 'The author explicitly supports research related to Usher syndrome and other genetic disorders, and hopes this project may contribute, even in a small way, to the bioinformatics research community.',
+ ],
+ privacyTitle: 'Privacy Policy',
+ privacyContent: 'This website does not collect any user data or store any information. All operations are performed locally in your browser. Data will be lost when you close the page.',
+ buttonText: 'I Understand, Let\'s Start',
+ };
+
+ const handleClose = () => {
+ localStorage.setItem('pedigree-draw-welcome-dismissed', 'true');
+ onClose();
+ };
+
+ return (
+
+
e.stopPropagation()}>
+
{content.title}
+
+
+ {content.aboutTitle}
+ {content.aboutContent.map((paragraph, index) => (
+ {paragraph}
+ ))}
+
+
+
+ {content.privacyTitle}
+ {content.privacyContent}
+
+
+
+
+
+ );
+}