guide.tsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. 'use client';
  2. import { HelpCircle } from 'lucide-react';
  3. import { useI18n } from '@/lib/hooks/use-i18n';
  4. import { HoverCard, HoverCardTrigger, HoverCardContent } from '@/components/ui/hover-card';
  5. /**
  6. * Inline guide shown below the role selection cards.
  7. * Hover to reveal the 3-step PBL workflow as a popover above.
  8. */
  9. export function PBLGuideInline() {
  10. const { t } = useI18n();
  11. return (
  12. <HoverCard openDelay={0} closeDelay={150}>
  13. <div className="w-full flex justify-center">
  14. <HoverCardTrigger asChild>
  15. <button className="flex items-center gap-1.5 text-sm text-muted-foreground hover:text-foreground transition-colors">
  16. <HelpCircle className="w-4 h-4" />
  17. <span>{t('pbl.guide.howItWorks')}</span>
  18. </button>
  19. </HoverCardTrigger>
  20. </div>
  21. <HoverCardContent
  22. side="top"
  23. collisionPadding={16}
  24. className="w-[380px] overflow-y-auto rounded-xl p-5"
  25. style={{
  26. maxHeight: 'var(--radix-hover-card-content-available-height, 70vh)',
  27. }}
  28. >
  29. <GuideContent />
  30. </HoverCardContent>
  31. </HoverCard>
  32. );
  33. }
  34. /**
  35. * Help button in workspace toolbar — hover to show guide popover.
  36. */
  37. export function PBLGuidePanel() {
  38. const { t } = useI18n();
  39. return (
  40. <HoverCard openDelay={0} closeDelay={150}>
  41. <HoverCardTrigger asChild>
  42. <button
  43. className="flex items-center justify-center w-7 h-7 rounded-md text-muted-foreground hover:text-foreground hover:bg-muted transition-colors"
  44. title={t('pbl.guide.help')}
  45. >
  46. <HelpCircle className="w-4 h-4" />
  47. </button>
  48. </HoverCardTrigger>
  49. <HoverCardContent
  50. side="bottom"
  51. align="end"
  52. collisionPadding={16}
  53. className="w-[380px] overflow-y-auto rounded-xl p-5"
  54. style={{
  55. maxHeight: 'var(--radix-hover-card-content-available-height, 80vh)',
  56. }}
  57. >
  58. <GuideContent />
  59. </HoverCardContent>
  60. </HoverCard>
  61. );
  62. }
  63. function GuideContent() {
  64. const { t } = useI18n();
  65. return (
  66. <div className="space-y-5 text-[13px] leading-relaxed text-foreground">
  67. {/* Step 1 */}
  68. <section>
  69. <h4 className="font-semibold mb-1">{t('pbl.guide.step1.title')}</h4>
  70. <p className="text-muted-foreground">{t('pbl.guide.step1.desc')}</p>
  71. </section>
  72. <hr className="border-border" />
  73. {/* Step 2 */}
  74. <section>
  75. <h4 className="font-semibold mb-1">{t('pbl.guide.step2.title')}</h4>
  76. <p className="text-muted-foreground mb-3">{t('pbl.guide.step2.desc')}</p>
  77. <ol className="list-decimal list-inside space-y-3 text-muted-foreground">
  78. {/* 2-1 */}
  79. <li>
  80. <span className="font-medium text-foreground">{t('pbl.guide.step2.s1.title')}</span>
  81. <p className="mt-0.5 ml-[1.125rem]">{t('pbl.guide.step2.s1.desc')}</p>
  82. </li>
  83. {/* 2-2 */}
  84. <li>
  85. <span className="font-medium text-foreground">{t('pbl.guide.step2.s2.title')}</span>
  86. <code className="ml-1.5 text-xs bg-muted rounded px-1.5 py-0.5 font-mono">
  87. @question
  88. </code>
  89. <div className="mt-1.5 ml-[1.125rem] space-y-1.5">
  90. <pre className="text-xs bg-muted/70 rounded-md px-3 py-2 font-mono leading-relaxed overflow-x-auto">
  91. {t('pbl.guide.step2.s2.example')}
  92. </pre>
  93. <p>{t('pbl.guide.step2.s2.desc')}</p>
  94. </div>
  95. </li>
  96. {/* 2-3 */}
  97. <li>
  98. <span className="font-medium text-foreground">{t('pbl.guide.step2.s3.title')}</span>
  99. <code className="ml-1.5 text-xs bg-muted rounded px-1.5 py-0.5 font-mono">@judge</code>
  100. <div className="mt-1.5 ml-[1.125rem] space-y-1.5">
  101. <pre className="text-xs bg-muted/70 rounded-md px-3 py-2 font-mono leading-relaxed overflow-x-auto">
  102. {t('pbl.guide.step2.s3.example')}
  103. </pre>
  104. <p>{t('pbl.guide.step2.s3.desc')}</p>
  105. <ul className="space-y-0.5 mt-1">
  106. <li>
  107. ✅ <span className="font-medium text-foreground">COMPLETE</span> →{' '}
  108. {t('pbl.guide.step2.s3.complete')}
  109. </li>
  110. <li>
  111. 🔄 <span className="font-medium text-foreground">NEEDS_REVISION</span> →{' '}
  112. {t('pbl.guide.step2.s3.revision')}
  113. </li>
  114. </ul>
  115. </div>
  116. </li>
  117. </ol>
  118. </section>
  119. <hr className="border-border" />
  120. {/* Step 3 */}
  121. <section>
  122. <h4 className="font-semibold mb-1">{t('pbl.guide.step3.title')}</h4>
  123. <p className="text-muted-foreground">{t('pbl.guide.step3.desc')}</p>
  124. </section>
  125. </div>
  126. );
  127. }