big updates :D

This commit is contained in:
headpatsyou 2026-01-09 21:47:42 +00:00
parent 0bf0ba54a8
commit 3abecb0133
4 changed files with 85 additions and 81 deletions

View file

@ -128,37 +128,37 @@ Os atletas, o seu pessoal de apoio e outros que estão sujeitos às regras antid
#### Direitos dos Atletas #### Direitos dos Atletas
"Cada atleta tem o direito ao desporto limpo!" ***"Cada atleta tem o direito ao desporto limpo!"***
Garantir que os atletas estão conscientes dos seus direitos e que estes direitos são respeitados é vital para o sucesso do desporto limpo. O Comité de Atletas da AMA (agora Conselho de Atletas) redigiu a Lei dos Direitos Antidopagem dos Atletas (Lei). Esta Lei é composta por duas partes. A primeira parte estabelece direitos que se encontram no Código e nas Normas Internacionais. A segunda parte estabelece direitos de atletas recomendados que não se encontram no Código ou nas Normas Internacionais, mas são direitos que os atletas recomendam que as Organizações Antidopagem (OAD) adotem como melhores práticas. Garantir que os atletas estão conscientes dos seus direitos e que estes direitos são respeitados é vital para o sucesso do desporto limpo. O Comité de Atletas da AMA (agora Conselho de Atletas) redigiu a [Lei dos Direitos Antidopagem dos Atletas](https://www.wada-ama.org/en/resources/athletes-anti-doping-rights-act) (Lei). Esta Lei é composta por duas partes. A primeira parte estabelece direitos que se encontram no Código e nas Normas Internacionais. A segunda parte estabelece direitos de atletas recomendados que não se encontram no Código ou nas Normas Internacionais, mas são direitos que os atletas recomendam que as Organizações Antidopagem (OAD) adotem como melhores práticas.
Os direitos dos atletas descritos no Código incluem: Os direitos dos atletas descritos no Código incluem:
Oportunidades iguais na sua busca pelo desporto, livre da participação de outros atletas que fazem dopagem * Oportunidades iguais na sua busca pelo desporto, livre da participação de outros atletas que fazem dopagem
Programas de testes equitativos e justos * Programas de testes equitativos e justos
Um processo de candidatura para Autorização de Uso Terapêutico (AUT) * Um processo de candidatura para Autorização de Uso Terapêutico (AUT)
Ser ouvido, ter uma audiência justa dentro de um prazo razoável por um painel de audiência justo, imparcial e operacionalmente independente, com uma decisão fundamentada oportuna que inclua especificamente uma explicação das razões da decisão * Ser ouvido, ter uma audiência justa dentro de um prazo razoável por um painel de audiência justo, imparcial e operacionalmente independente, com uma decisão fundamentada oportuna que inclua especificamente uma explicação das razões da decisão
Direito de recorrer da decisão da audiência * Direito de recorrer da decisão da audiência
Qualquer OAD que tenha jurisdição sobre eles será responsável pelas suas ações e um atleta terá a capacidade de denunciar qualquer questão de conformidade * Qualquer OAD que tenha jurisdição sobre eles será responsável pelas suas ações e um atleta terá a capacidade de denunciar qualquer questão de conformidade
Capacidade de denunciar Violações das Regras Antidopagem (VRA) através de um mecanismo anónimo e não ser sujeito a ameaças ou intimidação * Capacidade de denunciar Violações das Regras Antidopagem (VRA) através de um mecanismo anónimo e não ser sujeito a ameaças ou intimidação
Receber educação antidopagem * Receber educação antidopagem
Tratamento justo das suas informações pessoais pelas OAD de acordo com a Norma Internacional para a Proteção da Privacidade e Informação Pessoal (NIPPIP) e qualquer lei local aplicável * Tratamento justo das suas informações pessoais pelas OAD de acordo com a Norma Internacional para a Proteção da Privacidade e Informação Pessoal (NIPPIP) e qualquer lei local aplicável
Procurar indemnização de outro atleta cujas ações tenham prejudicado esse atleta através da prática de uma VRA * Procurar indemnização de outro atleta cujas ações tenham prejudicado esse atleta através da prática de uma VRA
Durante o processo de recolha de amostras, direito a: * Durante o processo de recolha de amostras, direito a:
Ver a identificação do Oficial de Controlo de Dopagem (OCD) * Ver a identificação do Oficial de Controlo de Dopagem (OCD)
Solicitar informações adicionais sobre o processo de recolha de amostras, sobre a autoridade sob a qual será realizado e sobre o tipo de recolha de amostras * Solicitar informações adicionais sobre o processo de recolha de amostras, sobre a autoridade sob a qual será realizado e sobre o tipo de recolha de amostras
Hidratar-se * Hidratar-se
Ser acompanhado por um representante e, se disponível, um intérprete * Ser acompanhado por um representante e, se disponível, um intérprete
Solicitar um atraso na apresentação na estação de controlo de dopagem por razões válidas (Norma Internacional para Testes e Investigações Art. 5.4.4) * Solicitar um atraso na apresentação na estação de controlo de dopagem por razões válidas (Norma Internacional para Testes e Investigações Art. 5.4.4)
Solicitar modificações para atletas com deficiências (se aplicável) * Solicitar modificações para atletas com deficiências (se aplicável)
Ser informado dos seus direitos e responsabilidades * Ser informado dos seus direitos e responsabilidades
Receber uma cópia dos registos do processo * Receber uma cópia dos registos do processo
Ter proteções adicionais para "pessoas protegidas" devido à sua idade ou falta de capacidade legal * Ter proteções adicionais para "pessoas protegidas" devido à sua idade ou falta de capacidade legal
Solicitar e assistir à análise da amostra B (no caso de um Resultado Analítico Adverso) * Solicitar e assistir à análise da amostra B (no caso de um Resultado Analítico Adverso)
Responsabilidades dos Atletas #### Responsabilidades dos Atletas
Os direitos dos atletas ao desporto limpo vêm com responsabilidades correspondentes, e os atletas podem ser testados dentro e fora de competição, a qualquer momento, em qualquer lugar e sem aviso prévio. Os direitos dos atletas ao desporto limpo vêm com responsabilidades correspondentes, e os atletas podem ser testados dentro e fora de competição, a qualquer momento, em qualquer lugar e sem aviso prévio.
@ -192,22 +192,22 @@ Responsabilidades do Pessoal de Apoio ao Atleta
As responsabilidades do pessoal de apoio ao atleta ao abrigo do Código incluem: As responsabilidades do pessoal de apoio ao atleta ao abrigo do Código incluem:
Usar a sua influência nos valores e comportamentos dos atletas para promover comportamentos de desporto limpo * Usar a sua influência nos valores e comportamentos dos atletas para promover comportamentos de desporto limpo
Conhecer e cumprir todas as políticas e regras antidopagem aplicáveis, incluindo as Regras Antidopagem da IPF (em conformidade com o Código) * Conhecer e cumprir todas as políticas e regras antidopagem aplicáveis, incluindo as Regras Antidopagem da IPF (em conformidade com o Código)
Cooperar com o programa de controlo de dopagem dos atletas * Cooperar com o programa de controlo de dopagem dos atletas
Cooperar com OAD que investigam Violações das Regras Antidopagem (VRA) * Cooperar com OAD que investigam Violações das Regras Antidopagem (VRA)
Informar a FI relevante e/ou ONAD se cometeram uma VRA nos últimos 10 anos * Informar a FI relevante e/ou ONAD se cometeram uma VRA nos últimos 10 anos
Abster-se de possuir uma substância proibida (ou um método proibido)*, administrar tal substância ou método a um atleta, traficar, encobrir uma violação das regras antidopagem (VRA) ou outras formas de cumplicidade e associar-se com uma pessoa condenada por dopagem (associação proibida). Estas são VRA aplicáveis ao pessoal de apoio ao atleta ao abrigo do Artigo 2 do Código Mundial Antidopagem e Artigo 2 das Regras Antidopagem da IPF. * Abster-se de possuir uma substância proibida (ou um método proibido)*, administrar tal substância ou método a um atleta, traficar, encobrir uma violação das regras antidopagem (VRA) ou outras formas de cumplicidade e associar-se com uma pessoa condenada por dopagem (associação proibida). Estas são VRA aplicáveis ao pessoal de apoio ao atleta ao abrigo do Artigo 2 do Código Mundial Antidopagem e Artigo 2 das Regras Antidopagem da IPF.
* A menos que o pessoal de apoio ao atleta possa estabelecer que a posse é consistente com uma AUT concedida a um atleta ou outra justificação aceitável. Justificação aceitável incluiria, por exemplo, um médico de equipa que transporta substâncias proibidas para lidar com situações agudas e de emergência. *A menos que o pessoal de apoio ao atleta possa estabelecer que a posse é consistente com uma AUT concedida a um atleta ou outra justificação aceitável. Justificação aceitável incluiria, por exemplo, um médico de equipa que transporta substâncias proibidas para lidar com situações agudas e de emergência.
Recomendação da IPF ao Pessoal de Apoio ao Atleta Recomendação da IPF ao Pessoal de Apoio ao Atleta
Aqui estão algumas formas como o pessoal de apoio ao atleta pode apoiar os seus atletas na sua educação sobre desporto limpo: Aqui estão algumas formas como o pessoal de apoio ao atleta pode apoiar os seus atletas na sua educação sobre desporto limpo:
Partilhar a Lei dos Direitos Antidopagem dos Atletas com o seu atleta - Partilhar a Lei dos Direitos Antidopagem dos Atletas com o seu atleta
Registar-se e fazer um curso adequado para si na plataforma ADEL da AMA - Registar-se e fazer um curso adequado para si na plataforma ADEL da AMA
Contactar ipfantidoping@cces.ca para quaisquer questões que possa ter - Contactar ipfantidoping@cces.ca para quaisquer questões que possa ter

View file

@ -129,7 +129,7 @@ p { font-size: 1rem; line-height: 1.6; color: var(--foreground); }
.markdown-content h6 { .markdown-content h6 {
margin-top: 1.25rem; margin-top: 1.25rem;
margin-bottom: 0.75rem; margin-bottom: 0.75rem;
scroll-margin-top: 100px; /* Account for header + subnav on mobile */ scroll-margin-top: 110px; /* Account for header + subnav on mobile + padding */
overflow-wrap: break-word; overflow-wrap: break-word;
word-wrap: break-word; word-wrap: break-word;
} }
@ -141,7 +141,7 @@ p { font-size: 1rem; line-height: 1.6; color: var(--foreground); }
.markdown-content h4, .markdown-content h4,
.markdown-content h5, .markdown-content h5,
.markdown-content h6 { .markdown-content h6 {
scroll-margin-top: 140px; /* More space on desktop */ scroll-margin-top: 150px; /* More space on desktop + padding */
} }
} }
.markdown-content p, .markdown-content ul, .markdown-content ol { .markdown-content p, .markdown-content ul, .markdown-content ol {
@ -574,8 +574,19 @@ p { font-size: 1rem; line-height: 1.6; color: var(--foreground); }
/* Table of Contents */ /* Table of Contents */
.toc-container { .toc-container {
position: sticky; position: sticky;
top: 110px; /* Below header + subnav */ /* Account for header (~66px) + subnav (~50px) + padding */
top: 160px;
align-self: start; align-self: start;
z-index: 30;
}
/* Mobile: ToC is not sticky, flows in document */
@media (max-width: 767px) {
.toc-container {
position: relative;
top: 0;
margin-bottom: 1.5rem;
}
} }
.toc-toggle { .toc-toggle {
@ -625,6 +636,7 @@ p { font-size: 1rem; line-height: 1.6; color: var(--foreground); }
.toc-nav { .toc-nav {
display: block; display: block;
/* Account for header + subnav + padding (120px top + some bottom margin) */
max-height: calc(100vh - 140px); max-height: calc(100vh - 140px);
overflow-y: auto; overflow-y: auto;
padding: 1rem; padding: 1rem;

View file

@ -3,6 +3,14 @@ import React, { useEffect, useMemo, useState } from "react";
type Row = Record<string, string>; type Row = Record<string, string>;
type LiftType = "Squat" | "Bench" | "Deadlift";
const liftTypeLabels: Record<LiftType, string> = {
Squat: "Agachamento",
Bench: "Supino",
Deadlift: "Deadlift",
};
const ResultCell = ({ value, isTotal = false }: { value: string | undefined; isTotal?: boolean }) => { const ResultCell = ({ value, isTotal = false }: { value: string | undefined; isTotal?: boolean }) => {
if (!value) return <td className="border p-2"></td>; if (!value) return <td className="border p-2"></td>;
@ -42,9 +50,7 @@ export function ResultsTable() {
const [selectedMeet, setSelectedMeet] = useState<string>(""); const [selectedMeet, setSelectedMeet] = useState<string>("");
const [rows, setRows] = useState<Row[]>([]); const [rows, setRows] = useState<Row[]>([]);
const [query, setQuery] = useState<string>(""); const [query, setQuery] = useState<string>("");
const [squatCol, setSquatCol] = useState<string>("Squat3Kg"); const [selectedLiftType, setSelectedLiftType] = useState<LiftType>("Squat");
const [benchCol, setBenchCol] = useState<string>("Bench3Kg");
const [deadliftCol, setDeadliftCol] = useState<string>("Deadlift3Kg");
useEffect(() => { useEffect(() => {
(async () => { (async () => {
@ -68,14 +74,13 @@ export function ResultsTable() {
return rows.filter((r) => (r["Name"] || "").toLowerCase().includes(q)); return rows.filter((r) => (r["Name"] || "").toLowerCase().includes(q));
}, [rows, query]); }, [rows, query]);
const attemptOptions = (prefix: string) => { // Get the column keys for the three attempts of the selected lift type
const labelPrefix = prefix === "Squat" ? "Agachamento" : prefix === "Bench" ? "Supino" : "Deadlift"; const getAttemptColumns = (liftType: LiftType) => {
const opts = [1, 2, 3, 4] return [1, 2, 3].map((n) => `${liftType}${n}Kg`);
.map((n) => ({ key: `${prefix}${n}Kg`, label: `${labelPrefix} ${n}` }))
.filter((o) => rows.some((r) => o.key in r));
return opts;
}; };
const attemptColumns = getAttemptColumns(selectedLiftType);
return ( return (
<section aria-labelledby="results-title"> <section aria-labelledby="results-title">
<h1 id="results-title" className="text-2xl font-bold">Resultados</h1> <h1 id="results-title" className="text-2xl font-bold">Resultados</h1>
@ -106,32 +111,19 @@ export function ResultsTable() {
onChange={(e) => setQuery(e.target.value)} onChange={(e) => setQuery(e.target.value)}
/> />
</label> </label>
<div className="grid grid-cols-3 gap-2" aria-label="Seleção de tentativas"> <label className="block">
<label> <span className="block font-semibold">Tipo de levantamento</span>
<span className="block font-semibold">Agachamento</span> <select
<select className="mt-1 w-full border p-2" value={squatCol} onChange={(e) => setSquatCol(e.target.value)}> className="mt-1 w-full border p-2"
{attemptOptions("Squat").map((o) => ( aria-label="Selecionar tipo de levantamento"
<option key={o.key} value={o.key}>{o.label}</option> value={selectedLiftType}
))} onChange={(e) => setSelectedLiftType(e.target.value as LiftType)}
</select> >
</label> {(Object.keys(liftTypeLabels) as LiftType[]).map((type) => (
<label> <option key={type} value={type}>{liftTypeLabels[type]}</option>
<span className="block font-semibold">Supino</span> ))}
<select className="mt-1 w-full border p-2" value={benchCol} onChange={(e) => setBenchCol(e.target.value)}> </select>
{attemptOptions("Bench").map((o) => ( </label>
<option key={o.key} value={o.key}>{o.label}</option>
))}
</select>
</label>
<label>
<span className="block font-semibold">Deadlift</span>
<select className="mt-1 w-full border p-2" value={deadliftCol} onChange={(e) => setDeadliftCol(e.target.value)}>
{attemptOptions("Deadlift").map((o) => (
<option key={o.key} value={o.key}>{o.label}</option>
))}
</select>
</label>
</div>
</div> </div>
<div className="mt-6 overflow-x-auto" role="region" aria-label="Tabela de resultados"> <div className="mt-6 overflow-x-auto" role="region" aria-label="Tabela de resultados">
@ -142,9 +134,9 @@ export function ResultsTable() {
{(["Place","Name","Sex","Age","Equipment","Division","Bodyweight (kg)"] as const).map((h) => ( {(["Place","Name","Sex","Age","Equipment","Division","Bodyweight (kg)"] as const).map((h) => (
<th key={h} scope="col" className="border p-2 text-left">{h}</th> <th key={h} scope="col" className="border p-2 text-left">{h}</th>
))} ))}
<th scope="col" className="border p-2 text-left">Agachamento</th> <th scope="col" className="border p-2 text-left">{liftTypeLabels[selectedLiftType]} 1</th>
<th scope="col" className="border p-2 text-left">Supino</th> <th scope="col" className="border p-2 text-left">{liftTypeLabels[selectedLiftType]} 2</th>
<th scope="col" className="border p-2 text-left">Deadlift</th> <th scope="col" className="border p-2 text-left">{liftTypeLabels[selectedLiftType]} 3</th>
{(["Total (kg)","GLPoints"] as const).map((h) => ( {(["Total (kg)","GLPoints"] as const).map((h) => (
<th key={h} scope="col" className="border p-2 text-left">{h}</th> <th key={h} scope="col" className="border p-2 text-left">{h}</th>
))} ))}
@ -160,9 +152,9 @@ export function ResultsTable() {
<td className="border p-2">{r["Equipment"]}</td> <td className="border p-2">{r["Equipment"]}</td>
<td className="border p-2">{r["Division"]}</td> <td className="border p-2">{r["Division"]}</td>
<td className="border p-2">{r["BodyweightKg"]}</td> <td className="border p-2">{r["BodyweightKg"]}</td>
<ResultCell value={r[squatCol]} /> <ResultCell value={r[attemptColumns[0]]} />
<ResultCell value={r[benchCol]} /> <ResultCell value={r[attemptColumns[1]]} />
<ResultCell value={r[deadliftCol]} /> <ResultCell value={r[attemptColumns[2]]} />
<ResultCell value={r["TotalKg"]} isTotal /> <ResultCell value={r["TotalKg"]} isTotal />
<ResultCell value={r["GLPoints"]} isTotal /> <ResultCell value={r["GLPoints"]} isTotal />
</tr> </tr>

View file

@ -13,7 +13,7 @@ export function TableOfContents({ headings }: { headings: Heading[] }) {
const getOffset = useCallback(() => { const getOffset = useCallback(() => {
const header = document.querySelector(".app-header"); const header = document.querySelector(".app-header");
const subnav = document.querySelector(".subnav-bar"); const subnav = document.querySelector(".subnav-bar");
let offset = 32; let offset = 16; // Padding for extra safety margin
if (header) offset += header.getBoundingClientRect().height; if (header) offset += header.getBoundingClientRect().height;
if (subnav) offset += subnav.getBoundingClientRect().height; if (subnav) offset += subnav.getBoundingClientRect().height;
return offset; return offset;
@ -36,7 +36,7 @@ export function TableOfContents({ headings }: { headings: Heading[] }) {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
// If this heading is at or above our threshold, it's the current one // If this heading is at or above our threshold, it's the current one
if (rect.top <= offset + 10) { if (rect.top <= offset + 5) {
found = headings[i].id; found = headings[i].id;
} else { } else {
// First heading that's below threshold - stop here // First heading that's below threshold - stop here
@ -45,7 +45,7 @@ export function TableOfContents({ headings }: { headings: Heading[] }) {
} }
// If at very top of page, select first heading // If at very top of page, select first heading
if (!found && window.scrollY < 100 && headings.length > 0) { if (!found && window.scrollY < offset + 50 && headings.length > 0) {
found = headings[0].id; found = headings[0].id;
} }