slop
This commit is contained in:
+30
-4
@@ -5065,11 +5065,26 @@ function noOpponentTooltip(match, roundLabel) {
|
|||||||
// threshold pans (and suppresses the click). Move/up live on the window so a fast
|
// threshold pans (and suppresses the click). Move/up live on the window so a fast
|
||||||
// drag keeps panning even when the cursor leaves the canvas.
|
// drag keeps panning even when the cursor leaves the canvas.
|
||||||
function BracketViewport({ children }) {
|
function BracketViewport({ children }) {
|
||||||
|
const containerRef = useRef(null)
|
||||||
const ref = useRef(null)
|
const ref = useRef(null)
|
||||||
|
const [fsActive, setFsActive] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handler = () => setFsActive(Boolean(document.fullscreenElement))
|
||||||
|
document.addEventListener('fullscreenchange', handler)
|
||||||
|
return () => document.removeEventListener('fullscreenchange', handler)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const toggleFs = (event) => {
|
||||||
|
event.stopPropagation()
|
||||||
|
if (document.fullscreenElement) document.exitFullscreen()
|
||||||
|
else containerRef.current?.requestFullscreen()
|
||||||
|
}
|
||||||
|
|
||||||
const onPointerDown = (event) => {
|
const onPointerDown = (event) => {
|
||||||
const el = ref.current
|
const el = ref.current
|
||||||
if (!el || event.button !== 0) return
|
if (!el || event.button !== 0) return
|
||||||
|
if (event.target.closest('[data-fs-btn]')) return
|
||||||
const start = { x: event.clientX, y: event.clientY, sl: el.scrollLeft, st: el.scrollTop, moved: false }
|
const start = { x: event.clientX, y: event.clientY, sl: el.scrollLeft, st: el.scrollTop, moved: false }
|
||||||
bracketPan.dragged = false
|
bracketPan.dragged = false
|
||||||
|
|
||||||
@@ -5102,8 +5117,19 @@ function BracketViewport({ children }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bracket-viewport" onPointerDown={onPointerDown} ref={ref}>
|
<div className="bracket-fs-container" ref={containerRef}>
|
||||||
{children}
|
<div className="bracket-viewport" onPointerDown={onPointerDown} ref={ref}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
className="bracket-fs-btn"
|
||||||
|
data-fs-btn=""
|
||||||
|
onClick={toggleFs}
|
||||||
|
title={fsActive ? 'Exit fullscreen' : 'Fullscreen'}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
{fsActive ? '✕' : '⛶'}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -5322,7 +5348,7 @@ function TournamentStandings({ standings }) {
|
|||||||
function TournamentListColumn({ column, navigate }) {
|
function TournamentListColumn({ column, navigate }) {
|
||||||
const [collapsed, setCollapsed] = useState(false)
|
const [collapsed, setCollapsed] = useState(false)
|
||||||
return (
|
return (
|
||||||
<div className="tournament-round-column">
|
<div className="tournament-list-column">
|
||||||
<button
|
<button
|
||||||
aria-expanded={!collapsed}
|
aria-expanded={!collapsed}
|
||||||
className="mb-3 flex items-center justify-center gap-1.5 text-xs font-semibold uppercase tracking-wide text-text-muted transition hover:text-text"
|
className="mb-3 flex items-center justify-center gap-1.5 text-xs font-semibold uppercase tracking-wide text-text-muted transition hover:text-text"
|
||||||
@@ -5333,7 +5359,7 @@ function TournamentListColumn({ column, navigate }) {
|
|||||||
<span aria-hidden="true" className={`bracket-caret${collapsed ? ' is-collapsed' : ''}`}>▾</span>
|
<span aria-hidden="true" className={`bracket-caret${collapsed ? ' is-collapsed' : ''}`}>▾</span>
|
||||||
</button>
|
</button>
|
||||||
{collapsed ? null : (
|
{collapsed ? null : (
|
||||||
<div className="flex flex-col gap-3">
|
<div className="grid grid-cols-2 gap-3">
|
||||||
{column.matches.map((match) => (
|
{column.matches.map((match) => (
|
||||||
<TournamentMatchCard
|
<TournamentMatchCard
|
||||||
key={`${match.type_bracket}-${match.match_id}`}
|
key={`${match.type_bracket}-${match.match_id}`}
|
||||||
|
|||||||
@@ -884,6 +884,52 @@ h3 {
|
|||||||
margin-left: calc(50% - 42.5vw);
|
margin-left: calc(50% - 42.5vw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bracket-fs-container {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bracket-fs-container:fullscreen {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: var(--color-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bracket-fs-container:fullscreen .bracket-viewport {
|
||||||
|
flex: 1;
|
||||||
|
max-height: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bracket-fs-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.5rem;
|
||||||
|
right: 0.5rem;
|
||||||
|
z-index: 10;
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
background: color-mix(in srgb, var(--color-surface) 85%, transparent);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color 0.15s;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bracket-fs-btn:hover {
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* List-style column inside the bracket viewport (Swiss / group rounds).
|
||||||
|
Two cards side by side; wider than the 200px bracket column. */
|
||||||
|
.tournament-list-column {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
display: flex;
|
||||||
|
min-width: 440px;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
.bracket-caret {
|
.bracket-caret {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 1.35rem;
|
font-size: 1.35rem;
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ function isAllowedApiUrl(req) {
|
|||||||
|
|
||||||
if (req.method !== 'GET' && req.method !== 'HEAD') return false
|
if (req.method !== 'GET' && req.method !== 'HEAD') return false
|
||||||
|
|
||||||
|
if (url.pathname === '/api/tss/tournaments') return true
|
||||||
|
if (/^\/api\/tss\/tournaments\/[^/]+$/.test(url.pathname)) return true
|
||||||
|
|
||||||
if (url.pathname === '/api/tss/leaderboard/teams') {
|
if (url.pathname === '/api/tss/leaderboard/teams') {
|
||||||
const keys = [...params.keys()]
|
const keys = [...params.keys()]
|
||||||
const limit = Number(params.get('limit') || 100)
|
const limit = Number(params.get('limit') || 100)
|
||||||
|
|||||||
Reference in New Issue
Block a user