mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-22 06:25:41 +00:00
chore(orbit): help modal with 9-section walk-through
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
import { useEffect } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import {
|
||||
X, Sparkles, Users, Share2, LogIn, MousePointerClick,
|
||||
ListMusic, Inbox, Sliders, LogOut,
|
||||
} from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useHelpModalStore } from '../store/helpModalStore';
|
||||
import SettingsSubSection from './SettingsSubSection';
|
||||
|
||||
/**
|
||||
* Orbit help modal. Rendered once at the app root; triggered from the
|
||||
* launch popover ("How does this work?") and the in-session bar's help
|
||||
* button. 9 accordion sections built on SettingsSubSection; all default
|
||||
* closed so the modal opens compact. Does not touch playback.
|
||||
*/
|
||||
export default function OrbitHelpModal() {
|
||||
const { t } = useTranslation();
|
||||
const { isOpen, close } = useHelpModalStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen) return;
|
||||
const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') close(); };
|
||||
window.addEventListener('keydown', onKey);
|
||||
return () => window.removeEventListener('keydown', onKey);
|
||||
}, [isOpen, close]);
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
const hostOnlyLabel = t('orbit.helpHostOnly');
|
||||
|
||||
return createPortal(
|
||||
<div
|
||||
className="modal-overlay"
|
||||
onClick={e => { if (e.target === e.currentTarget) close(); }}
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="orbit-help-title"
|
||||
style={{ alignItems: 'center', paddingTop: 0 }}
|
||||
>
|
||||
<div className="modal-content orbit-help-modal">
|
||||
<button type="button" className="modal-close" onClick={close} aria-label={t('orbit.closeAria')}>
|
||||
<X size={18} />
|
||||
</button>
|
||||
|
||||
<h3 id="orbit-help-title" className="orbit-help-modal__title">
|
||||
{t('orbit.helpTitle')}
|
||||
</h3>
|
||||
<p className="orbit-help-modal__intro">{t('orbit.helpIntro')}</p>
|
||||
|
||||
<div className="orbit-help-modal__body">
|
||||
<SettingsSubSection title={t('orbit.helpSec1Title')} icon={<Sparkles size={16} />}>
|
||||
<p>{t('orbit.helpSec1Body')}</p>
|
||||
</SettingsSubSection>
|
||||
|
||||
<SettingsSubSection title={t('orbit.helpSec2Title')} icon={<Users size={16} />}>
|
||||
<p>{t('orbit.helpSec2Body')}</p>
|
||||
<div className="orbit-help-modal__warn">
|
||||
<strong>{t('orbit.helpSec2WarnHead')}</strong>
|
||||
<span>{t('orbit.helpSec2WarnBody')}</span>
|
||||
</div>
|
||||
</SettingsSubSection>
|
||||
|
||||
<SettingsSubSection title={t('orbit.helpSec3Title')} icon={<Share2 size={16} />}>
|
||||
<p>{t('orbit.helpSec3Body')}</p>
|
||||
</SettingsSubSection>
|
||||
|
||||
<SettingsSubSection title={t('orbit.helpSec4Title')} icon={<LogIn size={16} />}>
|
||||
<p>{t('orbit.helpSec4Body')}</p>
|
||||
</SettingsSubSection>
|
||||
|
||||
<SettingsSubSection title={t('orbit.helpSec5Title')} icon={<MousePointerClick size={16} />}>
|
||||
<p>{t('orbit.helpSec5Body')}</p>
|
||||
</SettingsSubSection>
|
||||
|
||||
<SettingsSubSection title={t('orbit.helpSec6Title')} icon={<ListMusic size={16} />}>
|
||||
<p>{t('orbit.helpSec6Body')}</p>
|
||||
</SettingsSubSection>
|
||||
|
||||
<SettingsSubSection
|
||||
title={`${t('orbit.helpSec7Title')} ${hostOnlyLabel}`}
|
||||
icon={<Inbox size={16} />}
|
||||
>
|
||||
<p>{t('orbit.helpSec7Body')}</p>
|
||||
</SettingsSubSection>
|
||||
|
||||
<SettingsSubSection
|
||||
title={`${t('orbit.helpSec8Title')} ${hostOnlyLabel}`}
|
||||
icon={<Sliders size={16} />}
|
||||
>
|
||||
<p>{t('orbit.helpSec8Body')}</p>
|
||||
</SettingsSubSection>
|
||||
|
||||
<SettingsSubSection title={t('orbit.helpSec9Title')} icon={<LogOut size={16} />}>
|
||||
<p>{t('orbit.helpSec9Body')}</p>
|
||||
</SettingsSubSection>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
document.body,
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { X, RefreshCw, Shuffle, Settings2, Share2 } from 'lucide-react';
|
||||
import { X, RefreshCw, Shuffle, Settings2, Share2, HelpCircle } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useOrbitStore } from '../store/orbitStore';
|
||||
import { useHelpModalStore } from '../store/helpModalStore';
|
||||
import { usePlayerStore, songToTrack } from '../store/playerStore';
|
||||
import { getSong } from '../api/subsonic';
|
||||
import {
|
||||
@@ -208,6 +209,15 @@ export default function OrbitSessionBar() {
|
||||
<span>{t('orbit.catchUpLabel')}</span>
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
className="orbit-bar__settings"
|
||||
onClick={() => useHelpModalStore.getState().open()}
|
||||
data-tooltip={t('orbit.helpTooltip')}
|
||||
aria-label={t('orbit.helpTooltip')}
|
||||
>
|
||||
<HelpCircle size={14} />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="orbit-bar__exit"
|
||||
|
||||
@@ -3,6 +3,7 @@ import { createPortal } from 'react-dom';
|
||||
import { Orbit as OrbitIcon, Plus, LogIn, HelpCircle } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useOrbitStore } from '../store/orbitStore';
|
||||
import { useHelpModalStore } from '../store/helpModalStore';
|
||||
import OrbitStartModal from './OrbitStartModal';
|
||||
import OrbitJoinModal from './OrbitJoinModal';
|
||||
|
||||
@@ -54,6 +55,7 @@ export default function OrbitStartTrigger() {
|
||||
|
||||
const pickCreate = () => { setPopoverOpen(false); setStartOpen(true); };
|
||||
const pickJoin = () => { setPopoverOpen(false); setJoinOpen(true); };
|
||||
const pickHelp = () => { setPopoverOpen(false); useHelpModalStore.getState().open(); };
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -85,9 +87,7 @@ export default function OrbitStartTrigger() {
|
||||
<button
|
||||
type="button"
|
||||
className="orbit-launch-pop__item"
|
||||
disabled
|
||||
data-tooltip={t('orbit.launchHelpSoon')}
|
||||
data-tooltip-pos="bottom"
|
||||
onClick={pickHelp}
|
||||
>
|
||||
<HelpCircle size={14} />
|
||||
<span>{t('orbit.launchHelp')}</span>
|
||||
|
||||
Reference in New Issue
Block a user