diff --git a/src/pages/music/MusicStudio.css b/src/pages/music/MusicStudio.css index 480a955..f799685 100644 --- a/src/pages/music/MusicStudio.css +++ b/src/pages/music/MusicStudio.css @@ -3180,3 +3180,102 @@ width: 100%; accent-color: #22c55e; } + +/* === SetupTab === */ +.setup-container { display:flex; flex-direction:column; gap:16px; padding:16px; } +.setup-card { + background: rgba(0,0,0,.3); + border: 1px solid var(--ms-line, #2a2a3a); + border-radius: 14px; + padding: 16px; +} +.setup-card h3 { + margin: 0 0 12px; + font-size: 15px; + color: var(--ms-text, #f0f0f5); + font-family: var(--ms-ff-disp, inherit); + letter-spacing: 0.04em; +} +.setup-card label { + display: block; + margin: 8px 0; + font-size: 12px; + color: var(--ms-muted, #a0a0b0); +} +.setup-card input, +.setup-card textarea, +.setup-card select { + width: 100%; + padding: 8px; + margin-top: 4px; + background: rgba(255,255,255,.04); + border: 1px solid var(--ms-line, #2a2a3a); + border-radius: 8px; + color: var(--ms-text, #f0f0f5); + font-size: 13px; + font-family: inherit; + box-sizing: border-box; +} +.setup-card input[type="range"] { + padding: 0; + background: transparent; + border: none; + accent-color: var(--ms-accent, #f5a623); +} +.setup-card button { + padding: 6px 14px; + margin-top: 8px; + background: rgba(245, 166, 35, 0.15); + color: var(--ms-accent, #bae6fd); + border: 1px solid rgba(245, 166, 35, 0.4); + border-radius: 8px; + cursor: pointer; + font-size: 13px; + font-family: inherit; +} +.setup-card button:hover { + background: rgba(245, 166, 35, 0.25); +} +.setup-channel { + display: flex; + align-items: center; + gap: 12px; +} +.setup-avatar { + width: 32px; + height: 32px; + border-radius: 50%; +} +.setup-prompt-row { + display: flex; + gap: 8px; + margin: 6px 0; + align-items: center; +} +.setup-prompt-genre { + width: 80px; + font-size: 12px; + color: var(--ms-muted, #a0a0b0); + flex-shrink: 0; +} +.setup-saving { + position: fixed; + bottom: 16px; + right: 16px; + background: #222; + padding: 8px 12px; + border-radius: 8px; + border: 1px solid rgba(255,255,255,.1); + font-size: 12px; + color: var(--ms-text, #f0f0f5); + z-index: 100; +} +.ms-loading, +.ms-error { + padding: 24px; + text-align: center; + color: var(--ms-muted, #a0a0b0); +} +.ms-error { + color: #f87171; +} diff --git a/src/pages/music/components/SetupTab.jsx b/src/pages/music/components/SetupTab.jsx new file mode 100644 index 0000000..926d5c3 --- /dev/null +++ b/src/pages/music/components/SetupTab.jsx @@ -0,0 +1,148 @@ +import { useEffect, useState } from 'react'; +import { + getMusicSetup, updateMusicSetup, + getYoutubeAuthUrl, getYoutubeStatus, disconnectYoutube, +} from '../../../api'; + +export default function SetupTab() { + const [setup, setSetup] = useState(null); + const [yt, setYt] = useState(null); + const [saving, setSaving] = useState(false); + const [error, setError] = useState(''); + + useEffect(() => { + Promise.all([getMusicSetup(), getYoutubeStatus()]) + .then(([s, y]) => { setSetup(s); setYt(y); }) + .catch(e => setError(String(e))); + }, []); + + if (!setup) return
Loading…
; + + const save = async (patch) => { + setSaving(true); + try { + const next = await updateMusicSetup(patch); + setSetup(next); + } catch (e) { setError(String(e)); } + finally { setSaving(false); } + }; + + const connectYoutube = async () => { + const { url } = await getYoutubeAuthUrl(); + window.location.href = url; + }; + + return ( +