Fix heading anchor alignment with heading text and translate its accessibility label (#4281)

This commit is contained in:
Greg Bergé
2026-05-29 09:38:47 +02:00
committed by GitHub
parent 0ffb74a6f8
commit 2885a137f8
44 changed files with 64 additions and 8 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"gitbook": patch
---
Fix heading anchor alignment with heading text and translate its accessibility label.
+1 -1
View File
@@ -7,7 +7,7 @@
"devDependencies": {
"@biomejs/biome": "^1.9.4",
"@changesets/cli": "^2.31.0",
"turbo": "^2.9.14",
"turbo": "^2.9.15",
"vercel": "50.37.3",
},
},
@@ -1,6 +1,8 @@
import type { DocumentBlockExpandable } from '@gitbook/api';
import { Icon } from '@gitbook/icons';
import { getSpaceLanguage, tString } from '@/intl/server';
import { defaultLanguage } from '@/intl/translations';
import { getNodeFragmentByType } from '@/lib/document';
import { tcls } from '@/lib/tailwind';
@@ -10,7 +12,7 @@ import { Blocks } from '../Blocks';
import { Inlines } from '../Inlines';
import { Details } from './Details';
export function Expandable(props: BlockProps<DocumentBlockExpandable>) {
export async function Expandable(props: BlockProps<DocumentBlockExpandable>) {
const { block, style, ancestorBlocks, document, context } = props;
const title = getNodeFragmentByType(block, 'expandable-title');
@@ -26,6 +28,10 @@ export function Expandable(props: BlockProps<DocumentBlockExpandable>) {
let id = block.meta?.id ?? '';
id = context.getId ? context.getId(id) : id;
const language = context.contentContext
? await getSpaceLanguage(context.contentContext)
: defaultLanguage;
return (
<Details
id={id}
@@ -68,7 +74,7 @@ export function Expandable(props: BlockProps<DocumentBlockExpandable>) {
/>
<a
href={`#${id}`}
aria-label="Direct link to heading"
aria-label={tString(language, 'direct_link_to_heading')}
className={tcls(
'absolute',
'top-2',
@@ -13,11 +13,11 @@ export const hashLinkButtonWrapperStyles = tcls('relative', 'group/hash');
export function HashLinkButton(props: {
id: string;
block: DocumentBlockTabs | DocumentBlockHeading;
label?: string;
label: string;
className?: ClassValue;
iconClassName?: ClassValue;
}) {
const { id, block, className, iconClassName, label = 'Direct link to block' } = props;
const { id, block, className, iconClassName, label } = props;
const textStyle = getBlockTextStyle(block);
return (
<div
@@ -1,5 +1,7 @@
import type { DocumentBlockHeading } from '@gitbook/api';
import { getSpaceLanguage, tString } from '@/intl/server';
import { defaultLanguage } from '@/intl/translations';
import { tcls } from '@/lib/tailwind';
import type { BlockProps } from './Block';
@@ -8,7 +10,7 @@ import { Inlines } from './Inlines';
import { getBlockTextStyle } from './spacing';
import { getTextAlignment } from './utils';
export function Heading(props: BlockProps<DocumentBlockHeading>) {
export async function Heading(props: BlockProps<DocumentBlockHeading>) {
const { block, style, context, ...rest } = props;
const textStyle = getBlockTextStyle(block);
@@ -18,6 +20,10 @@ export function Heading(props: BlockProps<DocumentBlockHeading>) {
let id = block.meta?.id ?? '';
id = context.getId ? context.getId(id) : id;
const language = context.contentContext
? await getSpaceLanguage(context.contentContext)
: defaultLanguage;
return (
<Tag
id={id}
@@ -39,11 +45,11 @@ export function Heading(props: BlockProps<DocumentBlockHeading>) {
id={id}
block={block}
className={tcls(
'-ml-6 pr-2',
'-ml-6 self-center pr-2',
'[.flip-heading-hash_&]:order-last [.flip-heading-hash_&]:ml-1 [.flip-heading-hash_&]:pl-2'
)}
iconClassName={tcls('size-4')}
label="Direct link to heading"
label={tString(language, 'direct_link_to_heading')}
/>
<div
@@ -165,4 +165,5 @@ export const ar: TranslationLanguage = {
form_other_prompt: 'أدخل إجابتك...',
form_other_field: 'أخرى...',
cancel: 'إلغاء',
direct_link_to_heading: 'رابط مباشر إلى العنوان',
};
@@ -167,4 +167,5 @@ export const bg: TranslationLanguage = {
form_other_prompt: 'Въведете отговора си...',
form_other_field: 'Друго...',
cancel: 'Отказ',
direct_link_to_heading: 'Директна връзка към заглавието',
};
@@ -167,4 +167,5 @@ export const cs: TranslationLanguage = {
form_other_prompt: 'Zadejte svou odpověď...',
form_other_field: 'Jiné...',
cancel: 'Zrušit',
direct_link_to_heading: 'Přímý odkaz na nadpis',
};
@@ -166,4 +166,5 @@ export const da: TranslationLanguage = {
form_other_prompt: 'Indtast dit svar...',
form_other_field: 'Andet...',
cancel: 'Annuller',
direct_link_to_heading: 'Direkte link til overskriften',
};
@@ -167,4 +167,5 @@ export const de = {
form_other_prompt: 'Geben Sie Ihre Antwort ein...',
form_other_field: 'Sonstiges...',
cancel: 'Abbrechen',
direct_link_to_heading: 'Direkter Link zur Überschrift',
};
@@ -168,4 +168,5 @@ export const el: TranslationLanguage = {
form_other_prompt: 'Εισαγάγετε την απάντησή σας...',
form_other_field: 'Άλλο...',
cancel: 'Ακύρωση',
direct_link_to_heading: 'Άμεσος σύνδεσμος προς την επικεφαλίδα',
};
@@ -163,4 +163,5 @@ export const en = {
form_other_prompt: 'Enter your answer...',
form_other_field: 'Other...',
cancel: 'Cancel',
direct_link_to_heading: 'Direct link to heading',
};
@@ -168,4 +168,5 @@ export const es: TranslationLanguage = {
form_other_prompt: 'Escribe tu respuesta...',
form_other_field: 'Otro...',
cancel: 'Cancelar',
direct_link_to_heading: 'Enlace directo al encabezado',
};
@@ -165,4 +165,5 @@ export const et: TranslationLanguage = {
form_other_prompt: 'Sisestage oma vastus...',
form_other_field: 'Muu...',
cancel: 'Tühista',
direct_link_to_heading: 'Otselink pealkirjale',
};
@@ -166,4 +166,5 @@ export const fi: TranslationLanguage = {
form_other_prompt: 'Kirjoita vastauksesi...',
form_other_field: 'Muu...',
cancel: 'Peruuta',
direct_link_to_heading: 'Suora linkki otsikkoon',
};
@@ -163,4 +163,5 @@ export const fr = {
form_other_prompt: 'Saisissez votre réponse...',
form_other_field: 'Autre...',
cancel: 'Annuler',
direct_link_to_heading: 'Lien direct vers le titre',
};
@@ -164,4 +164,5 @@ export const he: TranslationLanguage = {
form_other_prompt: 'הזן את תשובתך...',
form_other_field: 'אחר...',
cancel: 'ביטול',
direct_link_to_heading: 'קישור ישיר לכותרת',
};
@@ -165,4 +165,5 @@ export const hi: TranslationLanguage = {
form_other_prompt: 'अपना उत्तर दर्ज करें...',
form_other_field: 'अन्य...',
cancel: 'रद्द करें',
direct_link_to_heading: 'शीर्षक का सीधा लिंक',
};
@@ -167,4 +167,5 @@ export const hr: TranslationLanguage = {
form_other_prompt: 'Unesite svoj odgovor...',
form_other_field: 'Ostalo...',
cancel: 'Odustani',
direct_link_to_heading: 'Izravna poveznica na naslov',
};
@@ -167,4 +167,5 @@ export const hu: TranslationLanguage = {
form_other_prompt: 'Adja meg a válaszát...',
form_other_field: 'Egyéb...',
cancel: 'Mégse',
direct_link_to_heading: 'Közvetlen hivatkozás a címsorra',
};
@@ -166,4 +166,5 @@ export const id: TranslationLanguage = {
form_other_prompt: 'Masukkan jawaban Anda...',
form_other_field: 'Lainnya...',
cancel: 'Batal',
direct_link_to_heading: 'Tautan langsung ke judul',
};
@@ -167,4 +167,5 @@ export const it: TranslationLanguage = {
form_other_prompt: 'Inserisci la tua risposta...',
form_other_field: 'Altro...',
cancel: 'Annulla',
direct_link_to_heading: 'Link diretto al titolo',
};
@@ -166,4 +166,5 @@ export const ja: TranslationLanguage = {
form_other_prompt: '回答を入力...',
form_other_field: 'その他...',
cancel: 'キャンセル',
direct_link_to_heading: '見出しへの直接リンク',
};
@@ -165,4 +165,5 @@ export const ko: TranslationLanguage = {
form_other_prompt: '답변을 입력하세요...',
form_other_field: '기타...',
cancel: '취소',
direct_link_to_heading: '제목으로 가는 직접 링크',
};
@@ -166,4 +166,5 @@ export const lt: TranslationLanguage = {
form_other_prompt: 'Įveskite savo atsakymą...',
form_other_field: 'Kita...',
cancel: 'Atšaukti',
direct_link_to_heading: 'Tiesioginė nuoroda į antraštę',
};
@@ -165,4 +165,5 @@ export const lv: TranslationLanguage = {
form_other_prompt: 'Ievadiet savu atbildi...',
form_other_field: 'Cits...',
cancel: 'Atcelt',
direct_link_to_heading: 'Tieša saite uz virsrakstu',
};
@@ -166,4 +166,5 @@ export const ms: TranslationLanguage = {
form_other_prompt: 'Masukkan jawapan anda...',
form_other_field: 'Lain-lain...',
cancel: 'Batal',
direct_link_to_heading: 'Pautan terus ke tajuk',
};
@@ -166,4 +166,5 @@ export const nl: TranslationLanguage = {
form_other_prompt: 'Voer je antwoord in...',
form_other_field: 'Anders...',
cancel: 'Annuleren',
direct_link_to_heading: 'Directe link naar kop',
};
@@ -166,4 +166,5 @@ export const no: TranslationLanguage = {
form_other_prompt: 'Skriv inn svaret ditt...',
form_other_field: 'Annet...',
cancel: 'Avbryt',
direct_link_to_heading: 'Direkte lenke til overskriften',
};
@@ -166,4 +166,5 @@ export const pl: TranslationLanguage = {
form_other_prompt: 'Wpisz swoją odpowiedź...',
form_other_field: 'Inne...',
cancel: 'Anuluj',
direct_link_to_heading: 'Bezpośredni link do nagłówka',
};
@@ -166,4 +166,5 @@ export const pt_br = {
form_other_prompt: 'Digite sua resposta...',
form_other_field: 'Outro...',
cancel: 'Cancelar',
direct_link_to_heading: 'Link direto para o título',
};
@@ -166,4 +166,5 @@ export const pt: TranslationLanguage = {
form_other_prompt: 'Introduza a sua resposta...',
form_other_field: 'Outro...',
cancel: 'Cancelar',
direct_link_to_heading: 'Ligação direta para o título',
};
@@ -168,4 +168,5 @@ export const ro: TranslationLanguage = {
form_other_prompt: 'Introdu răspunsul tău...',
form_other_field: 'Altul...',
cancel: 'Anulează',
direct_link_to_heading: 'Link direct către titlu',
};
@@ -165,4 +165,5 @@ export const ru = {
form_other_prompt: 'Введите ответ...',
form_other_field: 'Другое...',
cancel: 'Отмена',
direct_link_to_heading: 'Прямая ссылка на заголовок',
};
@@ -167,4 +167,5 @@ export const sk: TranslationLanguage = {
form_other_prompt: 'Zadajte svoju odpoveď...',
form_other_field: 'Iné...',
cancel: 'Zrušiť',
direct_link_to_heading: 'Priamy odkaz na nadpis',
};
@@ -166,4 +166,5 @@ export const sl: TranslationLanguage = {
form_other_prompt: 'Vnesite svoj odgovor...',
form_other_field: 'Drugo...',
cancel: 'Prekliči',
direct_link_to_heading: 'Neposredna povezava do naslova',
};
@@ -166,4 +166,5 @@ export const sv: TranslationLanguage = {
form_other_prompt: 'Ange ditt svar...',
form_other_field: 'Annat...',
cancel: 'Avbryt',
direct_link_to_heading: 'Direktlänk till rubriken',
};
@@ -163,4 +163,5 @@ export const th: TranslationLanguage = {
form_other_prompt: 'ป้อนคำตอบของคุณ...',
form_other_field: 'อื่น ๆ...',
cancel: 'ยกเลิก',
direct_link_to_heading: 'ลิงก์ตรงไปยังหัวเรื่อง',
};
@@ -165,4 +165,5 @@ export const tr: TranslationLanguage = {
form_other_prompt: 'Yanıtınızı girin...',
form_other_field: 'Diğer...',
cancel: 'İptal',
direct_link_to_heading: 'Başlığa doğrudan bağlantı',
};
@@ -165,4 +165,5 @@ export const uk: TranslationLanguage = {
form_other_prompt: 'Введіть відповідь...',
form_other_field: 'Інше...',
cancel: 'Скасувати',
direct_link_to_heading: 'Пряме посилання на заголовок',
};
@@ -165,4 +165,5 @@ export const vi: TranslationLanguage = {
form_other_prompt: 'Nhập câu trả lời của bạn...',
form_other_field: 'Khác...',
cancel: 'Hủy',
direct_link_to_heading: 'Liên kết trực tiếp đến tiêu đề',
};
@@ -162,4 +162,5 @@ export const yue: TranslationLanguage = {
form_other_prompt: '輸入你嘅回答...',
form_other_field: '其他...',
cancel: '取消',
direct_link_to_heading: '指向標題嘅直接連結',
};
@@ -162,4 +162,5 @@ export const zh_tw: TranslationLanguage = {
form_other_prompt: '輸入您的回答...',
form_other_field: '其他...',
cancel: '取消',
direct_link_to_heading: '指向標題的直接連結',
};
@@ -162,4 +162,5 @@ export const zh: TranslationLanguage = {
form_other_prompt: '请输入您的回答...',
form_other_field: '其他...',
cancel: '取消',
direct_link_to_heading: '指向标题的直接链接',
};