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:
2026-07-11 02:51:50 -05:00
parent e7bc316863
commit fe6f93481b
15 changed files with 609 additions and 218 deletions

View File

@@ -1410,6 +1410,33 @@
}
}
},
"/api/v1/public/shard/online": {
"get": {
"tags": [
"Public · Shard"
],
"summary": "Players online now (name + serial + map only)",
"description": "",
"responses": {
"200": {
"description": "Online players",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ShardOnlinePlayer"
}
}
}
}
},
"500": {
"description": "Internal Server Error"
}
}
}
},
"/api/v1/public/shard/idoc": {
"get": {
"tags": [
@@ -10307,6 +10334,67 @@
}
}
},
"ShardOnlinePlayer": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "object"
},
"description": {
"type": "string",
"example": "A player online now (redacted for the public list)."
},
"properties": {
"type": "object",
"properties": {
"serial": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "0x24C"
}
}
},
"name": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"example": {
"type": "string",
"example": "Darrow"
}
}
},
"map": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "string"
},
"nullable": {
"type": "boolean",
"example": true
},
"example": {
"type": "string",
"example": "Trammel"
}
}
}
}
}
}
},
"ShardHouse": {
"type": "object",
"properties": {