Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions assets/css/tailwind.css
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,37 @@ mark {
transparent 4px
);
}
/* Scan sweep across the top of the queue / match-confirm panels. The band is a
repeating gradient whose period is one track width, painted on a double-width
element, so shifting exactly one period (-50%) loops with no seam: the next
band enters the left edge as the previous one leaves the right. Colour is
currentColor, so callers pick it with text-*. */
@keyframes tac-scan-sweep {
from {
transform: translateX(-50%);
}
to {
transform: translateX(0);
}
}
.tac-scan-sweep {
width: 200%;
background-image: repeating-linear-gradient(
90deg,
transparent 0,
transparent 12.5%,
currentColor 25%,
transparent 37.5%,
transparent 50%
);
animation: tac-scan-sweep 2s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
.tac-scan-sweep {
animation: none;
}
}

/* One-shot pulse for clip share buttons — toast is far from the click
target, so the button itself flashes amber + scales briefly. Used
by MatchHighlightsReel queue/featured share, HighlightCard, and
Expand Down
31 changes: 31 additions & 0 deletions components/MatchOptions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,37 @@ import SettingHeader from "~/components/match/SettingHeader.vue";
</FormItem>
</FormField>

<FormField v-slot="{ value }" name="veto_pick_timeout">
<FormItem>
<SettingHeader>{{
$t("match.options.advanced.veto_pick_timeout.label")
}}</SettingHeader>
<NumberField
class="gap-2"
:min="0"
:max="600"
:model-value="value"
@update:model-value="
(timeout) => {
form.setFieldValue('veto_pick_timeout', timeout);
}
"
>
<NumberFieldContent>
<NumberFieldDecrement />
<FormControl>
<NumberFieldInput />
</FormControl>
<NumberFieldIncrement />
</NumberFieldContent>
</NumberField>
<FormDescription>
{{ $t("match.options.advanced.veto_pick_timeout.range") }}
</FormDescription>
<FormMessage />
</FormItem>
</FormField>

<FormField v-slot="{ value }" name="round_restart_delay">
<FormItem>
<SettingHeader>{{
Expand Down
16 changes: 13 additions & 3 deletions components/draft-games/DraftClock.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ const props = withDefaults(
total?: number;
accent?: string;
pulse?: boolean;
compact?: boolean;
}>(),
{
total: 30,
accent: "var(--tac-amber)",
pulse: false,
compact: false,
},
);

Expand Down Expand Up @@ -67,7 +69,11 @@ const urgent = computed(() => remaining.value <= 6 && remaining.value > 0);
:class="{ pulse: pulse }"
:style="{ '--accent': accent }"
>
<svg viewBox="0 0 120 120" class="h-32 w-32 -rotate-90">
<svg
viewBox="0 0 120 120"
class="-rotate-90"
:class="compact ? 'h-16 w-16' : 'h-32 w-32'"
>
<circle
cx="60"
cy="60"
Expand Down Expand Up @@ -95,13 +101,17 @@ const urgent = computed(() => remaining.value <= 6 && remaining.value > 0);
<div class="absolute inset-0 grid place-items-center text-center">
<div>
<div
class="font-mono text-3xl font-bold tabular-nums leading-none"
:class="urgent ? 'text-destructive' : 'text-foreground'"
class="font-mono font-bold tabular-nums leading-none"
:class="[
urgent ? 'text-destructive' : 'text-foreground',
compact ? 'text-base' : 'text-3xl',
]"
>
<template v-if="deadline">{{ Math.ceil(remaining) }}</template>
<template v-else>—</template>
</div>
<div
v-if="!compact"
class="mt-1 font-mono text-[0.55rem] uppercase tracking-[0.28em] text-muted-foreground"
>
<slot>SEC</slot>
Expand Down
18 changes: 18 additions & 0 deletions components/match/MatchMapVeto.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import MapDisplay from "~/components/MapDisplay.vue";
import MapSelector from "~/components/match/MapSelector.vue";
import { Separator } from "~/components/ui/separator";
import MatchPicksDisplay from "~/components/match/MatchPicksDisplay.vue";
import DraftClock from "~/components/draft-games/DraftClock.vue";
</script>

<template>
Expand Down Expand Up @@ -49,6 +50,15 @@ import MatchPicksDisplay from "~/components/match/MatchPicksDisplay.vue";
class="shrink-0 font-sans uppercase tracking-[0.14em]"
>{{ pickType }}</Badge
>

<DraftClock
v-if="vetoPickDeadline"
class="shrink-0"
compact
:deadline="vetoPickDeadline"
:total="match.options.veto_pick_timeout"
:pulse="isPicking"
/>
</div>

<div
Expand Down Expand Up @@ -226,6 +236,7 @@ export default {
},
side: true,
type: true,
auto_picked: true,
match_lineup_id: true,
match_lineup: [
{},
Expand Down Expand Up @@ -413,6 +424,13 @@ export default {

return this.match.map_veto_type;
},
vetoPickDeadline() {
if (!this.match.options.veto_pick_timeout) {
return null;
}

return this.match.veto_pick_expires_at ?? null;
},
pickingLineupName() {
if (this.match.lineup_1.is_picking_map_veto) {
return this.match.lineup_1.name;
Expand Down
14 changes: 14 additions & 0 deletions components/match/MatchOptionsDisplay.vue
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,20 @@ const BooleanPill = defineComponent({
}}</dt>
<dd><BooleanPill :value="options.region_veto" /></dd>
</div>
<div class="settings-row">
<dt class="settings-row__label">{{
$t("match.options.veto_pick_timeout")
}}</dt>
<dd>
{{
options.veto_pick_timeout > 0
? $t("match.options.veto_pick_timeout_seconds", {
seconds: options.veto_pick_timeout,
})
: $t("common.disabled")
}}
</dd>
</div>
</dl>
</section>
</div>
Expand Down
24 changes: 24 additions & 0 deletions components/match/MatchPicksDisplay.vue
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ import cleanMapName from "~/utilities/cleanMapName";
: pick.type
}}
</span>
<span
v-if="pick.auto_picked"
class="auto-pill"
:title="$t('match.picks.auto_picked_description')"
>
{{ $t("match.picks.auto_picked") }}
</span>
</div>
</div>

Expand Down Expand Up @@ -400,6 +407,23 @@ export default {
backdrop-filter: blur(2px);
text-shadow: 0 1px 2px hsl(0 0% 0% / 0.7);
}

.auto-pill {
display: inline-flex;
align-items: center;
padding: 0.08rem 0.4rem;
border-radius: 9999px;
font-family: "Oxanium", ui-sans-serif, system-ui, sans-serif;
font-size: 0.52rem;
font-weight: 700;
letter-spacing: 0.16em;
line-height: 1;
text-transform: uppercase;
color: hsl(var(--muted-foreground));
background: hsl(0 0% 0% / 0.45);
border: 1px solid hsl(var(--border) / 0.6);
backdrop-filter: blur(2px);
}
.pill-pick {
color: hsl(142 76% 58%);
border: 1px solid hsl(142 76% 58% / 0.55);
Expand Down
18 changes: 18 additions & 0 deletions components/match/MatchRegionVeto.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Check } from "lucide-vue-next";
import { Spinner } from "~/components/ui/spinner";
import { FormControl } from "~/components/ui/form";
import { Separator } from "~/components/ui/separator";
import DraftClock from "~/components/draft-games/DraftClock.vue";
import {
vetoTileClasses,
vetoTileHoverClasses,
Expand Down Expand Up @@ -52,6 +53,15 @@ import {
class="shrink-0 font-sans uppercase tracking-[0.14em]"
>{{ $t("match.region_veto.ban_label") }}</Badge
>

<DraftClock
v-if="vetoPickDeadline"
class="shrink-0"
compact
:deadline="vetoPickDeadline"
:total="match.options.veto_pick_timeout"
:pulse="isPicking"
/>
</div>

<div
Expand Down Expand Up @@ -246,6 +256,7 @@ export default {
},
{
region: true,
auto_picked: true,
},
],
}),
Expand Down Expand Up @@ -316,6 +327,13 @@ export default {
}
return "";
},
vetoPickDeadline() {
if (!this.match.options.veto_pick_timeout) {
return null;
}

return this.match.veto_pick_expires_at ?? null;
},
isPicking() {
if (this.canOverride && this.override) {
return true;
Expand Down
2 changes: 1 addition & 1 deletion components/matchmaking/Matchmaking.vue
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ function releaseSwapHeight(el: Element): void {
class="pointer-events-none absolute left-0 right-0 top-0 h-[2px] overflow-hidden"
>
<span
class="block h-full w-1/2 bg-gradient-to-r from-transparent via-[hsl(var(--tac-amber))] to-transparent animate-loading-bar"
class="tac-scan-sweep block h-full text-[hsl(var(--tac-amber))]"
></span>
</span>

Expand Down
4 changes: 2 additions & 2 deletions components/matchmaking/MatchmakingConfirm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ import { AlertDialog, AlertDialogContent } from "@/components/ui/alert-dialog";
class="pointer-events-none absolute left-0 right-0 top-0 h-[2px] overflow-hidden"
>
<span
class="block h-full w-1/2 bg-gradient-to-r from-transparent to-transparent animate-loading-bar"
class="tac-scan-sweep block h-full"
:class="
isCritical ? 'via-destructive' : 'via-[hsl(var(--tac-amber))]'
isCritical ? 'text-destructive' : 'text-[hsl(var(--tac-amber))]'
"
></span>
</span>
Expand Down
42 changes: 42 additions & 0 deletions components/tournament/TournamentStageForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,37 @@ import { $ } from "~/generated/zeus";
<FormMessage />
</FormItem>
</FormField>

<FormField v-slot="{ value }" name="veto_pick_timeout">
<FormItem>
<SettingHeader>{{
$t("match.options.advanced.veto_pick_timeout.label")
}}</SettingHeader>
<NumberField
class="gap-2"
:min="0"
:max="600"
:model-value="value"
@update:model-value="
(timeout) => {
form.setFieldValue('veto_pick_timeout', timeout);
}
"
>
<NumberFieldContent>
<NumberFieldDecrement />
<FormControl>
<NumberFieldInput />
</FormControl>
<NumberFieldIncrement />
</NumberFieldContent>
</NumberField>
<FormDescription>
{{ $t("match.options.advanced.veto_pick_timeout.range") }}
</FormDescription>
<FormMessage />
</FormItem>
</FormField>
</div>
</Card>

Expand Down Expand Up @@ -965,6 +996,7 @@ export default {
final_map_advantage: z.number().min(0).default(0),
// Advanced settings (5 overridable fields)
tv_delay: z.number().min(0).max(120).default(115),
veto_pick_timeout: z.number().min(0).max(600).default(60),
region_veto: z.boolean().default(true),
regions: z.string().array().default([]),
check_in_setting: z
Expand Down Expand Up @@ -1277,6 +1309,10 @@ export default {
stage.options?.tv_delay ??
this.tournament?.options?.tv_delay ??
115,
veto_pick_timeout:
stage.options?.veto_pick_timeout ??
this.tournament?.options?.veto_pick_timeout ??
60,
region_veto:
stage.options?.region_veto ??
this.tournament?.options?.region_veto ??
Expand Down Expand Up @@ -1372,6 +1408,7 @@ export default {
const options = this.tournament.options;
this.form.setValues({
tv_delay: options.tv_delay ?? 115,
veto_pick_timeout: options.veto_pick_timeout ?? 60,
region_veto: options.region_veto ?? true,
regions: options.regions ?? [],
check_in_setting:
Expand Down Expand Up @@ -1403,6 +1440,7 @@ export default {

if (
form.tv_delay !== tournamentOptions.tv_delay ||
form.veto_pick_timeout !== tournamentOptions.veto_pick_timeout ||
form.region_veto !== tournamentOptions.region_veto ||
form.check_in_setting !== tournamentOptions.check_in_setting ||
form.ready_setting !== tournamentOptions.ready_setting ||
Expand Down Expand Up @@ -1438,6 +1476,7 @@ export default {
variables: {
id: matchOptionsId,
tv_delay: form.tv_delay,
veto_pick_timeout: form.veto_pick_timeout,
region_veto: form.region_veto,
regions: form.regions || [],
check_in_setting: form.check_in_setting,
Expand All @@ -1464,6 +1503,7 @@ export default {
},
_set: {
tv_delay: $("tv_delay", "Int!"),
veto_pick_timeout: $("veto_pick_timeout", "Int!"),
region_veto: $("region_veto", "Boolean!"),
regions: $("regions", "[String!]!"),
check_in_setting: $(
Expand Down Expand Up @@ -1508,6 +1548,7 @@ export default {
const { data } = await (this as any).$apollo.mutate({
variables: {
tv_delay: form.tv_delay,
veto_pick_timeout: form.veto_pick_timeout,
region_veto: form.region_veto,
regions: form.regions || [],
check_in_setting: form.check_in_setting,
Expand All @@ -1531,6 +1572,7 @@ export default {
{
object: {
tv_delay: $("tv_delay", "Int!"),
veto_pick_timeout: $("veto_pick_timeout", "Int!"),
region_veto: $("region_veto", "Boolean!"),
regions: $("regions", "[String!]!"),
check_in_setting: $(
Expand Down
Loading