mcpField
R
recovery-app-onboarding

recovery-app-onboarding

github.com/curiositech设计与 UI257130 次安装2 天前更新
代码仓库

关于 recovery-app-onboarding

面向康复与健康应用设计者的入门体验技能,强调尊重用户处境、先展示价值并采用非评判性语言。内容涉及分阶段引导、危机资源、隐私说明、无障碍和测试。

主要功能

  1. 01以同理心设计入门流程
  2. 02渐进式功能引导
  3. 03情境化权限请求
  4. 04危机资源与安全计划入口
  5. 05无障碍与体验测试清单

适用场景

  1. 01设计首次使用与功能导览
  2. 02安排权限请求和隐私说明
  3. 03加入康复项目选择与安全计划
  4. 04检查引导流程的无障碍性

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/curiositech/some_claude_skills --skill recovery-app-onboarding

安装后在 Claude Code 中输入/recovery-app-onboarding确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

assets/
example_asset.txt
references/
api_reference.md
scripts/
example.py

详细介绍

康复应用引导体验优化

为康复和健康应用打造富有同理心、有效的引导体验,以尊严和实用价值服务于脆弱人群。

适用场景

✅ 以下场景请使用此技能:

  • 首次用户引导流程
  • 功能发现和应用导览
  • 渐进式信息披露设计
  • 权限请求的时机和说明方式
  • 欢迎屏幕和价值主张
  • 康复计划选择流程
  • 危机资源集成
  • 隐私和匿名性说明

❌ 以下场景请勿使用:

  • 通用移动端响应式设计 → 使用 mobile-ux-optimizer
  • 营销/转化优化 → 使用 seo-visibility-expert
  • 原生 iOS/Android 开发 → 使用平台专属技能
  • 数据库架构设计 → 使用 supabase-admin

核心原则

1. 同理心优先,功能其次

康复用户往往处于脆弱状态。每项引导决策都必须考虑:

❌ ANTI-PATTERN: "Sign up to track your progress!"
✅ CORRECT: "You're taking a brave step. Let's set up a private space for your journey."

❌ ANTI-PATTERN: Requiring account creation before showing any value
✅ CORRECT: Let users explore core features anonymously, then offer accounts for persistence
2. 先展示价值,再要求承诺

在索取个人信息前,先展示切实的价值:

WRONG ORDER:
1. Create account
2. Enter personal details
3. Grant permissions
4. Finally see the app

RIGHT ORDER:
1. Show immediate value (meeting finder, crisis resources)
2. Demonstrate app benefits
3. Offer optional account for saved data
4. Request permissions contextually
3. 使用不带评判的语言

避免使用引发羞耻感或造成刺激的语言:

❌ "How many days since your last relapse?"
✅ "What's your current sobriety date?"

❌ "You failed to complete..."
✅ "No worries—pick up where you left off"

❌ "Are you an alcoholic or drug addict?"
✅ "Which recovery programs interest you?"

移动端引导 UX(2025 年最佳实践)

渐进式信息披露

将复杂的引导拆分为易于理解的阶段:

// ✅ GOOD: Staged onboarding with clear progress
const ONBOARDING_STAGES = [
  { id: 'welcome', required: false },    // Emotional connection
  { id: 'programs', required: false },    // Personalization
  { id: 'features', required: false },    // Value discovery
  { id: 'preferences', required: false }, // Customization
  { id: 'safety', required: false },      // Crisis setup
];

// Each stage should be:
// - Skippable (never trap users)
// - Under 60 seconds to complete
// - Visually distinct with progress indicators
// - Reversible (can go back)
权限预先说明(授权率提高 28%)

切勿脱离具体情境请求权限:

// ❌ BAD: Immediate system permission dialog
useEffect(() => {
  requestLocationPermission();
}, []);

// ✅ GOOD: Contextual priming before system dialog
function MeetingSearchPrimer() {
  return (
    <div className="p-4 bg-blue-50 rounded-lg mb-4">
      <MapPin className="text-blue-500 mb-2" />
      <h3>Find Meetings Near You</h3>
      <p className="text-sm text-gray-600 mb-3">
        To show meetings within walking distance, we need your location.
        Your location stays on your device.
      </p>
      <button onClick={handleEnableLocation} className="btn-primary">
        Enable Location
      </button>
      <button onClick={handleSkip} className="btn-text">
        Search by ZIP instead
      </button>
    </div>
  );
}
“持续引导”——不止于首次启动

引导并非一次性事件:

// Feature discovery on first use of each feature
function useFeatureOnboarding(featureId: string) {
  const [hasSeenTooltip, setHasSeen] = useLocalStorage(`onboard:${featureId}`, false);

  return {
    showTooltip: !hasSeenTooltip,
    dismissTooltip: () => setHasSeen(true),
  };
}

// Example: First time using gratitude journal
function GratitudeJournal() {
  const { showTooltip, dismissTooltip } = useFeatureOnboarding('gratitude');

  return (
    <>
      {showTooltip && (
        <FeatureTooltip
          title="Daily Gratitude"
          description="Write 3 things you're grateful for. Research shows this builds resilience."
          onDismiss={dismissTooltip}
        />
      )}
      {/* Journal UI */}
    </>
  );
}
使用骨架屏加载器,切勿使用旋转加载图标

处于危机中的康复用户需要即时反馈:

// ❌ BAD: Spinner creates anxiety
{isLoading && <Loader2 className="animate-spin" />}

// ✅ GOOD: Skeleton shows structure immediately
{isLoading && <MeetingCardSkeleton count={5} />}

// Skeleton implementation
function MeetingCardSkeleton() {
  return (
    <div className="p-4 bg-leather-800 rounded-lg animate-pulse">
      <div className="h-4 bg-leather-700 rounded w-3/4 mb-2" />
      <div className="h-3 bg-leather-700 rounded w-1/2 mb-4" />
      <div className="flex gap-2">
        <div className="h-6 w-16 bg-leather-700 rounded" />
        <div className="h-6 w-16 bg-leather-700 rounded" />
      </div>
    </div>
  );
}

康复应用功能类别

核心功能(优先展示)
  1. 会议查找器——核心实用功能,立即提供价值
  2. 危机资源——关乎生命安全,始终可访问
  3. 安全计划——个人支持网络
互动功能(次优先)
  1. 每日签到——关注 HALT 状态
  2. 康复日志——反思与成长
  3. 感恩练习——积极强化
高级功能(逐步引导发现)
  1. 戒瘾计数器——里程碑追踪
  2. 社区论坛——同伴支持
  3. 康复计划——AI 辅助指导
  4. 线上会议——虚拟选项
功能卡片模式
interface OnboardingFeature {
  id: string;
  icon: React.ComponentType;
  title: string;
  description: string;
  highlight: string;        // Key benefit (e.g., "24/7 support available")
  color: string;            // Brand color for visual distinction
  category: 'essential' | 'engagement' | 'advanced';
}

const FEATURES: OnboardingFeature[] = [
  {
    id: 'meetings',
    icon: MapPin,
    title: 'Find Meetings Near You',
    description: 'Search thousands of AA, NA, CMA, SMART, and other recovery meetings.',
    highlight: '100,000+ meetings nationwide',
    color: 'bg-blue-500',
    category: 'essential',
  },
  {
    id: 'crisis',
    icon: Phone,
    title: 'Crisis Resources',
    description: 'One-tap access to crisis hotlines and emergency support.',
    highlight: '24/7 support available',
    color: 'bg-red-500',
    category: 'essential',
  },
  // ... more features
];

危机资源集成

重要提示:只有 45% 的心理健康应用包含危机资源。这对康复应用而言是不可妥协的要求。

始终可见的危机支持入口
// Crisis resources should be accessible from EVERY screen
function Navigation() {
  return (
    <nav>
      {/* Normal nav items */}
      <CrisisButton className="fixed bottom-20 right-4" />
    </nav>
  );
}

// Crisis button design
function CrisisButton({ className }: { className?: string }) {
  return (
    <Link
      href="/crisis"
      className={cn(
        'flex items-center justify-center',
        'w-14 h-14 rounded-full',
        'bg-red-600 hover:bg-red-700',
        'shadow-lg shadow-red-600/30',
        'text-white',
        className
      )}
      aria-label="Crisis resources"
    >
      <Phone size={24} />
    </Link>
  );
}
引导流程中的安全计划步骤
// Include safety planning in onboarding, but make it optional
function SafetyPlanStep() {
  return (
    <div className="space-y-4">
      <h2>Your Safety Network</h2>
      <p className="text-gray-600">
        Having support contacts ready can make all the difference.
        This is optional—you can set this up anytime.
      </p>

      <EmergencyContactInput
        label="Emergency Contact"
        placeholder="Someone who can help in a crisis"
      />

      <SupportPersonInput
        label="Support Person"
        placeholder="Sponsor, therapist, or trusted friend"
      />

      <div className="flex gap-2 mt-6">
        <button className="btn-secondary flex-1" onClick={handleSkip}>
          Set Up Later
        </button>
        <button className="btn-primary flex-1" onClick={handleSave}>
          Save Contacts
        </button>
      </div>
    </div>
  );
}

康复计划选择

支持多选,兼容不同选择

以不带评判的态度支持多种康复路径:

const RECOVERY_PROGRAMS = [
  { id: 'aa', name: 'Alcoholics Anonymous', short: 'AA', color: 'bg-blue-500' },
  { id: 'na', name: 'Narcotics Anonymous', short: 'NA', color: 'bg-purple-500' },
  { id: 'cma', name: 'Crystal Meth Anonymous', short: 'CMA', color: 'bg-pink-500' },
  { id: 'smart', name: 'SMART Recovery', short: 'SMART', color: 'bg-green-500' },
  { id: 'dharma', name: 'Recovery Dharma', short: 'Dharma', color: 'bg-amber-500' },
  { id: 'ha', name: 'Heroin Anonymous', short: 'HA', color: 'bg-red-500' },
  { id: 'oa', name: 'Overeaters Anonymous', short: 'OA', color: 'bg-teal-500' },
  { id: 'other', name: 'Other/Multiple', short: 'Other', color: 'bg-gray-500' },
];

// UI should allow multiple selections
function ProgramSelection({ selected, onChange }) {
  return (
    <div className="grid grid-cols-2 gap-3">
      {RECOVERY_PROGRAMS.map((program) => (
        <ProgramCard
          key={program.id}
          program={program}
          isSelected={selected.includes(program.id)}
          onToggle={() => toggleProgram(program.id)}
        />
      ))}
    </div>
  );
}

引导流程架构

状态管理
interface OnboardingState {
  currentStep: number;
  completedSteps: string[];
  selectedPrograms: string[];
  meetingPreferences: {
    formats: ('in-person' | 'online' | 'hybrid')[];
    days: string[];
    times: ('morning' | 'afternoon' | 'evening')[];
  };
  safetyContacts: {
    emergency?: string;
    support?: string;
  };
  skippedSteps: string[];
}

// Persist across sessions
function useOnboardingState() {
  return useLocalStorage<OnboardingState>('onboarding', defaultState);
}
步骤导航
function OnboardingWizard() {
  const [state, setState] = useOnboardingState();
  const currentStep = STEPS[state.currentStep];

  const goNext = () => {
    setState(prev => ({
      ...prev,
      currentStep: Math.min(prev.currentStep + 1, STEPS.length - 1),
      completedSteps: [...prev.completedSteps, currentStep.id],
    }));
  };

  const goBack = () => {
    setState(prev => ({
      ...prev,
      currentStep: Math.max(prev.currentStep - 1, 0),
    }));
  };

  const skip = () => {
    setState(prev => ({
      ...prev,
      skippedSteps: [...prev.skippedSteps, currentStep.id],
    }));
    goNext();
  };

  return (
    <div className="min-h-screen flex flex-col">
      <ProgressIndicator
        current={state.currentStep}
        total={STEPS.length}
        completedSteps={state.completedSteps}
      />

      <main className="flex-1 p-4">
        <CurrentStepComponent {...currentStep} state={state} setState={setState} />
      </main>

      <footer className="p-4 border-t border-leather-700">
        <div className="flex gap-3">
          {state.currentStep > 0 && (
            <button onClick={goBack} className="btn-secondary flex-1">
              Back
            </button>
          )}
          {currentStep.skippable && (
            <button onClick={skip} className="btn-text">
              Skip
            </button>
          )}
          <button onClick={goNext} className="btn-primary flex-1">
            {state.currentStep === STEPS.length - 1 ? 'Get Started' : 'Continue'}
          </button>
        </div>
      </footer>
    </div>
  );
}

微交互

入场动画
// Staggered entrance for lists
function StaggeredList({ items, renderItem }) {
  return (
    <div className="space-y-3">
      {items.map((item, index) => (
        <div
          key={item.id}
          className="animate-fade-in-up"
          style={{ animationDelay: `${index * 100}ms` }}
        >
          {renderItem(item, index)}
        </div>
      ))}
    </div>
  );
}
轮播导航
// Swipe gesture support for mobile feature tours
function useSwipeNavigation({ onNext, onPrev, threshold = 50 }) {
  const [touchStart, setTouchStart] = useState<number | null>(null);
  const [touchEnd, setTouchEnd] = useState<number | null>(null);

  const onTouchStart = (e: React.TouchEvent) => {
    setTouchEnd(null);
    setTouchStart(e.targetTouches[0].clientX);
  };

  const onTouchMove = (e: React.TouchEvent) => {
    setTouchEnd(e.targetTouches[0].clientX);
  };

  const onTouchEnd = () => {
    if (!touchStart || !touchEnd) return;
    const distance = touchStart - touchEnd;
    if (distance > threshold) onNext();
    if (distance < -threshold) onPrev();
  };

  return { onTouchStart, onTouchMove, onTouchEnd };
}

无障碍要求

符合 WCAG AA 标准
  • 对比度:字号小于 18px 的文本为 4.5:1,字号大于或等于 18px 的文本为 3:1
  • 触控目标:最小尺寸为 44x44px
  • 焦点指示器:所有交互元素都要显示轮廓
  • 屏幕阅读器:使用 aria-live 播报步骤变化
减少动态效果
@media (prefers-reduced-motion: reduce) {
  .animate-fade-in-up,
  .animate-slide-in {
    animation: none;
    opacity: 1;
    transform: none;
  }
}

测试清单

功能测试
  • 所有步骤均可完成
  • 所有步骤均可跳过
  • 返回导航正常
  • 进度可在不同会话间保留
  • 移动端滑动手势正常
  • 键盘导航正常
无障碍测试
  • 屏幕阅读器会播报步骤变化
  • 所有交互元素均有标签
  • 焦点顺序合理
  • 颜色对比度符合 WCAG AA 标准
  • 触控目标最小尺寸为 44x44px
性能测试
  • 初次加载时间少于 2 秒
  • 步骤切换时间少于 300ms
  • 动画期间没有布局偏移
  • 首次加载后可离线使用
情绪体验测试
  • 语言不带评判
  • 跳过选项清晰易懂
  • 不使用施压手段
  • 危机资源清晰可见
  • 隐私说明清晰

参考资料

详细指南请参阅 /references/:

  • competitor-analysis.md - I Am Sober、Nomo、Sober Grid 的设计模式
  • wellness-patterns.md - Headspace、Calm、Daylio 的见解
  • crisis-integration.md - 紧急资源最佳实践

评论

支持 Markdown