diff --git a/src/command/render/pandoc-dependencies-html.ts b/src/command/render/pandoc-dependencies-html.ts index ce2ccbc971e..0775b08c75e 100644 --- a/src/command/render/pandoc-dependencies-html.ts +++ b/src/command/render/pandoc-dependencies-html.ts @@ -209,6 +209,7 @@ interface HtmlInjector { href: string, rel: string, type?: string, + media?: string, ): void; injectHtml(html: string): void; @@ -350,7 +351,7 @@ function processHtmlDependencies( // Link tags if (dependency.links) { dependency.links.forEach((link) => { - injector.injectLink(link.href, link.rel, link.type); + injector.injectLink(link.href, link.rel, link.type, link.media); }); } @@ -515,6 +516,7 @@ function domDependencyInjector( href: string, rel: string, type?: string, + media?: string, ) => { const linkEl = doc.createElement("link"); linkEl.setAttribute("href", pathWithForwardSlashes(href)); @@ -522,6 +524,9 @@ function domDependencyInjector( if (type) { linkEl.setAttribute("type", type); } + if (media) { + linkEl.setAttribute("media", media); + } injectEl(linkEl); }; @@ -575,7 +580,7 @@ function lineDependencyInjector( ` href="<%- href %>" rel="stylesheet" />`, ); const rawLinkTemplate = ld.template( - ` type="<%- type %>"<% } %> />`, + ` type="<%- type %>"<% } %><% if (media) { %> media="<%- media %>"<% } %> />`, ); const inject = (content: string, afterBody?: boolean) => { @@ -625,6 +630,7 @@ function lineDependencyInjector( href: string, rel: string, type?: string, + media?: string, ) => { if (!type) { type = ""; diff --git a/src/config/types.ts b/src/config/types.ts index 09daafe951d..71cb95e0c62 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -269,7 +269,7 @@ export interface FormatDependency { version?: string; external?: boolean; meta?: Record; - links?: { rel: string; href: string; type?: string }[]; + links?: { rel: string; href: string; type?: string; media?: string }[]; scripts?: DependencyHtmlFile[]; stylesheets?: DependencyHtmlFile[]; serviceworkers?: DependencyServiceWorker[]; diff --git a/src/project/types/website/website.ts b/src/project/types/website/website.ts index 3a924975abf..b3bc5752e53 100644 --- a/src/project/types/website/website.ts +++ b/src/project/types/website/website.ts @@ -19,6 +19,7 @@ import { import { ProjectCreate, ProjectOutputFile, ProjectType } from "../types.ts"; import { Format, + FormatDependency, FormatExtras, kDependencies, kHtmlFinalizers, @@ -179,25 +180,42 @@ export const websiteProjectType: ProjectType = { } // dependency for favicon if we have one - let favicon = websiteConfigString(kSiteFavicon, project.config); - if (!favicon) { + let faviconLight = websiteConfigString(kSiteFavicon, project.config); + let faviconDark = undefined; // until schema upgrade + if (!faviconLight) { const brand = await project.resolveBrand(); if (brand?.light) { - favicon = getFavicon(brand.light); + faviconLight = getFavicon(brand.light); + } + if (brand?.dark) { + faviconDark = getFavicon(brand.dark); } } - if (favicon) { + if (faviconLight || faviconDark) { const offset = projectOffset(project, source); extras.html = extras.html || {}; extras.html.dependencies = extras.html.dependencies || []; - extras.html.dependencies.push({ + const faviconDep: FormatDependency = { name: kSiteFavicon, - links: [{ + links: [], + }; + if (faviconDark) { + faviconDep.links!.push({ rel: "icon", - href: offset + "/" + favicon, - type: contentType(favicon), - }], - }); + href: offset + "/" + faviconDark, + type: contentType(faviconDark), + media: "(prefers-color-scheme:dark)", + }); + } + if (faviconLight) { + faviconDep.links!.push({ + rel: "icon", + href: offset + "/" + faviconLight, + type: contentType(faviconLight), + media: "(prefers-color-scheme:light)", + }); + } + extras.html.dependencies.push(faviconDep); } // pagetitle for home page if it has no title diff --git a/tests/docs/smoke-all/brand/logo/brand-icon-small-favicon-book/index.qmd b/tests/docs/smoke-all/brand/logo/brand-icon-small-favicon-book/index.qmd index 06ec2006de2..eee7c533986 100644 --- a/tests/docs/smoke-all/brand/logo/brand-icon-small-favicon-book/index.qmd +++ b/tests/docs/smoke-all/brand/logo/brand-icon-small-favicon-book/index.qmd @@ -2,8 +2,8 @@ _quarto: tests: html: - ensureFileRegexMatches: - - [''] + ensureHtmlElements: + - ['link[href="./logos/small.png"][rel="icon"][type="image/png"]'] - [] --- diff --git a/tests/docs/smoke-all/brand/logo/favicon/.gitignore b/tests/docs/smoke-all/brand/logo/favicon/.gitignore new file mode 100644 index 00000000000..075b2542afb --- /dev/null +++ b/tests/docs/smoke-all/brand/logo/favicon/.gitignore @@ -0,0 +1 @@ +/.quarto/ diff --git a/tests/docs/smoke-all/brand/logo/favicon/_brand.yml b/tests/docs/smoke-all/brand/logo/favicon/_brand.yml new file mode 100644 index 00000000000..f619452e818 --- /dev/null +++ b/tests/docs/smoke-all/brand/logo/favicon/_brand.yml @@ -0,0 +1,11 @@ +color: + background: + light: "#fff" + dark: "#111" + foreground: + light: "#111" + dark: "#fff" +logo: + small: + light: sun-face.png + dark: moon-face.png diff --git a/tests/docs/smoke-all/brand/logo/favicon/_quarto.yml b/tests/docs/smoke-all/brand/logo/favicon/_quarto.yml new file mode 100644 index 00000000000..e82461507d8 --- /dev/null +++ b/tests/docs/smoke-all/brand/logo/favicon/_quarto.yml @@ -0,0 +1,2 @@ +project: + type: website diff --git a/tests/docs/smoke-all/brand/logo/favicon/index.qmd b/tests/docs/smoke-all/brand/logo/favicon/index.qmd new file mode 100644 index 00000000000..e37a1f3c45d --- /dev/null +++ b/tests/docs/smoke-all/brand/logo/favicon/index.qmd @@ -0,0 +1,22 @@ +--- +brand: + color: + background: + light: "#fff" + dark: "#111" + foreground: + light: "#111" + dark: "#fff" + logo: + small: + light: sun-face.png + dark: moon-face.png +_quarto: + tests: + html: + ensureHtmlElements: + - + - 'link[rel="icon"][href="./sun-face.png"][media="(prefers-color-scheme:light)"]' + - 'link[rel="icon"][href="./moon-face.png"][media="(prefers-color-scheme:dark)"]' + - [] +--- diff --git a/tests/docs/smoke-all/brand/logo/navbar/favicon/_brand.yml b/tests/docs/smoke-all/brand/logo/navbar/favicon/_brand.yml new file mode 100644 index 00000000000..f619452e818 --- /dev/null +++ b/tests/docs/smoke-all/brand/logo/navbar/favicon/_brand.yml @@ -0,0 +1,11 @@ +color: + background: + light: "#fff" + dark: "#111" + foreground: + light: "#111" + dark: "#fff" +logo: + small: + light: sun-face.png + dark: moon-face.png diff --git a/tests/docs/smoke-all/brand/logo/navbar/favicon/_quarto.yml b/tests/docs/smoke-all/brand/logo/navbar/favicon/_quarto.yml new file mode 100644 index 00000000000..5e981a2e5cb --- /dev/null +++ b/tests/docs/smoke-all/brand/logo/navbar/favicon/_quarto.yml @@ -0,0 +1,12 @@ +project: + type: website +theme: + light: brand + dark: [brand, dark-fixups.scss] +website: + navbar: + style: "docked" + search: true + contents: + - index.qmd + - conclusion.qmd diff --git a/tests/docs/smoke-all/brand/logo/navbar/favicon/conclusion.qmd b/tests/docs/smoke-all/brand/logo/navbar/favicon/conclusion.qmd new file mode 100644 index 00000000000..adaa3368882 --- /dev/null +++ b/tests/docs/smoke-all/brand/logo/navbar/favicon/conclusion.qmd @@ -0,0 +1,3 @@ +--- +title: conclusion +--- diff --git a/tests/docs/smoke-all/brand/logo/navbar/favicon/dark-fixups.scss b/tests/docs/smoke-all/brand/logo/navbar/favicon/dark-fixups.scss new file mode 100644 index 00000000000..4b1e9601a6a --- /dev/null +++ b/tests/docs/smoke-all/brand/logo/navbar/favicon/dark-fixups.scss @@ -0,0 +1,9 @@ +/*-- scss:rules --*/ + +nav.sidebar.sidebar-navigation:not(.rollup) { + background-color: #282b30; +} + +nav.navbar { + background-color: rgba(13, 108, 251, 25%); +} diff --git a/tests/docs/smoke-all/brand/logo/navbar/favicon/index.qmd b/tests/docs/smoke-all/brand/logo/navbar/favicon/index.qmd new file mode 100644 index 00000000000..715790258ac --- /dev/null +++ b/tests/docs/smoke-all/brand/logo/navbar/favicon/index.qmd @@ -0,0 +1,15 @@ +--- +title: intro +_quarto: + tests: + html: + ensureHtmlElements: + - + # favicon + - 'link[rel="icon"][href="./sun-face.png"][media="(prefers-color-scheme:light)"]' + - 'link[rel="icon"][href="./moon-face.png"][media="(prefers-color-scheme:dark)"]' + # navbar + - 'img[class*="light-content"][src="./sun-face.png"][alt=""]' + - 'img[class*="dark-content"][src="./moon-face.png"][alt=""]' + - [] +--- diff --git a/tests/docs/smoke-all/brand/logo/navbar/favicon/moon-face.png b/tests/docs/smoke-all/brand/logo/navbar/favicon/moon-face.png new file mode 100644 index 00000000000..ee057e972b9 Binary files /dev/null and b/tests/docs/smoke-all/brand/logo/navbar/favicon/moon-face.png differ diff --git a/tests/docs/smoke-all/brand/logo/navbar/favicon/sun-face.png b/tests/docs/smoke-all/brand/logo/navbar/favicon/sun-face.png new file mode 100644 index 00000000000..62a734cb8db Binary files /dev/null and b/tests/docs/smoke-all/brand/logo/navbar/favicon/sun-face.png differ diff --git a/tests/docs/smoke-all/brand/logo/website-favicon/index.qmd b/tests/docs/smoke-all/brand/logo/website-favicon/index.qmd index f20e6354104..25b8f343c84 100644 --- a/tests/docs/smoke-all/brand/logo/website-favicon/index.qmd +++ b/tests/docs/smoke-all/brand/logo/website-favicon/index.qmd @@ -3,8 +3,8 @@ title: "test-brand-favicon" _quarto: tests: html: - ensureFileRegexMatches: - - [''] + ensureHtmlElements: + - ['link[href="./logos/small.png"][rel="icon"][type="image/png"]'] - [] ---