Path: blob/main/src/format/html/format-html-axe.ts
12925 views
/*1* format-html-axe.ts2*3* Copyright (C) 2020-2025 Posit Software, PBC4*/56import { isHtmlDashboardOutput, isRevealjsOutput } from "../../config/format.ts";7import {8Format,9FormatDependency,10FormatExtras,11kDependencies,12} from "../../config/types.ts";13import { formatResourcePath } from "../../core/resources.ts";14import { encodeBase64 } from "../../deno_ral/encoding.ts";15import { join } from "../../deno_ral/path.ts";1617function axeHtmlDependency(options: unknown): FormatDependency {18return {19name: "quarto-axe",20head: `<script id="quarto-axe-checker-options" type="text/plain">${21encodeBase64(JSON.stringify(options))22}</script>`,23scripts: [{24name: "axe-check.js",25path: formatResourcePath("html", join("axe", "axe-check.js")),26attribs: { type: "module" },27}],28};29}3031export function axeFormatDependencies(32format: Format,33options?: unknown,34): FormatExtras {35if (!options) return {};3637// Use reveal-theme for revealjs, bootstrap for other HTML formats.38// Note: For revealjs, sass-bundles compile separately from the theme39// (which compiles in format-reveal-theme.ts), so the !default values40// below are used instead of actual theme colors. This is a known41// limitation - see GitHub issue for architectural context.42const isRevealjs = isRevealjsOutput(format.pandoc);43const isDashboard = isHtmlDashboardOutput(format.identifier["base-format"]);44const sassDependency = isRevealjs ? "reveal-theme" : "bootstrap";4546// Base overlay rules shared by all formats (also serves as fallback for revealjs)47const baseRules = `48body div.quarto-axe-report {49position: fixed;50bottom: 3rem;51right: 3rem;52padding: 1rem;53border: 1px solid var(--r-main-color, $body-color);54z-index: 9999;55background-color: var(--r-background-color, $body-bg);56color: var(--r-main-color, $body-color);57max-height: 50vh;58overflow-y: auto;59}6061.quarto-axe-violation-help { padding-left: 0.5rem; }62.quarto-axe-violation-selector { padding-left: 1rem; }63.quarto-axe-violation-target {64padding: 0.5rem;65color: $link-color;66text-decoration: underline;67cursor: pointer;68}6970.quarto-axe-hover-highlight {71background-color: red;72border: 2px solid red;73}`;7475// RevealJS: override overlay styles when report is embedded as a slide76const revealjsRules = isRevealjs77? `78.reveal .slides section.quarto-axe-report-slide {79text-align: left;80font-size: 0.55em;81h2 {82margin-bottom: 0.5em;83font-size: 1.8em;84}85div.quarto-axe-report {86position: static;87padding: 0;88border: none;89background-color: transparent;90max-height: none;91overflow-y: visible;92z-index: auto;93}94.quarto-axe-violation-description {95margin-top: 0.6em;96font-weight: bold;97}98.quarto-axe-violation-target {99font-size: 0.9em;100}101}`102: "";103104// Dashboard: report inside offcanvas sidebar (not fixed overlay)105const dashboardRules = isDashboard106? `107.quarto-dashboard .offcanvas.quarto-axe-offcanvas {108.quarto-axe-report {109position: static;110padding: 0;111border: none;112background-color: transparent;113max-height: none;114overflow-y: visible;115z-index: auto;116}117}118.quarto-dashboard .quarto-axe-toggle {119position: fixed;120bottom: 1rem;121right: 1rem;122z-index: 1040;123border-radius: 50%;124width: 3rem;125height: 3rem;126display: flex;127align-items: center;128justify-content: center;129font-size: 1.25rem;130}131.quarto-dashboard .quarto-axe-scanning {132padding: 1rem;133text-align: center;134opacity: 0.7;135font-style: italic;136}`137: "";138139return {140html: {141[kDependencies]: [142axeHtmlDependency(options),143],144"sass-bundles": [145{146key: "axe",147dependency: sassDependency,148user: [{149uses: "",150defaults: `151$body-color: #222 !default;152$body-bg: #fff !default;153$link-color: #2a76dd !default;154`,155functions: "",156mixins: "",157rules: baseRules + revealjsRules + dashboardRules,158}],159},160],161},162};163}164165166