Standardize WalkUp branding

This commit is contained in:
Codex
2026-04-24 07:15:29 -05:00
parent 6c0c7608bf
commit 23dc6d9151
13 changed files with 43 additions and 43 deletions

View File

@@ -1,4 +1,4 @@
# Walkup Implementation Plan # WalkUp Implementation Plan
## Scope ## Scope
- React PWA frontend. - React PWA frontend.

View File

@@ -1,6 +1,6 @@
# Walkup # WalkUp
Walkup is a collaborative baseball walk-up song app built as a React PWA with a FastAPI backend. The browser integrates with TeamSnap through the official JavaScript SDK, while the backend keeps TeamSnap secrets and only stores app-owned media and game state. WalkUp is a collaborative baseball walk-up song app built as a React PWA with a FastAPI backend. The browser integrates with TeamSnap through the official JavaScript SDK, while the backend keeps TeamSnap secrets and only stores app-owned media and game state.
## Stack ## Stack
- Frontend: React, TypeScript, Vite, React Router, TanStack Query, `teamsnap.js`, `vite-plugin-pwa` - Frontend: React, TypeScript, Vite, React Router, TanStack Query, `teamsnap.js`, `vite-plugin-pwa`

View File

@@ -9,7 +9,7 @@ from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings): class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore") model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore")
app_name: str = "Walkup API" app_name: str = "WalkUp API"
backend_host: str = "0.0.0.0" backend_host: str = "0.0.0.0"
backend_port: int = 8000 backend_port: int = 8000
backend_cors_origins_raw: str = "https://kif.local.ascorrea.com" backend_cors_origins_raw: str = "https://kif.local.ascorrea.com"

View File

@@ -1,6 +1,6 @@
# Architecture # Architecture
Walkup is a baseball walk-up song app with a React PWA frontend and a FastAPI backend. WalkUp is a baseball walk-up song app with a React PWA frontend and a FastAPI backend.
## System Overview ## System Overview

View File

@@ -1,6 +1,6 @@
# Coding Standards # Coding Standards
These rules apply to Walkup-specific work in this repository. These rules apply to WalkUp-specific work in this repository.
## General ## General

View File

@@ -6,7 +6,7 @@
<meta name="theme-color" content="#132238" /> <meta name="theme-color" content="#132238" />
<meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="default" /> <meta name="apple-mobile-web-app-status-bar-style" content="default" />
<meta name="apple-mobile-web-app-title" content="Walkup" /> <meta name="apple-mobile-web-app-title" content="WalkUp" />
<link rel="icon" href="/favicon.ico" sizes="any" /> <link rel="icon" href="/favicon.ico" sizes="any" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" /> <link rel="icon" type="image/svg+xml" href="/icon.svg" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" /> <link rel="apple-touch-icon" href="/apple-touch-icon.png" />
@@ -25,7 +25,7 @@
href="/apple-splash-1290x2796.png" href="/apple-splash-1290x2796.png"
media="screen and (device-width: 430px) and (device-height: 932px) and (-webkit-device-pixel-ratio: 3)" media="screen and (device-width: 430px) and (device-height: 932px) and (-webkit-device-pixel-ratio: 3)"
/> />
<title>Walkup</title> <title>WalkUp</title>
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>

View File

@@ -26,7 +26,7 @@
/> />
</g> </g>
<text x="645" y="1848" text-anchor="middle" fill="#f4ede2" font-size="108" font-weight="700" letter-spacing="0.02em" font-family="Arial, Helvetica, sans-serif"> <text x="645" y="1848" text-anchor="middle" fill="#f4ede2" font-size="108" font-weight="700" letter-spacing="0.02em" font-family="Arial, Helvetica, sans-serif">
Walkup WalkUp
</text> </text>
<text x="645" y="1920" text-anchor="middle" fill="#b9c6d3" font-size="40" font-weight="500" letter-spacing="0.04em" font-family="Arial, Helvetica, sans-serif"> <text x="645" y="1920" text-anchor="middle" fill="#b9c6d3" font-size="40" font-weight="500" letter-spacing="0.04em" font-family="Arial, Helvetica, sans-serif">
Offline clip cache for the dugout Offline clip cache for the dugout

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -17,7 +17,7 @@ function getRouteDestinationLabel(pathname: string) {
case "/": case "/":
return "your dashboard"; return "your dashboard";
case "/library": case "/library":
return "walkup clips"; return "WalkUp clips";
case "/gameday": case "/gameday":
return "gameday"; return "gameday";
default: default:
@@ -30,7 +30,7 @@ function getNavbarPageLabel(pathname: string) {
case "/": case "/":
return "Home"; return "Home";
case "/library": case "/library":
return "Walkup Clips"; return "WalkUp Clips";
case "/gameday": case "/gameday":
return "Gameday"; return "Gameday";
case "/profile": case "/profile":
@@ -182,7 +182,7 @@ function TeamSelectionModal() {
<div className="d-grid gap-2 text-body-secondary"> <div className="d-grid gap-2 text-body-secondary">
<div>1. Sign in with TeamSnap.</div> <div>1. Sign in with TeamSnap.</div>
<div>2. Choose the team you want to manage.</div> <div>2. Choose the team you want to manage.</div>
<div>3. Continue into the dashboard, walkup clips, or game tools.</div> <div>3. Continue into the dashboard, WalkUp clips, or game tools.</div>
</div> </div>
</div> </div>
</div> </div>
@@ -204,7 +204,7 @@ class AppErrorBoundary extends Component<{ children: ReactNode }, { errorMessage
} }
componentDidCatch(error: unknown, errorInfo: ErrorInfo) { componentDidCatch(error: unknown, errorInfo: ErrorInfo) {
console.error("Walkup render error", error, errorInfo); console.error("WalkUp render error", error, errorInfo);
} }
render() { render() {
@@ -266,7 +266,7 @@ function ShellLayout() {
<i className="bi bi-person-walking" /> <i className="bi bi-person-walking" />
</span> </span>
<span className="d-flex flex-column gap-0"> <span className="d-flex flex-column gap-0">
<span className="fw-semibold fs-4 lh-1 text-white">Walkup</span> <span className="fw-semibold fs-4 lh-1 text-white">WalkUp</span>
{currentPageLabel ? ( {currentPageLabel ? (
<span className="navbar-text d-lg-none small lh-1 text-white-50">{currentPageLabel}</span> <span className="navbar-text d-lg-none small lh-1 text-white-50">{currentPageLabel}</span>
) : null} ) : null}
@@ -299,7 +299,7 @@ function ShellLayout() {
className={`nav-link btn btn-link${location.pathname === "/library" ? " active" : ""}`} className={`nav-link btn btn-link${location.pathname === "/library" ? " active" : ""}`}
onClick={() => goTo("/library")} onClick={() => goTo("/library")}
> >
Walkup Clips WalkUp Clips
</button> </button>
</li> </li>
<li className="nav-item"> <li className="nav-item">

View File

@@ -13,7 +13,7 @@ export function DashboardPage() {
<div className="card shadow-sm h-100"> <div className="card shadow-sm h-100">
<div className="card-body d-grid gap-3"> <div className="card-body d-grid gap-3">
<p className="text-uppercase small text-body-secondary mb-0">Library</p> <p className="text-uppercase small text-body-secondary mb-0">Library</p>
<h2 className="h4 mb-0">Manage walkup clips</h2> <h2 className="h4 mb-0">Manage WalkUp clips</h2>
<p className="text-body-secondary mb-0"> <p className="text-body-secondary mb-0">
Upload audio, trim clips, reorder them, and pin them to players before game day. Upload audio, trim clips, reorder them, and pin them to players before game day.
</p> </p>
@@ -31,7 +31,7 @@ export function DashboardPage() {
<p className="text-uppercase small text-body-secondary mb-0">Gameday</p> <p className="text-uppercase small text-body-secondary mb-0">Gameday</p>
<h2 className="h4 mb-0">Run the game-day view</h2> <h2 className="h4 mb-0">Run the game-day view</h2>
<p className="text-body-secondary mb-0"> <p className="text-body-secondary mb-0">
Review lineups, check availability, and play the right walkup clips during the game. Review lineups, check availability, and play the right WalkUp clips during the game.
</p> </p>
<div> <div>
<Link to="/gameday" className="btn btn-primary"> <Link to="/gameday" className="btn btn-primary">
@@ -53,7 +53,7 @@ export function DashboardPage() {
<div className="card shadow-sm h-100"> <div className="card shadow-sm h-100">
<div className="card-body d-grid gap-3"> <div className="card-body d-grid gap-3">
<p className="text-uppercase small text-body-secondary mb-0">Library</p> <p className="text-uppercase small text-body-secondary mb-0">Library</p>
<h2 className="h4 mb-0">Manage walkup clips</h2> <h2 className="h4 mb-0">Manage WalkUp clips</h2>
<p className="text-body-secondary mb-0"> <p className="text-body-secondary mb-0">
Upload audio, trim clips, reorder them, and pin them to players before game day. Upload audio, trim clips, reorder them, and pin them to players before game day.
</p> </p>
@@ -71,7 +71,7 @@ export function DashboardPage() {
<p className="text-uppercase small text-body-secondary mb-0">Gameday</p> <p className="text-uppercase small text-body-secondary mb-0">Gameday</p>
<h2 className="h4 mb-0">Run the game-day view</h2> <h2 className="h4 mb-0">Run the game-day view</h2>
<p className="text-body-secondary mb-0"> <p className="text-body-secondary mb-0">
Review lineups, check availability, and play the right walkup clips during the game. Review lineups, check availability, and play the right WalkUp clips during the game.
</p> </p>
<div> <div>
<Link to="/gameday" className="btn btn-primary"> <Link to="/gameday" className="btn btn-primary">

View File

@@ -410,11 +410,11 @@ function LibraryClips({
}); });
if (fallbackClipsQuery.isLoading) { if (fallbackClipsQuery.isLoading) {
return <div className="muted">Loading walkup clips...</div>; return <div className="muted">Loading WalkUp clips...</div>;
} }
if (!fallbackClipsQuery.data?.length) { if (!fallbackClipsQuery.data?.length) {
return <div className="muted">No walkup clips available for this player.</div>; return <div className="muted">No WalkUp clips available for this player.</div>;
} }
const clips = [...fallbackClipsQuery.data].sort((a, b) => { const clips = [...fallbackClipsQuery.data].sort((a, b) => {

View File

@@ -225,7 +225,7 @@ export function LibraryPage() {
<div className="gameday-loading-spinner spinner-border text-primary" aria-hidden="true" /> <div className="gameday-loading-spinner spinner-border text-primary" aria-hidden="true" />
<div className="gameday-loading-copy"> <div className="gameday-loading-copy">
<span className="gameday-loading-label">Waiting for TeamSnap</span> <span className="gameday-loading-label">Waiting for TeamSnap</span>
<strong>Loading walkup clips</strong> <strong>Loading WalkUp clips</strong>
<span className="muted">Teams, roster details, and clip data are being fetched.</span> <span className="muted">Teams, roster details, and clip data are being fetched.</span>
</div> </div>
</div> </div>
@@ -234,13 +234,13 @@ export function LibraryPage() {
} }
if (!walkup.isTeamSnap) { if (!walkup.isTeamSnap) {
return <section className="page-grid"><div className="panel">Reconnect with TeamSnap to manage walkup clips.</div></section>; return <section className="page-grid"><div className="panel">Reconnect with TeamSnap to manage WalkUp clips.</div></section>;
} }
if (!teamId || !playerId) { if (!teamId || !playerId) {
return ( return (
<section className="page-grid"> <section className="page-grid">
<div className="panel">No player record was found on the selected team, so this account cannot add walkup clips yet.</div> <div className="panel">No player record was found on the selected team, so this account cannot add WalkUp clips yet.</div>
</section> </section>
); );
} }
@@ -300,7 +300,7 @@ export function LibraryPage() {
/> />
))} ))}
{!clipsQuery.isLoading && !orderedClips.length ? ( {!clipsQuery.isLoading && !orderedClips.length ? (
<div className="muted">No walkup clips created yet. Open the modal to make the first one.</div> <div className="muted">No WalkUp clips created yet. Open the modal to make the first one.</div>
) : null} ) : null}
{deleteClipMutation.error instanceof Error ? <div className="muted">{deleteClipMutation.error.message}</div> : null} {deleteClipMutation.error instanceof Error ? <div className="muted">{deleteClipMutation.error.message}</div> : null}
</div> </div>
@@ -308,7 +308,7 @@ export function LibraryPage() {
<div className="panel"> <div className="panel">
<div className="section-header"> <div className="section-header">
<h2>Uploaded media</h2> <h2>Uploaded media</h2>
<div className="muted">Review the source files behind your walkup clips. You can rename or delete uploads here.</div> <div className="muted">Review the source files behind your WalkUp clips. You can rename or delete uploads here.</div>
</div> </div>
<div className="row walkup-panel-actions"> <div className="row walkup-panel-actions">
<button type="button" className="btn btn-outline-secondary" onClick={openManageMedia}> <button type="button" className="btn btn-outline-secondary" onClick={openManageMedia}>
@@ -451,7 +451,7 @@ function WalkupClipModal({
const resolveCreatedClip = async (assetId: number) => { const resolveCreatedClip = async (assetId: number) => {
setSourceProgress({ setSourceProgress({
label: "Loading clip", label: "Loading clip",
detail: "Refreshing the library with the generated walkup clip.", detail: "Refreshing the library with the generated WalkUp clip.",
percent: null, percent: null,
}); });
await Promise.all([ await Promise.all([
@@ -529,14 +529,14 @@ function WalkupClipModal({
setSourceProgress({ setSourceProgress({
label: "Creating clip", label: "Creating clip",
detail: "Creating a walkup clip from the selected media.", detail: "Creating a WalkUp clip from the selected media.",
percent: null, percent: null,
}); });
const clip = await api.createClip({ const clip = await api.createClip({
asset_id: Number(existingAssetId), asset_id: Number(existingAssetId),
external_team_id: teamId, external_team_id: teamId,
owner_external_player_id: playerId, owner_external_player_id: playerId,
label: draftLabel.trim() || "Walkup clip", label: draftLabel.trim() || "WalkUp clip",
start_ms: 0, start_ms: 0,
end_ms: DEFAULT_CLIP_LENGTH_MS, end_ms: DEFAULT_CLIP_LENGTH_MS,
}); });
@@ -548,7 +548,7 @@ function WalkupClipModal({
setDraftClip(clip); setDraftClip(clip);
setDraftStartMs(clip.start_ms); setDraftStartMs(clip.start_ms);
setDraftEndMs(clip.end_ms); setDraftEndMs(clip.end_ms);
setDraftLabel(clip.label || "Walkup clip"); setDraftLabel(clip.label || "WalkUp clip");
setStep("editor"); setStep("editor");
}, },
onError: () => { onError: () => {
@@ -605,7 +605,7 @@ function WalkupClipModal({
</button> </button>
</div> </div>
<div className="walkup-modal-body"> <div className="walkup-modal-body">
<nav aria-label="Walkup clip steps"> <nav aria-label="WalkUp clip steps">
<ol className="breadcrumb walkup-step-breadcrumb mb-0"> <ol className="breadcrumb walkup-step-breadcrumb mb-0">
<li className={`breadcrumb-item${step === "source" ? " active" : ""}`} aria-current={step === "source" ? "page" : undefined}> <li className={`breadcrumb-item${step === "source" ? " active" : ""}`} aria-current={step === "source" ? "page" : undefined}>
Source Source
@@ -618,7 +618,7 @@ function WalkupClipModal({
{step === "source" ? ( {step === "source" ? (
<form className="stack" onSubmit={handleSourceSubmit} aria-busy={createSourceMutation.isPending}> <form className="stack" onSubmit={handleSourceSubmit} aria-busy={createSourceMutation.isPending}>
<ul className="nav nav-tabs" role="tablist" aria-label="Walkup clip source"> <ul className="nav nav-tabs" role="tablist" aria-label="WalkUp clip source">
<li className="nav-item" role="presentation"> <li className="nav-item" role="presentation">
<button <button
id="walkup-upload-tab" id="walkup-upload-tab"
@@ -670,7 +670,7 @@ function WalkupClipModal({
className={`tab-pane fade${sourceMode === "upload" ? " show active" : ""}`} className={`tab-pane fade${sourceMode === "upload" ? " show active" : ""}`}
> >
<div className="stack"> <div className="stack">
<div className="muted">Upload a local audio file to create a new walkup clip.</div> <div className="muted">Upload a local audio file to create a new WalkUp clip.</div>
<label className="field"> <label className="field">
Media title Media title
<input <input
@@ -732,7 +732,7 @@ function WalkupClipModal({
className={`tab-pane fade${sourceMode === "existing" ? " show active" : ""}`} className={`tab-pane fade${sourceMode === "existing" ? " show active" : ""}`}
> >
<div className="stack"> <div className="stack">
<div className="muted">Pick an existing media file to turn into a walkup clip.</div> <div className="muted">Pick an existing media file to turn into a WalkUp clip.</div>
<label className="field"> <label className="field">
Existing media file Existing media file
<select <select
@@ -751,7 +751,7 @@ function WalkupClipModal({
{existingAssetId ? ( {existingAssetId ? (
<div className="panel-note">The clip will be created from the selected existing media file.</div> <div className="panel-note">The clip will be created from the selected existing media file.</div>
) : ( ) : (
<div className="muted">Choose one of the existing media files in this walkup media library.</div> <div className="muted">Choose one of the existing media files in this WalkUp media library.</div>
)} )}
</div> </div>
</div> </div>
@@ -878,7 +878,7 @@ function ManageUploadedMediaModal({
> >
<div className="walkup-modal-header"> <div className="walkup-modal-header">
<div> <div>
<p className="eyebrow mb-1">Walkup clips</p> <p className="eyebrow mb-1">WalkUp clips</p>
<h2 id="walkup-media-title" className="h3 mb-0"> <h2 id="walkup-media-title" className="h3 mb-0">
Manage uploaded media Manage uploaded media
</h2> </h2>
@@ -894,7 +894,7 @@ function ManageUploadedMediaModal({
</div> </div>
<div className="walkup-modal-body"> <div className="walkup-modal-body">
<div className="panel-note"> <div className="panel-note">
Rename or delete the uploaded media that backs your walkup clips. Existing clip edits stay in the clip view. Rename or delete the uploaded media that backs your WalkUp clips. Existing clip edits stay in the clip view.
</div> </div>
<div className="stack"> <div className="stack">
{assets.map((asset) => ( {assets.map((asset) => (
@@ -1264,7 +1264,7 @@ function WalkupClipEditorPanel({
mutationFn: async () => { mutationFn: async () => {
const trimmedLabel = label.trim(); const trimmedLabel = label.trim();
if (!trimmedLabel) { if (!trimmedLabel) {
throw new Error("Walkup clip name cannot be blank"); throw new Error("WalkUp clip name cannot be blank");
} }
if (endMs <= startMs) { if (endMs <= startMs) {
throw new Error("Clip end must be greater than start"); throw new Error("Clip end must be greater than start");
@@ -1312,11 +1312,11 @@ function WalkupClipEditorPanel({
<form className="stack" onSubmit={handleSubmit}> <form className="stack" onSubmit={handleSubmit}>
<div className="panel-note">{introText}</div> <div className="panel-note">{introText}</div>
<label className="field"> <label className="field">
Walkup clip name WalkUp clip name
<input <input
value={label} value={label}
onChange={(event) => setLabel(event.target.value)} onChange={(event) => setLabel(event.target.value)}
placeholder="Walkup clip name" placeholder="WalkUp clip name"
autoComplete="off" autoComplete="off"
/> />
</label> </label>

View File

@@ -30,7 +30,7 @@ export function SignInPage() {
<div className="card shadow-sm border-0"> <div className="card shadow-sm border-0">
<div className="card-body p-4 p-lg-5 d-grid gap-4"> <div className="card-body p-4 p-lg-5 d-grid gap-4">
<div className="d-grid gap-2"> <div className="d-grid gap-2">
<p className="text-uppercase small text-primary-emphasis mb-0">Walkup</p> <p className="text-uppercase small text-primary-emphasis mb-0">WalkUp</p>
<h1 className="h2 mb-0">Sign in</h1> <h1 className="h2 mb-0">Sign in</h1>
<p className="text-body-secondary mb-0">Use TeamSnap to continue into your team dashboard.</p> <p className="text-body-secondary mb-0">Use TeamSnap to continue into your team dashboard.</p>
</div> </div>

View File

@@ -41,8 +41,8 @@ export default defineConfig(({ mode }) => {
}, },
manifest: { manifest: {
id: "/", id: "/",
name: "Walkup", name: "WalkUp",
short_name: "Walkup", short_name: "WalkUp",
description: "Collaborative baseball walk-up songs.", description: "Collaborative baseball walk-up songs.",
theme_color: "#132238", theme_color: "#132238",
background_color: "#f4ede2", background_color: "#f4ede2",