Add player portal + character-sheet front end (phase 4 follow-up)
Turns the raw shard endpoints into proper, navigable pages in the site's visual language. - components/CharacterSheet.jsx: reusable sheet — attribute tiles, vitals bars, resistances, skills (with bars), and equipment — styled with the shared panel/grid vocabulary. - Player portal with a nav bar: PlayerPortalLayout (Characters / Account tabs + sign-out) wraps /player and /account. /player (PlayerCharacters) tells the logged-in player if they haven't linked a game account (with the [link code prompt) or, once linked, shows their characters grouped by account; each character opens its sheet at /player/char/:serial. Account security moved into the same shell (the buried "Game accounts" block was removed from it). Login/register now land on /player. - Public: GET /public/shard/online (redacted name+serial+map) drives an "Online now" list on /site/shard that links to public character sheets at /site/shard/char/:serial (ShardChar). Swagger: ShardOnlinePlayer + regenerated. - api.shard.online added. Verified live against the running shard: Darrow's full sheet (STR 120, 58 skills, 3 equipment) renders through the browser-facing proxy; the online list returns the live roster; player routes 401 without a session. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011qPmpmVH1xGCiZoz9m9vW3
This commit is contained in:
54
client/src/routes/player/PlayerPortalLayout.jsx
Normal file
54
client/src/routes/player/PlayerPortalLayout.jsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import { NavLink, Link, Outlet, useNavigate } from 'react-router-dom'
|
||||
import MoonDot from '../../components/MoonDot.jsx'
|
||||
import { useAuth } from '../../contexts/AuthContext.jsx'
|
||||
|
||||
// Shared shell for the logged-in player portal: a header with a nav bar
|
||||
// (Characters / Account) and the page content in an <Outlet />. Matches the
|
||||
// site's dark theme vocabulary.
|
||||
const tab = ({ isActive }) => ({
|
||||
textDecoration: 'none',
|
||||
fontFamily: 'var(--sans)',
|
||||
fontSize: '0.9rem',
|
||||
padding: '8px 4px',
|
||||
color: isActive ? 'var(--head)' : 'var(--muted)',
|
||||
borderBottom: `2px solid ${isActive ? 'var(--accent)' : 'transparent'}`,
|
||||
})
|
||||
|
||||
export default function PlayerPortalLayout() {
|
||||
const { user, logout } = useAuth()
|
||||
const navigate = useNavigate()
|
||||
|
||||
async function signOut() {
|
||||
await logout()
|
||||
navigate('/account/login', { replace: true })
|
||||
}
|
||||
|
||||
return (
|
||||
<main style={{ minHeight: '100vh', background: 'var(--bg-deep)', color: 'var(--ink)' }}>
|
||||
<header style={{ borderBottom: '1px solid var(--line)' }}>
|
||||
<div style={{ maxWidth: 820, margin: '0 auto', padding: '16px 20px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
|
||||
<MoonDot size={12} glow={0.5} />
|
||||
<div>
|
||||
<div className="display" style={{ color: 'var(--head)', fontSize: '1.05rem', letterSpacing: '0.04em' }}>UOMysticmoon</div>
|
||||
<div className="sans" style={{ color: 'var(--dim)', fontSize: '0.64rem', letterSpacing: '0.14em', textTransform: 'uppercase' }}>Player Portal</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
|
||||
<span className="sans dim" style={{ fontSize: '0.82rem' }}>{user?.username}</span>
|
||||
<Link to="/" className="sans" style={{ color: 'var(--accent)', fontSize: '0.84rem', textDecoration: 'none' }}>← Site</Link>
|
||||
<button onClick={signOut} className="pill">Sign out</button>
|
||||
</div>
|
||||
</div>
|
||||
<nav style={{ maxWidth: 820, margin: '0 auto', padding: '0 20px', display: 'flex', gap: 22 }}>
|
||||
<NavLink to="/player" end style={tab}>Characters</NavLink>
|
||||
<NavLink to="/account" style={tab}>Account</NavLink>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<div style={{ maxWidth: 820, margin: '0 auto', padding: '28px 20px 60px' }}>
|
||||
<Outlet />
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user