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}

+
+ + +
+
+ ); +}