diff --git a/src/components/EnhancedPromotionModal/index.tsx b/src/components/EnhancedPromotionModal/index.tsx new file mode 100644 index 00000000..4d801c4b --- /dev/null +++ b/src/components/EnhancedPromotionModal/index.tsx @@ -0,0 +1,166 @@ +import noop from '../../utils/noop' +import { hasSeenEnhancedPromotionAtom } from '@/store' +import { Dialog, Transition } from '@headlessui/react' +import { track } from '@vercel/analytics' +import { useAtom } from 'jotai' +import type React from 'react' +import { Fragment, useEffect, useState } from 'react' +import IconStar from '~icons/heroicons/star-solid' +import IconX from '~icons/tabler/x' + +const EnhancedPromotionModal: React.FC = () => { + const [hasSeenPromotion, setHasSeenPromotion] = useAtom(hasSeenEnhancedPromotionAtom) + const [isOpen, setIsOpen] = useState(false) + + useEffect(() => { + // Only show modal if user hasn't seen it before + if (!hasSeenPromotion) { + const timer = setTimeout(() => { + setIsOpen(true) + }, 2000) // Show after 2 seconds to let the page load + + return () => clearTimeout(timer) + } + }, [hasSeenPromotion]) + + const handleTryNow = () => { + track('promotion_event', { + from: 'enhanced_promotion_modal', + action: 'open', + }) + setHasSeenPromotion(true) + // setIsOpen(false) + // Open in new tab + window.open('https://qwertylearner.ai', '_blank') + } + + const handleDismiss = () => { + track('promotion_event', { + from: 'enhanced_promotion_modal', + action: 'close', + }) + setHasSeenPromotion(true) + setIsOpen(false) + } + + return ( + + + +
+ + +
+
+ + + {/* Header with close button */} +
+ +
+ + {/* Content */} +
+ {/* Icon and title */} +
+
+ +
+

+ 体验 QwertyLearner.ai +

+ +

解锁更强大的学习体验 ✨

+
+ + {/* Main content */} +
+

+ 不会编程?想拥有自己的专属学习词典?操作简单,一键上传,点击即用 +
+

+ 那么,推荐您尝试由英国 DeepLearningAI 专业团队开发运营的 QwertyLearner.ai +

+ +
+

🚀 专业功能

+
    +
  • + + + AI 智能词库 - 一键上传,智能生成释义和词性,打造专属自定义词库 + +
  • +
  • + + + 文章练习 - 自定义文章内容,提升实战能力 + +
  • +
  • + + + 云端同步 - 多设备练习记录、错题库同步 + +
  • +
  • + + + 词典选择 - 更多丰富的专业词库 + +
  • +
+
+ +
+

+ 说明:QwertyLearner.ai 由英国 DeepLearningAI 独立开发运营,为开源版 QwertyLearner + 的独立衍生版本,开源版将持续维持开源与开放运营。 +

+
+
+ + {/* Action buttons */} +
+ +
+
+
+
+
+
+
+
+ ) +} + +export default EnhancedPromotionModal diff --git a/src/pages/Gallery-N/DictRequest.tsx b/src/pages/Gallery-N/DictRequest.tsx index 28b5c9f7..c3901648 100644 --- a/src/pages/Gallery-N/DictRequest.tsx +++ b/src/pages/Gallery-N/DictRequest.tsx @@ -1,4 +1,5 @@ import InfoPanel from '@/components/InfoPanel' +import { track } from '@vercel/analytics' import { useCallback, useState } from 'react' import IconBook2 from '~icons/tabler/book-2' @@ -7,10 +8,18 @@ export default function DictRequest() { const onOpenPanel = useCallback(() => { setShowPanel(true) + track('promotion_event', { + from: 'dict_request_button', + action: 'open', + }) }, []) const onClosePanel = useCallback(() => { setShowPanel(false) + track('promotion_event', { + from: 'dict_request_panel', + action: 'close', + }) }, []) return ( @@ -18,36 +27,91 @@ export default function DictRequest() { {showPanel && ( -

- 如果您有相关的编程基础,可以参考 - - 导入词典 - - ,给项目贡献新的词典。 -
-
- 如果您没有相关的编程基础,可以将您的字典需求发送邮件到{' '} - - me@kaiyi.cool - - ,或者在网页底部添加我们的用户社群进行反馈。 -

-
+
+
+

👨‍💻 具备编程技能?

+

+ 您可以参考我们的 + + 词典贡献指南 + + ,为开源项目贡献新的词典内容。 +

+
+ +
+

🚀 尝试 QwertyLearner.ai

+

+ 不会编程?想拥有自己的专属学习词典?操作简单,一键上传,点击即用 +
+

+ 那么,推荐您尝试由英国 DeepLearningAI 专业团队开发运营的 + QwertyLearner.ai +

+
+
+ + + AI 智能词库 - 一键上传,智能生成释义和词性,打造专属自定义词库 + +
+
+ + + 文章练习 - 自定义文章内容,提升实战能力 + +
+
+ + + 云端同步 - 多设备练习记录、错题库同步 + +
+
+ + + 词典选择 - 更多丰富的专业词库 + +
+
+ +
+ +
+

+ 说明:QwertyLearner.ai 由英国 DeepLearningAI 独立开发运营,为开源版 QwertyLearner + 的独立衍生版本,开源版将持续维持开源与开放运营。 +

+
+
)} - ) diff --git a/src/pages/Gallery-N/index.tsx b/src/pages/Gallery-N/index.tsx index c94e83cc..cdef2a53 100644 --- a/src/pages/Gallery-N/index.tsx +++ b/src/pages/Gallery-N/index.tsx @@ -67,7 +67,7 @@ export default function GalleryPage() {
-
+
diff --git a/src/pages/Typing/index.tsx b/src/pages/Typing/index.tsx index 7b835ea4..7e865655 100644 --- a/src/pages/Typing/index.tsx +++ b/src/pages/Typing/index.tsx @@ -11,8 +11,8 @@ import { useConfetti } from './hooks/useConfetti' import { useWordList } from './hooks/useWordList' import { TypingContext, TypingStateActionType, initialState, typingReducer } from './store' import { DonateCard } from '@/components/DonateCard' +import EnhancedPromotionModal from '@/components/EnhancedPromotionModal' import Header from '@/components/Header' -import StarCard from '@/components/StarCard' import Tooltip from '@/components/Tooltip' import { idDictionaryMap } from '@/resources/dictionary' import { currentChapterAtom, currentDictIdAtom, isReviewModeAtom, randomConfigAtom, reviewModeInfoAtom } from '@/store' @@ -129,7 +129,7 @@ const App: React.FC = () => { return ( - + {state.isFinished && } {state.isFinished && } diff --git a/src/store/index.ts b/src/store/index.ts index 7d7dd819..90e27974 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -110,5 +110,8 @@ export const wordDictationConfigAtom = atomForConfig('wordDictationConfig', { export const dismissStartCardDateAtom = atomWithStorage(DISMISS_START_CARD_DATE_KEY, null) +// Enhanced version promotion popup state +export const hasSeenEnhancedPromotionAtom = atomWithStorage('hasSeenEnhancedPromotion', false) + // for dev test // dismissStartCardDateAtom = atom(new Date())