Merge branch 'master' into refactor/polyfills

This commit is contained in:
squidfunk
2023-07-06 13:28:16 +02:00
2510 changed files with 10115 additions and 11988 deletions

View File

@@ -211,4 +211,74 @@
}
}
}
// Social card
.mdx-social {
position: relative;
height: min(#{px2rem(540px)}, 80vw);
// Social card image on hover
&:hover .mdx-social__image {
background-color: rgba(228, 228, 228, 0.05);
}
// Social card layer
&__layer {
position: absolute;
margin-top: px2rem(80px);
transition: 250ms cubic-bezier(0.7, 0, 0.3, 1);
transform-style: preserve-3d;
// Social card layer on hover
&:hover {
// Social card label
.mdx-social__label {
opacity: 1;
}
// Social card image
.mdx-social__image {
background-color: rgba(127, 127, 127, 0.99);
}
// Hide top layers
~ .mdx-social__layer {
opacity: 0;
}
}
}
// Social card image
&__image {
box-shadow:
px2rem(-5px) px2rem(5px) px2rem(10px)
rgba(0, 0, 0, 0.05);
transition: all 250ms;
transform: rotate(-40deg) skew(15deg, 15deg) scale(0.7);
// Actual image
img {
display: block;
}
}
// Social card label
&__label {
position: absolute;
display: block;
padding: px2rem(4px) px2rem(8px);
color: var(--md-default-bg-color);
background-color: var(--md-default-fg-color--light);
opacity: 0;
transition: all 250ms;
}
// Transform on hover
@for $i from 6 through 0 {
&:hover .mdx-social__layer:nth-child(#{$i}) {
transform: translateY(#{($i - 3) * -10}px);
}
}
}
}

View File

@@ -151,7 +151,9 @@ countries = dict({
"it": "it",
"ja": "jp",
"ka": "ge",
"kn": "in",
"ko": "kr",
"ku-IQ": "iq",
"lt": "lt",
"lv": "lv",
"mk": "mk",
@@ -166,12 +168,14 @@ countries = dict({
"pt": "pt",
"ro": "ro",
"ru": "ru",
"sa": "in",
"sh": "rs",
"si": "lk",
"sk": "sk",
"sl": "si",
"sr": "rs",
"sv": "se",
"te": "in",
"th": "th",
"tl": "ph",
"tr": "tr",

View File

@@ -25,6 +25,7 @@ import {
filter,
fromEvent,
map,
merge,
shareReplay,
startWith
} from "rxjs"
@@ -66,10 +67,17 @@ export function setLocationHash(hash: string): void {
/**
* Watch location hash
*
* @param location$ - Location observable
*
* @returns Location hash observable
*/
export function watchLocationHash(): Observable<string> {
return fromEvent<HashChangeEvent>(window, "hashchange")
export function watchLocationHash(
location$: Observable<URL>
): Observable<string> {
return merge(
fromEvent<HashChangeEvent>(window, "hashchange"),
location$
)
.pipe(
map(getLocationHash),
startWith(getLocationHash()),
@@ -81,10 +89,14 @@ export function watchLocationHash(): Observable<string> {
/**
* Watch location target
*
* @param location$ - Location observable
*
* @returns Location target observable
*/
export function watchLocationTarget(): Observable<HTMLElement> {
return watchLocationHash()
export function watchLocationTarget(
location$: Observable<URL>
): Observable<HTMLElement> {
return watchLocationHash(location$)
.pipe(
map(id => getOptionalElement(`[id="${id}"]`)!),
filter(el => typeof el !== "undefined")

View File

@@ -124,7 +124,7 @@ document.documentElement.classList.add("js")
/* Set up navigation observables and subjects */
const document$ = watchDocument()
const location$ = watchLocation()
const target$ = watchLocationTarget()
const target$ = watchLocationTarget(location$)
const keyboard$ = watchKeyboard()
/* Set up media observables */
@@ -145,7 +145,8 @@ setupClipboardJS({ alert$ })
/* Set up instant loading, if enabled */
if (feature("navigation.instant"))
setupInstantLoading({ document$, location$, viewport$ })
setupInstantLoading({ location$, viewport$ })
.subscribe(document$)
/* Set up version selector */
if (config.version?.provider === "mike")

View File

@@ -28,7 +28,6 @@ import {
finalize,
fromEvent,
map,
startWith,
tap
} from "rxjs"
@@ -86,18 +85,12 @@ export function mountAnnounce(
/* Mount component on subscription */
return defer(() => {
const push$ = new Subject<Announce>()
push$
.pipe(
startWith({ hash: __md_get<number>("__announce") })
)
.subscribe(({ hash }) => {
if (hash && hash === (__md_get<number>("__announce") ?? hash)) {
el.hidden = true
push$.subscribe(({ hash }) => {
el.hidden = true
/* Persist preference in local storage */
__md_set<number>("__announce", hash)
}
})
/* Persist preference in local storage */
__md_set<number>("__announce", hash)
})
/* Create and return component */
return watchAnnounce(el)

View File

@@ -222,7 +222,10 @@ export function mountAnnotation(
takeUntil(done$),
filter(ev => !(ev.metaKey || ev.ctrlKey))
)
.subscribe(ev => ev.preventDefault())
.subscribe(ev => {
ev.stopPropagation()
ev.preventDefault()
})
/* Allow to open link in new tab or blur on close */
fromEvent<MouseEvent>(index, "mousedown")

View File

@@ -143,7 +143,7 @@ export function mountAnnotationList(
const annotations = new Map<string, HTMLElement>()
for (const marker of findAnnotationMarkers(container)) {
const [, id] = marker.textContent!.match(/\((\d+)\)/)!
if (getOptionalElement(`li:nth-child(${id})`, el)) {
if (getOptionalElement(`:scope > li:nth-child(${id})`, el)) {
annotations.set(id, renderAnnotation(id, prefix))
marker.replaceWith(annotations.get(id)!)
}
@@ -162,7 +162,7 @@ export function mountAnnotationList(
for (const [id, annotation] of annotations)
pairs.push([
getElement(".md-typeset", annotation),
getElement(`li:nth-child(${id})`, el)
getElement(`:scope > li:nth-child(${id})`, el)
])
/* Handle print mode - see https://bit.ly/3rgPdpt */

View File

@@ -177,7 +177,7 @@ export function mountCodeBlock(
feature("content.code.copy") && !el.closest(".no-copy")
)) {
const parent = el.closest("pre")!
parent.id = `__code_${++sequence}`
parent.id = `__code_${sequence++}`
parent.insertBefore(
renderClipboardButton(parent.id),
el

View File

@@ -78,6 +78,7 @@ marker {
.edgePath .path,
.flowchart-link {
stroke: var(--md-mermaid-edge-color);
stroke-width: .05rem;
}
/* Flowchart arrow head */
@@ -99,12 +100,12 @@ marker {
}
/* Flowchart markers */
defs #flowchart-circleStart,
defs #flowchart-circleEnd,
defs #flowchart-crossStart,
defs #flowchart-crossEnd,
defs #flowchart-pointStart,
defs #flowchart-pointEnd {
g #flowchart-circleStart,
g #flowchart-circleEnd,
g #flowchart-crossStart,
g #flowchart-crossEnd,
g #flowchart-pointStart,
g #flowchart-pointEnd {
stroke: none;
}
@@ -396,6 +397,17 @@ line {
fill: var(--md-accent-bg-color);
}
/* Sequence rectangle */
rect.rect {
fill: var(--md-mermaid-node-bg-color);
stroke: none;
}
/* Sequence rectangle text */
rect.rect + text.text {
fill: var(--md-mermaid-edge-color);
}
/* Sequence diagram markers */
defs #sequencenumber {
fill: var(--md-mermaid-node-fg-color) !important;

View File

@@ -69,7 +69,7 @@ let sequence = 0
*/
function fetchScripts(): Observable<void> {
return typeof mermaid === "undefined" || mermaid instanceof Element
? watchScript("https://unpkg.com/mermaid@9.3.0/dist/mermaid.min.js")
? watchScript("https://unpkg.com/mermaid@9.4.3/dist/mermaid.min.js")
: of(undefined)
}

View File

@@ -244,6 +244,13 @@ export function mountContentTabs(
}
})
/* Pause media (audio, video) on switch - see https://bit.ly/3Bk6cel */
push$.pipe(takeUntil(done$))
.subscribe(() => {
for (const media of getElements<HTMLAudioElement>("audio, video", el))
media.pause()
})
/* Create and return component */
return watchContentTabs(el)
.pipe(

View File

@@ -119,6 +119,10 @@ export function mountPalette(
const meta = h("meta", { name: "theme-color" })
document.head.appendChild(meta)
// Add color scheme meta tag
const scheme = h("meta", { name: "color-scheme" })
document.head.appendChild(scheme)
/* Mount component on subscription */
return defer(() => {
const push$ = new Subject<Palette>()
@@ -145,10 +149,13 @@ export function mountPalette(
.pipe(
map(() => {
const header = getComponentElement("header")
const { backgroundColor } = window.getComputedStyle(header)
const style = window.getComputedStyle(header)
// Set color scheme
scheme.content = style.colorScheme
/* Return color in hexadecimal format */
return backgroundColor.match(/\d+/g)!
return style.backgroundColor.match(/\d+/g)!
.map(value => (+value).toString(16).padStart(2, "0"))
.join("")
})

View File

@@ -29,6 +29,7 @@ import {
distinctUntilKeyChanged,
endWith,
finalize,
fromEvent,
ignoreElements,
map,
repeat,
@@ -166,6 +167,13 @@ export function mountBackToTop(
el.style.top = `${height + 16}px`
})
/* Go back to top */
fromEvent(el, "click")
.subscribe(ev => {
ev.preventDefault()
window.scrollTo({ top: 0 })
})
/* Create and return component */
return watchBackToTop(el, { viewport$, main$, target$ })
.pipe(

View File

@@ -22,54 +22,40 @@
import {
EMPTY,
NEVER,
Observable,
Subject,
bufferCount,
catchError,
concatMap,
concat,
debounceTime,
distinctUntilChanged,
distinctUntilKeyChanged,
filter,
endWith,
fromEvent,
ignoreElements,
map,
merge,
of,
sample,
share,
skip,
skipUntil,
switchMap
startWith,
switchMap,
take,
withLatestFrom
} from "rxjs"
import { configuration, feature } from "~/_"
import {
Viewport,
ViewportOffset,
getElements,
getLocation,
getOptionalElement,
request,
setLocation,
setLocationHash
} from "~/browser"
import { getComponentElement } from "~/components"
import { h } from "~/utilities"
import { fetchSitemap } from "../sitemap"
/* ----------------------------------------------------------------------------
* Types
* ------------------------------------------------------------------------- */
/**
* History state
*/
export interface HistoryState {
url: URL /* State URL */
offset?: ViewportOffset /* State viewport offset */
}
/* ----------------------------------------------------------------------------
* Helper types
* ------------------------------------------------------------------------- */
@@ -78,7 +64,6 @@ export interface HistoryState {
* Setup options
*/
interface SetupOptions {
document$: Subject<Document> /* Document subject */
location$: Subject<URL> /* Location subject */
viewport$: Observable<Viewport> /* Viewport observable */
}
@@ -88,152 +73,165 @@ interface SetupOptions {
* ------------------------------------------------------------------------- */
/**
* Set up instant loading
* Set up instant navigation
*
* When fetching, theoretically, we could use `responseType: "document"`, but
* since all MkDocs links are relative, we need to make sure that the current
* location matches the document we just loaded. Otherwise any relative links
* in the document could use the old location.
*
* This is the reason why we need to synchronize history events and the process
* of fetching the document for navigation changes (except `popstate` events):
*
* 1. Fetch document via `XMLHTTPRequest`
* 2. Set new location via `history.pushState`
* 3. Parse and emit fetched document
*
* For `popstate` events, we must not use `history.pushState`, or the forward
* history will be irreversibly overwritten. In case the request fails, the
* location change is dispatched regularly.
* This is a heavily orchestrated operation - see inline comments to learn how
* this works with Material for MkDocs, and how you can hook into it.
*
* @param options - Options
*
* @returns Document observable
*/
export function setupInstantLoading(
{ document$, location$, viewport$ }: SetupOptions
): void {
{ location$, viewport$ }: SetupOptions
): Observable<Document> {
const config = configuration()
if (location.protocol === "file:")
return
return EMPTY
/* Disable automatic scroll restoration */
if ("scrollRestoration" in history) {
history.scrollRestoration = "manual"
/* Hack: ensure that reloads restore viewport offset */
fromEvent(window, "beforeunload")
.subscribe(() => {
history.scrollRestoration = "auto"
})
}
/* Hack: ensure absolute favicon link to omit 404s when switching */
const favicon = getOptionalElement<HTMLLinkElement>("link[rel=icon]")
if (typeof favicon !== "undefined")
favicon.href = favicon.href
/* Intercept internal navigation */
const push$ = fetchSitemap()
// Load sitemap immediately, so we have it available when the user initiates
// the first instant navigation request, and canonicalize URLs to the current
// base URL. The base URL will remain stable in between loads, as it's only
// read at the first initialization of the application.
const sitemap$ = fetchSitemap()
.pipe(
map(paths => paths.map(path => `${new URL(path, config.base)}`)),
switchMap(urls => fromEvent<MouseEvent>(document.body, "click")
.pipe(
filter(ev => !ev.metaKey && !ev.ctrlKey),
switchMap(ev => {
if (ev.target instanceof Element) {
const el = ev.target.closest("a")
if (el && !el.target) {
const url = new URL(el.href)
/* Canonicalize URL */
url.search = ""
url.hash = ""
/* Check if URL should be intercepted */
if (
url.pathname !== location.pathname &&
urls.includes(url.toString())
) {
ev.preventDefault()
return of({
url: new URL(el.href)
})
}
}
}
return NEVER
})
)
),
share<HistoryState>()
map(paths => paths.map(path => `${new URL(path, config.base)}`))
)
/* Intercept history back and forward */
const pop$ = fromEvent<PopStateEvent>(window, "popstate")
// Intercept inter-site navigation - to keep the number of event listeners
// low we use the fact that uncaptured events bubble up to the body. This also
// has the nice property that we don't need to detach and then again attach
// event listeners when instant navigation occurs.
const instant$ = fromEvent<MouseEvent>(document.body, "click")
.pipe(
filter(ev => ev.state !== null),
map(ev => ({
url: new URL(location.href),
offset: ev.state
})),
share<HistoryState>()
)
withLatestFrom(sitemap$),
switchMap(([ev, sitemap]) => {
if (!(ev.target instanceof Element))
return EMPTY
/* Emit location change */
merge(push$, pop$)
.pipe(
distinctUntilChanged((a, b) => a.url.href === b.url.href),
map(({ url }) => url)
)
.subscribe(location$)
// Skip, as target is not within a link - clicks on non-link elements
// are also captured, which we need to exclude from processing.
const el = ev.target.closest("a")
if (el === null)
return EMPTY
/* Fetch document via `XMLHTTPRequest` */
const response$ = location$
.pipe(
distinctUntilKeyChanged("pathname"),
switchMap(url => request(url.href)
.pipe(
catchError(() => {
setLocation(url)
return NEVER
})
)
),
// Skip, as link opens in new window - we now know we have captured a
// click on a link, but the link either has a `target` property defined,
// or the user pressed the `meta` or `ctrl` key to open it in a new
// window. Thus, we need to filter those events, too.
if (el.target || ev.metaKey || ev.ctrlKey)
return EMPTY
// Next, we must check if the URL is relevant for us, i.e., if it's an
// internal link to a page that is managed by MkDocs. Only then we can
// be sure that the structure of the page to be loaded adheres to the
// current document structure and can subsequently be injected into it
// without doing a full reload. For this reason, we must canonicalize
// the URL by removing all search parameters and hash fragments.
const url = new URL(el.href)
url.search = url.hash = ""
// Skip, if URL is not included in the sitemap - this could be the case
// when linking between versions or languages, or to another page that
// the author included as part of the build, but that is not managed by
// MkDocs. In that case we must not continue with instant navigation.
if (!sitemap.includes(`${url}`))
return EMPTY
// We now know that we have a link to an internal page, so we prevent
// the browser from navigation and emit the URL for instant navigation.
// Note that this also includes anchor links, which means we need to
// implement anchor positioning ourselves. The reason for this is that
// if we wouldn't manage anchor links as well, scroll restoration will
// not work correctly (e.g. following an anchor link and scrolling).
ev.preventDefault()
return of(new URL(el.href))
}),
share()
)
/* Set new location via `history.pushState` */
push$
.pipe(
sample(response$)
)
.subscribe(({ url }) => {
history.pushState({}, "", `${url}`)
})
// Before fetching for the first time, resolve the absolute favicon position,
// as the browser will try to fetch the icon immediately.
instant$.pipe(take(1))
.subscribe(() => {
const favicon = getOptionalElement<HTMLLinkElement>("link[rel=icon]")
if (typeof favicon !== "undefined")
favicon.href = favicon.href
})
/* Parse and emit fetched document */
// Enable scroll restoration before window unloads - this is essential to
// ensure that full reloads (F5) restore the viewport offset correctly. If
// only popstate events wouldn't reset the scroll position prior to their
// emission, we could just reset this in popstate. Meh.
fromEvent(window, "beforeunload")
.subscribe(() => {
history.scrollRestoration = "auto"
})
// When an instant navigation event occurs, disable scroll restoration, since
// we must normalize and synchronize the behavior across all browsers. For
// instance, when the user clicks the back or forward button, the browser
// would immediately jump to the position of the previous document.
instant$.pipe(withLatestFrom(viewport$))
.subscribe(([url, { offset }]) => {
history.scrollRestoration = "manual"
// While it would be better UX to defer the history state change until the
// document was fully fetched and parsed, we must schedule it here, since
// popstate events are emitted when history state changes happen. Moreover
// we need to back up the current viewport offset, so we can restore it
// when popstate events occur, e.g., when the browser's back and forward
// buttons are used for navigation.
history.replaceState(offset, "")
history.pushState(null, "", url)
})
// Emit URL that should be fetched via instant loading on location subject,
// which was passed into this function. The idea is that instant loading can
// be intercepted by other parts of the application, which can synchronously
// back up or restore state before instant loading happens.
instant$.subscribe(location$)
// Fetch document - when fetching, we could use `responseType: document`, but
// since all MkDocs links are relative, we need to make sure that the current
// location matches the document we just loaded. Otherwise any relative links
// in the document might use the old location. If the request fails for some
// reason, we fall back to regular navigation and set the location explicitly,
// which will force-load the page. Furthermore, we must pre-warm the buffer
// for the duplicate check, or the first click on an anchor link will also
// trigger an instant loading event, which doesn't make sense.
const response$ = location$
.pipe(
startWith(getLocation()),
distinctUntilKeyChanged("pathname"),
skip(1),
switchMap(url => request(url)
.pipe(
catchError(() => {
setLocation(url)
return EMPTY
})
)
)
)
// Initialize the DOM parser, parse the returned HTML, and replace selected
// meta tags and components before handing control down to the application.
const dom = new DOMParser()
response$
const document$ = response$
.pipe(
switchMap(res => res.text()),
map(res => dom.parseFromString(res, "text/html"))
)
.subscribe(document$)
/* Replace meta tags and components */
document$
.pipe(
skip(1)
)
.subscribe(replacement => {
switchMap(res => {
const document = dom.parseFromString(res, "text/html")
for (const selector of [
/* Meta tags */
// Meta tags
"title",
"link[rel=canonical]",
"meta[name=author]",
"meta[name=description]",
/* Components */
// Components
"[data-md-component=announce]",
"[data-md-component=container]",
"[data-md-component=header-topic]",
@@ -245,7 +243,7 @@ export function setupInstantLoading(
: []
]) {
const source = getOptionalElement(selector)
const target = getOptionalElement(selector, replacement)
const target = getOptionalElement(selector, document)
if (
typeof source !== "undefined" &&
typeof target !== "undefined"
@@ -253,68 +251,95 @@ export function setupInstantLoading(
source.replaceWith(target)
}
}
// After meta tags and components were replaced, re-evaluate scripts
// that were provided by the author as part of Markdown files.
const container = getComponentElement("container")
return concat(getElements("script", container))
.pipe(
switchMap(el => {
const script = document.createElement("script")
if (el.src) {
for (const name of el.getAttributeNames())
script.setAttribute(name, el.getAttribute(name)!)
el.replaceWith(script)
// Complete when script is loaded
return new Observable(observer => {
script.onload = () => observer.complete()
})
// Complete immediately
} else {
script.textContent = el.textContent
el.replaceWith(script)
return EMPTY
}
}),
ignoreElements(),
endWith(document)
)
}),
share()
)
// Intercept popstate events, e.g. when using the browser's back and forward
// buttons, and emit new location for fetching and parsing.
const popstate$ = fromEvent<PopStateEvent>(window, "popstate")
popstate$.pipe(map(getLocation))
.subscribe(location$)
// Intercept clicks on anchor links, and scroll document into position. As
// we disabled scroll restoration, we need to do this manually here.
location$
.pipe(
startWith(getLocation()),
bufferCount(2, 1),
switchMap(([prev, next]) => (
prev.pathname === next.pathname &&
prev.hash !== next.hash
)
? of(next)
: EMPTY
)
)
.subscribe(url => {
if (history.state !== null || !url.hash) {
window.scrollTo(0, history.state?.y ?? 0)
} else {
history.scrollRestoration = "auto"
setLocationHash(url.hash)
history.scrollRestoration = "manual"
}
})
/* Re-evaluate scripts */
// After parsing the document, check if the current history entry has a state.
// This may happen when users press the back or forward button to visit a page
// that was already seen. If there's no state, it means a new page was visited
// and we should scroll to the top, unless an anchor is given.
document$.pipe(withLatestFrom(location$))
.subscribe(([, url]) => {
if (history.state !== null || !url.hash) {
window.scrollTo(0, history.state?.y ?? 0)
} else {
setLocationHash(url.hash)
}
})
// If the current history is not empty, register an event listener updating
// the current history state whenever the scroll position changes. This must
// be debounced and cannot be done in popstate, as popstate has already
// removed the entry from the history.
document$
.pipe(
skip(1),
map(() => getComponentElement("container")),
switchMap(el => getElements("script", el)),
concatMap(el => {
const script = h("script")
if (el.src) {
for (const name of el.getAttributeNames())
script.setAttribute(name, el.getAttribute(name)!)
el.replaceWith(script)
/* Complete when script is loaded */
return new Observable(observer => {
script.onload = () => observer.complete()
})
/* Complete immediately */
} else {
script.textContent = el.textContent
el.replaceWith(script)
return EMPTY
}
})
)
.subscribe()
/* Emit history state change */
merge(push$, pop$)
.pipe(
sample(document$)
)
.subscribe(({ url, offset }) => {
if (url.hash && !offset) {
setLocationHash(url.hash)
} else {
window.scrollTo(0, offset?.y || 0)
}
})
/* Debounce update of viewport offset */
viewport$
.pipe(
skipUntil(push$),
debounceTime(250),
distinctUntilKeyChanged("offset")
switchMap(() => viewport$),
distinctUntilKeyChanged("offset"),
debounceTime(100)
)
.subscribe(({ offset }) => {
history.replaceState(offset, "")
})
/* Set viewport offset from history */
merge(push$, pop$)
.pipe(
bufferCount(2, 1),
filter(([a, b]) => a.url.pathname === b.url.pathname),
map(([, state]) => state)
)
.subscribe(({ offset }) => {
window.scrollTo(0, offset?.y || 0)
})
// Return document
return document$
}

View File

@@ -60,9 +60,9 @@ export type SearchHighlightFactoryFn = (query: string) => SearchHighlightFn
export function setupSearchHighlighter(
config: SearchConfig
): SearchHighlightFactoryFn {
// Hack: temporarily remove pure lookaheads
// Hack: temporarily remove pure lookaheads and lookbehinds
const regex = config.separator.split("|").map(term => {
const temp = term.replace(/(\(\?[!=][^)]+\))/g, "")
const temp = term.replace(/(\(\?[!=<][^)]+\))/g, "")
return temp.length === 0 ? "<22>" : term
})
.join("|")

View File

@@ -90,7 +90,7 @@ function renderSearchDocument(
{document.tags && document.tags.map(tag => {
const type = tags
? tag in tags
? `md-tag-icon md-tag-icon--${tags[tag]}`
? `md-tag-icon md-tag--${tags[tag]}`
: "md-tag-icon"
: ""
return (

View File

@@ -47,6 +47,15 @@
// Allow to explicitly use color schemes in nested content
[data-md-color-scheme="default"] {
@extend %root;
// Indicate that the site is rendered with a light color scheme
color-scheme: light;
// Hide images for dark mode
img[src$="#only-dark"],
img[src$="#gh-dark-mode-only"] {
display: none;
}
}
// ----------------------------------------------------------------------------

View File

@@ -34,8 +34,8 @@
.inline {
float: inline-start;
width: px2rem(234px);
margin-top: 0;
margin-inline-end: px2rem(16px);
margin-top: 0;
margin-bottom: px2rem(16px);
// Modifier to move to end (ltr: right, rtl: left)

View File

@@ -64,8 +64,8 @@ a {
// Normalize horizontal separator styles
hr {
display: block;
box-sizing: content-box;
display: block;
height: px2rem(1px);
padding: 0;
overflow: visible;
@@ -90,8 +90,8 @@ img {
// Reset table styles
table {
border-collapse: separate;
border-spacing: 0;
border-collapse: separate;
}
// Reset table cell styles
@@ -103,10 +103,10 @@ th {
// Reset button styles
button {
margin: 0;
padding: 0;
font-size: inherit;
margin: 0;
font-family: inherit;
font-size: inherit;
background: transparent;
border: 0;
}

View File

@@ -44,17 +44,17 @@ body {
body,
input,
aside {
color: var(--md-typeset-color);
font-feature-settings: "kern", "liga";
font-family: var(--md-text-font-family);
font-feature-settings: "kern", "liga";
color: var(--md-typeset-color);
}
// Define monospaced fonts
code,
pre,
kbd {
font-feature-settings: "kern";
font-family: var(--md-code-font-family);
font-feature-settings: "kern";
}
// ----------------------------------------------------------------------------
@@ -96,18 +96,18 @@ kbd {
// Headline on level 1
h1 {
margin: 0 0 px2em(40px, 32px);
color: var(--md-default-fg-color--light);
font-weight: 300;
font-size: px2em(32px);
font-weight: 300;
line-height: 1.3;
color: var(--md-default-fg-color--light);
letter-spacing: -0.01em;
}
// Headline on level 2
h2 {
margin: px2em(40px, 25px) 0 px2em(16px, 25px);
font-weight: 300;
font-size: px2em(25px);
font-weight: 300;
line-height: 1.4;
letter-spacing: -0.01em;
}
@@ -115,8 +115,8 @@ kbd {
// Headline on level 3
h3 {
margin: px2em(32px, 20px) 0 px2em(16px, 20px);
font-weight: 400;
font-size: px2em(20px);
font-weight: 400;
line-height: 1.5;
letter-spacing: -0.01em;
}
@@ -137,9 +137,9 @@ kbd {
h5,
h6 {
margin: px2em(16px, 12.8px) 0;
color: var(--md-default-fg-color--light);
font-weight: 700;
font-size: px2em(12.8px);
font-weight: 700;
color: var(--md-default-fg-color--light);
letter-spacing: -0.01em;
}
@@ -193,9 +193,9 @@ kbd {
code,
pre,
kbd {
font-variant-ligatures: none;
color: var(--md-code-fg-color);
direction: ltr;
font-variant-ligatures: none;
// [print]: Wrap text and hide scollbars
@media print {
@@ -228,14 +228,14 @@ kbd {
// Code block
> code {
display: block;
margin: 0;
padding: px2em(10.5px, 13.6px) px2em(16px, 13.6px);
margin: 0;
overflow: auto;
word-break: normal;
touch-action: auto;
outline-color: var(--md-accent-fg-color);
box-shadow: none;
box-decoration-break: slice;
touch-action: auto;
scrollbar-width: thin;
scrollbar-color: var(--md-default-fg-color--lighter) transparent;
@@ -266,10 +266,10 @@ kbd {
kbd {
display: inline-block;
padding: 0 px2em(8px, 12px);
color: var(--md-default-fg-color);
font-size: px2em(12px);
vertical-align: text-top;
color: var(--md-default-fg-color);
word-break: break-word;
vertical-align: text-top;
background-color: var(--md-typeset-kbd-color);
border-radius: px2rem(2px);
box-shadow:
@@ -289,8 +289,8 @@ kbd {
// Abbreviation
abbr {
text-decoration: none;
border-bottom: px2rem(1px) dotted var(--md-default-fg-color--light);
cursor: help;
border-bottom: px2rem(1px) dotted var(--md-default-fg-color--light);
// Show tooltip for touch devices
@media (hover: none) {
@@ -299,14 +299,14 @@ kbd {
&[title]:is(:focus, :hover)::after {
position: absolute;
inset-inline: px2rem(16px);
margin-top: 2em;
padding: px2rem(4px) px2rem(6px);
color: var(--md-default-bg-color);
margin-top: 2em;
font-size: px2rem(14px);
color: var(--md-default-bg-color);
content: attr(title);
background-color: var(--md-default-fg-color);
border-radius: px2rem(2px);
box-shadow: var(--md-shadow-z3);
content: attr(title);
}
}
}
@@ -338,8 +338,8 @@ kbd {
// Unordered and ordered list
ul,
ol {
margin-inline-start: px2em(10px);
padding: 0;
margin-inline-start: px2em(10px);
// Adjust display mode if not hidden
&:not([hidden]) {
@@ -358,8 +358,8 @@ kbd {
// List element
li {
margin-bottom: 0.5em;
margin-inline-start: px2em(20px);
margin-bottom: 0.5em;
// Adjust spacing
p,
@@ -413,12 +413,6 @@ kbd {
&[align]:only-child {
margin-top: 0;
}
// Hide images for dark mode
&[src$="#only-dark"],
&[src$="#gh-dark-mode-only"] {
display: none;
}
}
// Figure
@@ -453,10 +447,10 @@ kbd {
max-width: 100%;
overflow: auto;
font-size: px2rem(12.8px);
touch-action: auto;
background-color: var(--md-default-bg-color);
border: px2rem(1px) solid var(--md-typeset-table-color);
border-radius: px2rem(2px);
touch-action: auto;
// [print]: Reset display mode so table header wraps when printing
@media print {
@@ -537,11 +531,11 @@ kbd {
height: 1.2em;
margin-inline-start: 0.5em;
vertical-align: text-bottom;
content: "";
transition: background-color 125ms;
mask-image: var(--md-typeset-table-sort-icon);
mask-repeat: no-repeat;
mask-size: contain;
transition: background-color 125ms;
content: "";
}
// Show sort icon on hover
@@ -572,8 +566,8 @@ kbd {
// Data table wrapper
&__table {
display: inline-block;
margin-bottom: 0.5em;
padding: 0 px2rem(16px);
margin-bottom: 0.5em;
// [print]: Reset display mode so table header wraps when printing
@media print {

View File

@@ -43,8 +43,8 @@
// Banner wrapper
&__inner {
margin: px2rem(12px) auto;
padding: 0 px2rem(16px);
margin: px2rem(12px) auto;
font-size: px2rem(14px);
}

View File

@@ -112,7 +112,6 @@ body {
// Add ellipsis in case of overflowing text
.md-ellipsis {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
@@ -152,24 +151,24 @@ body {
// Hack: if we don't set the negative `z-index`, the skip link will force the
// creation of new layers when code blocks are near the header on scrolling
z-index: -1;
margin: px2rem(10px);
padding: px2rem(6px) px2rem(10px);
color: var(--md-default-bg-color);
margin: px2rem(10px);
font-size: px2rem(12.8px);
color: var(--md-default-bg-color);
background-color: var(--md-default-fg-color);
border-radius: px2rem(2px);
outline-color: var(--md-accent-fg-color);
transform: translateY(px2rem(8px));
opacity: 0;
transform: translateY(px2rem(8px));
// Show skip link on focus
&:focus {
z-index: 10;
transform: translateY(0);
opacity: 1;
transition:
transform 250ms cubic-bezier(0.4, 0, 0.2, 1),
opacity 175ms 75ms;
transform: translateY(0);
}
}

View File

@@ -40,10 +40,10 @@
width: px2em(24px);
height: px2em(24px);
color: var(--md-default-fg-color--lightest);
cursor: pointer;
border-radius: px2rem(2px);
outline-color: var(--md-accent-fg-color);
outline-offset: px2rem(2px);
cursor: pointer;
transition: color 250ms;
// [print]: Hide button
@@ -74,12 +74,12 @@
width: px2em(18px);
height: px2em(18px);
margin: 0 auto;
content: "";
background-color: currentcolor;
mask-image: var(--md-clipboard-icon);
mask-position: center;
mask-repeat: no-repeat;
mask-size: contain;
content: "";
}
// Inline clipboard button

View File

@@ -27,13 +27,13 @@
// Show consent
@keyframes consent {
0% {
transform: translateY(100%);
opacity: 0;
transform: translateY(100%);
}
100% {
transform: translateY(0);
opacity: 1;
transform: translateY(0);
}
}

View File

@@ -34,8 +34,8 @@
// Content wrapper
&__inner {
margin: 0 px2rem(16px) px2rem(24px);
padding-top: px2rem(12px);
margin: 0 px2rem(16px) px2rem(24px);
// [screen +]: Adjust spacing between content area and sidebars
@include break-from-device(screen) {
@@ -69,9 +69,9 @@
// a document-level, i.e. linking to related source code files, printing etc.
&__button {
float: inline-end;
padding: 0;
margin: px2rem(8px) 0;
margin-inline-start: px2rem(8px);
padding: 0;
// [print]: Hide buttons
@media print {

View File

@@ -27,20 +27,20 @@
// Dialog
.md-dialog {
position: fixed;
inset-inline-end: px2rem(16px);
bottom: px2rem(16px);
z-index: 4;
min-width: px2rem(222px);
padding: px2rem(8px) px2rem(12px);
pointer-events: none;
background-color: var(--md-default-fg-color);
border-radius: px2rem(2px);
box-shadow: var(--md-shadow-z3);
transform: translateY(100%);
opacity: 0;
transition:
transform 0ms 400ms,
opacity 400ms;
pointer-events: none;
transform: translateY(100%);
inset-inline-end: px2rem(16px);
// [print]: Hide dialog
@media print {
@@ -49,17 +49,17 @@
// Active dialog
&--active {
transform: translateY(0);
pointer-events: initial;
opacity: 1;
transition:
transform 400ms cubic-bezier(0.075, 0.85, 0.175, 1),
opacity 400ms;
pointer-events: initial;
transform: translateY(0);
}
// Dialog wrapper
&__inner {
color: var(--md-default-bg-color);
font-size: px2rem(14px);
color: var(--md-default-bg-color);
}
}

View File

@@ -31,8 +31,8 @@
// Feedback fieldset
fieldset {
margin: 0;
padding: 0;
margin: 0;
border: none;
}
@@ -89,11 +89,11 @@
// Feedback note
&__note {
position: relative;
transform: translateY(px2rem(8px));
opacity: 0;
transition:
transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1),
opacity 150ms;
transform: translateY(px2rem(8px));
// Feedback note value
> * {
@@ -103,8 +103,8 @@
// Show after submission
:disabled & {
transform: translateY(0);
opacity: 1;
transform: translateY(0);
}
}
}

View File

@@ -54,8 +54,9 @@
// a tiny factor seems to get rid of the ellipsis and renders the text as
// it should - see https://bit.ly/2ZUCXQ8
flex-grow: 0.01;
padding-top: px2rem(28px);
padding-bottom: px2rem(8px);
align-items: end;
max-width: 100%;
margin-block: px2rem(20px) px2rem(8px);
overflow: hidden;
outline-color: var(--md-accent-fg-color);
transition: opacity 250ms;
@@ -70,14 +71,15 @@
transform: scaleX(-1);
}
// Footer link to previous page
&--prev {
// [mobile -]: Adjust width to 25/75 and hide title
@include break-to-device(mobile) {
// [mobile -]: Adjust width to 25/75 and hide title
@include break-to-device(mobile) {
// Footer link to previous page
&--prev {
flex-shrink: 0;
// Hide footer title
.md-footer__title {
.md-footer__title {
display: none;
}
}
@@ -97,27 +99,22 @@
// Footer title
&__title {
position: relative;
flex-grow: 1;
max-width: calc(100% - #{px2rem(48px)});
padding: 0 px2rem(20px);
margin-bottom: px2rem(14px);
font-size: px2rem(18px);
line-height: px2rem(48px);
white-space: nowrap;
}
// Footer link button
&__button {
margin: px2rem(4px);
padding: px2rem(8px);
margin: px2rem(4px);
}
// Footer link direction (i.e. prev and next)
&__direction {
position: absolute;
inset-inline: 0;
margin-top: px2rem(-20px);
padding: 0 px2rem(20px);
font-size: px2rem(12.8px);
opacity: 0.7;
}
@@ -151,10 +148,10 @@
// Copyright and theme information
.md-copyright {
width: 100%;
margin: auto px2rem(12px);
padding: px2rem(8px) 0;
color: var(--md-footer-fg-color--lighter);
margin: auto px2rem(12px);
font-size: px2rem(12.8px);
color: var(--md-footer-fg-color--lighter);
// [tablet portrait +]: Show copyright and social links in one line
@include break-from-device(tablet portrait) {
@@ -172,8 +169,8 @@
// Social links
.md-social {
margin: 0 px2rem(8px);
padding: px2rem(4px) 0 px2rem(12px);
margin: 0 px2rem(8px);
// [tablet portrait +]: Show copyright and social links in one line
@include break-from-device(tablet portrait) {

View File

@@ -31,11 +31,11 @@
.md-button {
display: inline-block;
padding: px2em(10px) px2em(32px);
color: var(--md-primary-fg-color);
font-weight: 700;
color: var(--md-primary-fg-color);
cursor: pointer;
border: px2rem(2px) solid currentcolor;
border-radius: px2rem(2px);
cursor: pointer;
transition:
color 125ms,
background-color 125ms,

View File

@@ -28,8 +28,8 @@
// viewport. If this behavior is not desired, just set `position: static`.
.md-header {
position: sticky;
top: 0;
inset-inline: 0;
top: 0;
z-index: 4;
display: block;
color: var(--md-primary-bg-color);
@@ -47,10 +47,10 @@
// Header is hidden
&[hidden] {
transform: translateY(-100%);
transition:
transform 250ms cubic-bezier(0.8, 0, 0.6, 1),
box-shadow 250ms;
transform: translateY(-100%);
}
// Header in shadow state, i.e. shadow is visible
@@ -74,12 +74,12 @@
&__button {
position: relative;
z-index: 1;
margin: px2rem(4px);
padding: px2rem(8px);
margin: px2rem(4px);
color: currentcolor;
vertical-align: middle;
outline-color: var(--md-accent-fg-color);
cursor: pointer;
outline-color: var(--md-accent-fg-color);
transition: opacity 250ms;
// Button on hover
@@ -100,8 +100,8 @@
// Button with logo, pointing to `config.site_url`
&.md-logo {
margin: px2rem(4px);
padding: px2rem(8px);
margin: px2rem(4px);
// [tablet -]: Hide button
@include break-to-device(tablet) {
@@ -159,12 +159,12 @@
// Second header topic - title of the current page
& + & {
z-index: -1;
transform: translateX(px2rem(25px));
pointer-events: none;
opacity: 0;
transition:
transform 400ms cubic-bezier(1, 0.7, 0.1, 0.1),
opacity 150ms;
pointer-events: none;
transform: translateX(px2rem(25px));
// Adjust for right-to-left languages
[dir="rtl"] & {
@@ -182,20 +182,20 @@
&__title {
flex-grow: 1;
height: px2rem(48px);
margin-inline-end: px2rem(8px);
margin-inline-start: px2rem(20px);
margin-inline-end: px2rem(8px);
font-size: px2rem(18px);
line-height: px2rem(48px);
// Header title in active state, i.e. page title is visible
&--active .md-header__topic {
z-index: -1;
transform: translateX(px2rem(-25px));
pointer-events: none;
opacity: 0;
transition:
transform 400ms cubic-bezier(1, 0.7, 0.1, 0.1),
opacity 150ms;
pointer-events: none;
transform: translateX(px2rem(-25px));
// Adjust for right-to-left languages
[dir="rtl"] & {
@@ -205,12 +205,12 @@
// Second header topic - title of the current page
+ .md-header__topic {
z-index: 0;
transform: translateX(0);
pointer-events: initial;
opacity: 1;
transition:
transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1),
opacity 150ms;
pointer-events: initial;
transform: translateX(0);
}
}

View File

@@ -43,8 +43,8 @@
display: block;
padding: 0 px2rem(12px);
overflow: hidden;
color: var(--md-default-fg-color--light);
font-weight: 700;
color: var(--md-default-fg-color--light);
text-overflow: ellipsis;
// Navigaton button
@@ -75,8 +75,8 @@
// Navigation list
&__list {
margin: 0;
padding: 0;
margin: 0;
list-style: none;
}
@@ -171,8 +171,8 @@
&--primary,
&--primary & {
position: absolute;
top: 0;
inset-inline: 0;
top: 0;
z-index: 1;
display: flex;
flex-direction: column;
@@ -194,11 +194,11 @@
position: relative;
height: px2rem(112px);
padding: px2rem(60px) px2rem(16px) px2rem(4px);
color: var(--md-default-fg-color--light);
line-height: px2rem(48px);
color: var(--md-default-fg-color--light);
white-space: nowrap;
background-color: var(--md-default-fg-color--lightest);
cursor: pointer;
background-color: var(--md-default-fg-color--lightest);
// Navigation icon
.md-nav__icon {
@@ -215,23 +215,23 @@
display: block;
width: 100%;
height: 100%;
content: "";
background-color: currentcolor;
mask-image: var(--md-nav-icon--prev);
mask-position: center;
mask-repeat: no-repeat;
mask-size: contain;
content: "";
}
}
// Navigation list
~ .md-nav__list {
overflow-y: auto;
touch-action: pan-y;
background-color: var(--md-default-bg-color);
box-shadow:
0 px2rem(1px) 0 var(--md-default-fg-color--lightest) inset;
scroll-snap-type: y mandatory;
touch-action: pan-y;
// Omit border on first child
> :first-child {
@@ -241,19 +241,19 @@
// Top-level navigation title
&[for="__drawer"] {
color: var(--md-primary-bg-color);
font-weight: 700;
color: var(--md-primary-bg-color);
background-color: var(--md-primary-fg-color);
}
// Button with logo, pointing to `config.site_url`
.md-logo {
position: absolute;
top: px2rem(4px);
inset-inline: px2rem(4px);
top: px2rem(4px);
display: block;
margin: px2rem(4px);
padding: px2rem(8px);
margin: px2rem(4px);
}
}
@@ -280,8 +280,8 @@
// Navigation link
.md-nav__link {
margin-top: 0;
padding: px2rem(12px) px2rem(16px);
margin-top: 0;
// Navigation icon
.md-nav__icon {
@@ -295,12 +295,12 @@
display: block;
width: 100%;
height: 100%;
content: "";
background-color: currentcolor;
mask-image: var(--md-nav-icon--next);
mask-position: center;
mask-repeat: no-repeat;
mask-size: contain;
content: "";
}
}
}
@@ -353,11 +353,11 @@
// Toggle for nested navigation
&__toggle ~ & {
display: flex;
transform: translateX(100%);
opacity: 0;
transition:
transform 250ms cubic-bezier(0.8, 0, 0.6, 1),
opacity 125ms 50ms;
transform: translateX(100%);
// Adjust for right-to-left languages
[dir="rtl"] & {
@@ -367,11 +367,11 @@
// Show nested navigation when toggle is active
&__toggle:checked ~ & {
transform: translateX(0);
opacity: 1;
transition:
transform 250ms cubic-bezier(0.4, 0, 0.2, 1),
opacity 125ms 125ms;
transform: translateX(0);
// Navigation list
> .md-nav__list {
@@ -549,14 +549,7 @@
width: px2rem(18px);
height: px2rem(18px);
border-radius: 100%;
transition:
background-color 250ms,
transform 250ms;
// Adjust for right-to-left languages
[dir="rtl"] & {
transform: rotate(180deg);
}
transition: background-color 250ms;
// Navigation icon on hover
&:hover {
@@ -569,18 +562,25 @@
width: 100%;
height: 100%;
vertical-align: px2rem(-2px);
content: "";
background-color: currentcolor;
border-radius: 100%;
transition: transform 250ms;
mask-image: var(--md-nav-icon--next);
mask-position: center;
mask-repeat: no-repeat;
mask-size: contain;
content: "";
}
// Navigation icon - rotate icon when toggle is active or indeterminate
.md-nav__item--nested .md-nav__toggle:checked ~ .md-nav__link &,
.md-nav__item--nested .md-nav__toggle:indeterminate ~ .md-nav__link & {
transform: rotate(90deg);
// Adjust for right-to-left languages
[dir="rtl"] & {
transform: rotate(180deg);
}
// Navigation icon - rotate icon when toggle is active or indeterminate
.md-nav__item--nested .md-nav__toggle:checked ~ .md-nav__link &,
.md-nav__item--nested .md-nav__toggle:indeterminate ~ .md-nav__link & {
transform: rotate(90deg);
}
}
}
@@ -607,8 +607,8 @@
position: sticky;
top: 0;
z-index: 1;
margin-top: 0;
padding: 0 px2rem(12px);
margin-top: 0;
font-weight: 700;
background: var(--md-default-bg-color);
box-shadow: 0 0 px2rem(8px) px2rem(8px) var(--md-default-bg-color);

View File

@@ -54,17 +54,17 @@
@include break-to-device(tablet portrait) {
position: absolute;
top: px2rem(-20px);
inset-inline-start: px2rem(-44px);
width: px2rem(40px);
height: px2rem(40px);
overflow: hidden;
pointer-events: none;
background-color: var(--md-default-bg-color);
border-radius: px2rem(20px);
transform-origin: center;
transition:
transform 300ms 100ms,
opacity 200ms 200ms;
pointer-events: none;
transform-origin: center;
inset-inline-start: px2rem(-44px);
// Show overlay when search is active
[data-md-toggle="search"]:checked ~ .md-header & {
@@ -79,15 +79,15 @@
@include break-from-device(tablet landscape) {
position: fixed;
top: 0;
inset-inline-start: 0;
width: 0;
height: 0;
background-color: hsla(0, 0%, 0%, 0.54);
cursor: pointer;
background-color: hsla(0, 0%, 0%, 0.54);
transition:
width 0ms 250ms,
height 0ms 250ms,
opacity 250ms;
inset-inline-start: 0;
// Show overlay when search is active
[data-md-toggle="search"]:checked ~ .md-header & {
@@ -134,18 +134,18 @@
@include break-to-device(tablet portrait) {
position: fixed;
top: 0;
inset-inline-start: 0;
z-index: 2;
width: 0;
height: 0;
overflow: hidden;
transform: translateX(5%);
opacity: 0;
transition:
width 0ms 300ms,
height 0ms 300ms,
transform 150ms 150ms cubic-bezier(0.4, 0, 0.2, 1),
opacity 150ms 150ms;
transform: translateX(5%);
inset-inline-start: 0;
// Adjust for right-to-left languages
[dir="rtl"] & {
@@ -156,13 +156,13 @@
[data-md-toggle="search"]:checked ~ .md-header & {
width: 100%;
height: 100%;
transform: translateX(0);
opacity: 1;
transition:
width 0ms 0ms,
height 0ms 0ms,
transform 150ms 150ms cubic-bezier(0.1, 0.7, 0.1, 1),
opacity 150ms 150ms;
transform: translateX(0);
}
}
@@ -259,8 +259,8 @@
// [tablet landscape +]: Header-embedded search
@include break-from-device(tablet landscape) {
padding-inline-start: px2rem(44px);
color: inherit;
font-size: px2rem(16px);
color: inherit;
// Search placeholder
&::placeholder {
@@ -357,11 +357,11 @@
> .md-icon {
margin-inline-start: px2rem(4px);
color: var(--md-default-fg-color--light);
transform: scale(0.75);
opacity: 0;
transition:
transform 150ms cubic-bezier(0.1, 0.7, 0.1, 1),
opacity 150ms;
transform: scale(0.75);
// Hide outline for pointer devices
&:not(.focus-visible) {
@@ -372,9 +372,9 @@
// Show buttons when search is active and input non-empty
[data-md-toggle="search"]:checked ~ .md-header
.md-search__input:valid ~ & {
transform: scale(1);
opacity: 1;
pointer-events: initial;
opacity: 1;
transform: scale(1);
// Search focus icon
&:hover {
@@ -393,8 +393,8 @@
width: 100%;
height: 100%;
padding-inline: px2rem(72px) px2rem(44px);
color: var(--md-default-fg-color--lighter);
font-size: px2rem(18px);
color: var(--md-default-fg-color--lighter);
white-space: nowrap;
opacity: 0;
transition: opacity 50ms;
@@ -445,13 +445,13 @@
&__scrollwrap {
height: 100%;
overflow-y: auto;
background-color: var(--md-default-bg-color);
// Hack: promote to own layer to reduce jitter
backface-visibility: hidden;
// Hack: Chrome 88+ has weird overscroll behavior. Overall, scroll snapping
// seems to be something that is not ready for prime time on some browsers.
// scroll-snap-type: y mandatory;
touch-action: pan-y;
background-color: var(--md-default-bg-color);
// Hack: promote to own layer to reduce jitter
backface-visibility: hidden;
// Mitigiate excessive repaints on non-retina devices
@media (max-resolution: 1dppx) {
@@ -511,9 +511,9 @@
// Search result metadata
&__meta {
padding: 0 px2rem(16px);
color: var(--md-default-fg-color--light);
font-size: px2rem(12.8px);
line-height: px2rem(36px);
color: var(--md-default-fg-color--light);
background-color: var(--md-default-fg-color--lightest);
scroll-snap-align: start;
@@ -525,8 +525,8 @@
// Search result list
&__list {
margin: 0;
padding: 0;
margin: 0;
list-style: none;
// Hack: omit accidental text selection on fast toggle of more button
user-select: none;
@@ -566,8 +566,8 @@
top: 0;
z-index: 1;
display: block;
outline: none;
cursor: pointer;
outline: none;
scroll-snap-align: start;
// Hide native details marker
@@ -584,8 +584,8 @@
// Search result more button
> div {
padding: px2em(12px) px2rem(16px);
color: var(--md-typeset-a-color);
font-size: px2rem(12.8px);
color: var(--md-typeset-a-color);
transition:
color 250ms,
background-color 250ms;
@@ -640,12 +640,12 @@
display: inline-block;
width: 100%;
height: 100%;
content: "";
background-color: currentcolor;
mask-image: var(--md-search-result-icon);
mask-position: center;
mask-repeat: no-repeat;
mask-size: contain;
content: "";
// Adjust for right-to-left languages
[dir="rtl"] & {
@@ -656,17 +656,17 @@
// Typesetted content
.md-typeset {
color: var(--md-default-fg-color--light);
font-size: px2rem(12.8px);
line-height: 1.6;
color: var(--md-default-fg-color--light);
// Search result article title
h1 {
margin: px2rem(11px) 0;
color: var(--md-default-fg-color);
font-weight: 400;
font-size: px2rem(16px);
font-weight: 400;
line-height: 1.4;
color: var(--md-default-fg-color);
// Search term highlighting
mark {
@@ -677,10 +677,10 @@
// Search result section title
h2 {
margin: 0.5em 0;
color: var(--md-default-fg-color);
font-weight: 700;
font-size: px2rem(12.8px);
font-weight: 700;
line-height: 1.6;
color: var(--md-default-fg-color);
// Search term highlighting
mark {
@@ -693,9 +693,9 @@
&__terms {
display: block;
margin: 0.5em 0;
color: var(--md-default-fg-color);
font-size: px2rem(12.8px);
font-style: italic;
color: var(--md-default-fg-color);
}
// Search term highlighting

View File

@@ -40,22 +40,22 @@
background-color: var(--md-default-bg-color);
border-radius: px2rem(2px);
box-shadow: var(--md-shadow-z2);
transform: translate3d(-50%, px2rem(6px), 0);
opacity: 0;
transition:
transform 250ms 375ms,
opacity 250ms 250ms,
max-height 0ms 500ms;
transform: translate3d(-50%, px2rem(6px), 0);
// Selection bubble on parent focus/hover
.md-select:is(:focus-within, :hover) & {
max-height: px2rem(200px);
transform: translate3d(-50%, 0, 0);
opacity: 1;
transition:
transform 250ms cubic-bezier(0.1, 0.7, 0.1, 1),
opacity 250ms,
max-height 0ms;
transform: translate3d(-50%, 0, 0);
}
// Selection bubble handle
@@ -67,18 +67,18 @@
height: 0;
margin-top: px2rem(-4px);
margin-left: px2rem(-4px);
content: "";
border: px2rem(4px) solid transparent;
border-top: 0;
border-bottom-color: var(--md-default-bg-color);
content: "";
}
}
// Selection list
&__list {
max-height: inherit;
margin: 0;
padding: 0;
margin: 0;
overflow: auto;
font-size: px2rem(16px);
list-style-type: none;
@@ -95,8 +95,8 @@
display: block;
width: 100%;
padding-inline: px2rem(12px) px2rem(24px);
outline: none;
cursor: pointer;
outline: none;
transition:
background-color 250ms,
color 250ms;

View File

@@ -45,16 +45,16 @@
@include break-to-device(tablet) {
position: fixed;
top: 0;
inset-inline-start: px2rem(-242px);
z-index: 5;
display: block;
width: px2rem(242px);
height: 100%;
background-color: var(--md-default-bg-color);
transform: translateX(0);
transition:
transform 250ms cubic-bezier(0.4, 0, 0.2, 1),
box-shadow 250ms;
transform: translateX(0);
inset-inline-start: px2rem(-242px);
// Show sidebar when drawer is active
[data-md-toggle="drawer"]:checked ~ .md-container & {

View File

@@ -38,8 +38,8 @@
// Show repository fact
@keyframes fact {
0% {
transform: translateY(100%);
opacity: 0;
transform: translateY(100%);
}
50% {
@@ -47,8 +47,8 @@
}
100% {
transform: translateY(0%);
opacity: 1;
transform: translateY(0%);
}
}
@@ -91,14 +91,14 @@
// Align with margin only (as opposed to normal button alignment)
svg {
margin-top: px2rem(12px);
margin-inline-start: px2rem(12px);
margin-top: px2rem(12px);
}
// Adjust spacing if icon is present
+ .md-source__repository {
margin-inline-start: px2rem(-40px);
padding-inline-start: px2rem(40px);
margin-inline-start: px2rem(-40px);
}
}
@@ -117,8 +117,8 @@
display: flex;
gap: px2rem(8px);
width: 100%;
margin: px2rem(2px) 0 0;
padding: 0;
margin: px2rem(2px) 0 0;
overflow: hidden;
font-size: px2rem(11px);
list-style-type: none;
@@ -147,11 +147,11 @@
height: px2rem(12px);
margin-inline-end: px2rem(2px);
vertical-align: text-top;
content: "";
background-color: currentcolor;
mask-position: center;
mask-repeat: no-repeat;
mask-size: contain;
content: "";
}
// Adjust spacing for 2nd+ fact

View File

@@ -32,8 +32,8 @@
display: block;
width: 100%;
overflow: auto;
color: var(--md-primary-bg-color);
line-height: 1.3;
color: var(--md-primary-bg-color);
background-color: var(--md-primary-fg-color);
// [print]: Hide tabs
@@ -53,9 +53,9 @@
// Navigation tabs list
&__list {
padding: 0;
margin: 0;
margin-inline-start: px2rem(4px);
padding: 0;
overflow: auto;
white-space: nowrap;
list-style: none;
@@ -111,11 +111,11 @@
// Hide tabs upon scrolling - disable transition to minimizes repaints
// while scrolling down, while scrolling up seems to be okay
.md-tabs[hidden] & {
transform: translateY(50%);
opacity: 0;
transition:
transform 0ms 100ms,
opacity 100ms;
transform: translateY(50%);
}
}
}

View File

@@ -43,11 +43,11 @@
// Tag
.md-tag {
display: inline-block;
padding: px2em(4px, 12.8px) px2em(12px, 12.8px);
margin-inline-end: 0.5em;
margin-bottom: 0.5em;
padding: px2em(4px, 12.8px) px2em(12px, 12.8px);
font-weight: 700;
font-size: px2rem(12.8px);
font-weight: 700;
line-height: 1.6;
letter-spacing: initial;
vertical-align: middle;
@@ -86,13 +86,13 @@
height: 1.2em;
margin-right: 0.4em;
vertical-align: text-bottom;
content: "";
background-color: var(--md-default-fg-color--lighter);
transition: background-color 125ms;
mask-image: var(--md-tag-icon);
mask-position: center;
mask-repeat: no-repeat;
mask-size: contain;
transition: background-color 125ms;
content: "";
}
// Linked tag on focus/hover

View File

@@ -71,29 +71,29 @@
z-index: 0;
width: var(--md-tooltip-width);
max-width: calc(100vw - 2 * #{px2rem(16px)});
color: var(--md-default-fg-color);
font-family: var(--md-text-font-family);
color: var(--md-default-fg-color);
background-color: var(--md-default-bg-color);
border-radius: px2rem(2px);
box-shadow: var(--md-shadow-z2);
transform: translateY(px2rem(-8px));
// Hack: promote to own layer to reduce jitter
backface-visibility: hidden;
opacity: 0;
transition:
transform 0ms 250ms,
opacity 250ms,
z-index 250ms;
transform: translateY(px2rem(-8px));
// Hack: promote to own layer to reduce jitter
backface-visibility: hidden;
// Active tooltip
&--active {
z-index: 2;
transform: translateY(0);
opacity: 1;
transition:
transform 250ms cubic-bezier(0.1, 0.7, 0.1, 1),
opacity 250ms,
z-index 0ms;
transform: translateY(0);
}
// Show outline on target and for keyboard devices
@@ -144,11 +144,11 @@
position: relative;
z-index: 0;
margin: 0 1ch;
font-size: px2em(13.6px, 16px);
font-family: var(--md-code-font-family);
outline: none;
font-size: px2em(13.6px, 16px);
cursor: pointer;
user-select: none;
outline: none;
// Hack: increase specificity to override default for anchors
.md-annotation & {
@@ -175,14 +175,14 @@
width: calc(100% + 1.2ch);
width: max(2.2ch, 100% + 1.2ch);
height: 2.2ch;
margin: 0 -0.4ch;
padding: 0 0.4ch;
margin: 0 -0.4ch;
content: "";
background-color: var(--md-default-fg-color--lighter);
border-radius: 2ch;
transition:
color 250ms,
background-color 250ms;
content: "";
// [reduced motion]: Disable animation
@media not all and (prefers-reduced-motion) {
@@ -204,8 +204,8 @@
// Annotation index in code block
code & {
font-size: inherit;
font-family: var(--md-code-font-family);
font-size: inherit;
}
// Annotation index for active tooltip or on hover
@@ -235,9 +235,9 @@
display: inline-block;
padding-bottom: 0.1em;
vertical-align: 0.065em;
transform: scale(1.15);
transition: transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1);
content: attr(data-md-annotation-id);
transition: transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1);
transform: scale(1.15);
// [not print]: if we're not in print mode, show a `+` sign instead of
// the original numbers, as context is already given by the position.

View File

@@ -30,20 +30,21 @@
top: px2rem(48px + 16px);
z-index: 2;
display: block;
margin-inline-start: 50%;
padding: px2rem(8px) px2rem(16px);
color: var(--md-default-fg-color--light);
margin-inline-start: 50%;
font-size: px2rem(14px);
color: var(--md-default-fg-color--light);
cursor: pointer;
background-color: var(--md-default-bg-color);
border-radius: px2rem(32px);
outline: none;
box-shadow: var(--md-shadow-z2);
transform: translate(-50%, 0);
transition:
color 125ms,
background-color 125ms,
transform 125ms cubic-bezier(0.4, 0, 0.2, 1),
opacity 125ms;
transform: translate(-50%, 0);
// [print]: Hide back-to-top button
@media print {
@@ -57,10 +58,10 @@
// Back-to-top button is hidden
&[hidden] {
transform: translate(-50%, px2rem(4px));
pointer-events: none;
opacity: 0;
transition-duration: 0ms;
pointer-events: none;
transform: translate(-50%, px2rem(4px));
// Adjust for right-to-left languages
[dir="rtl"] & {

View File

@@ -58,8 +58,8 @@
top: px2rem(1px);
margin-inline: px2rem(28px) px2rem(8px);
color: inherit;
outline: none;
cursor: pointer;
outline: none;
// Version selection icon
&::after {
@@ -67,12 +67,12 @@
width: px2rem(8px);
height: px2rem(12px);
margin-inline-start: px2rem(8px);
content: "";
background-color: currentcolor;
mask-image: var(--md-version-icon);
mask-position: center;
mask-repeat: no-repeat;
mask-size: contain;
content: "";
}
}
@@ -82,8 +82,8 @@
top: px2rem(3px);
z-index: 3;
max-height: 0;
margin: px2rem(4px) px2rem(16px);
padding: 0;
margin: px2rem(4px) px2rem(16px);
overflow: auto;
color: var(--md-default-fg-color);
list-style-type: none;
@@ -131,8 +131,8 @@
width: 100%;
padding-inline: px2rem(12px) px2rem(24px);
white-space: nowrap;
outline: none;
cursor: pointer;
outline: none;
transition:
color 250ms,
background-color 250ms;

View File

@@ -64,15 +64,15 @@ $admonitions: (
// rendered as collapsible admonitions with summary elements as titles.
.admonition {
display: flow-root;
margin: px2em(20px, 12.8px) 0;
padding: 0 px2rem(12px);
color: var(--md-admonition-fg-color);
margin: px2em(20px, 12.8px) 0;
font-size: px2rem(12.8px);
page-break-inside: avoid;
color: var(--md-admonition-fg-color);
background-color: var(--md-admonition-bg-color);
border: px2rem(1px) solid $clr-blue-a200;
border-radius: px2rem(4px);
box-shadow: var(--md-shadow-z1);
page-break-inside: avoid;
// [print]: Omit shadow as it may lead to rendering errors
@media print {
@@ -115,10 +115,10 @@ $admonitions: (
// Admonition title
.admonition-title {
position: relative;
margin-block: 0;
margin-inline: px2rem(-12px);
padding-block: px2rem(8px);
padding-inline: px2rem(40px) px2rem(12px);
margin-block: 0;
margin-inline: px2rem(-12px);
font-weight: 700;
background-color: color.adjust($clr-blue-a200, $alpha: -0.9);
border: none;
@@ -135,15 +135,15 @@ $admonitions: (
&::before {
position: absolute;
top: px2em(10px);
inset-inline-start: px2rem(12px);
width: px2rem(20px);
height: px2rem(20px);
content: "";
background-color: $clr-blue-a200;
inset-inline-start: px2rem(12px);
mask-image: var(--md-admonition-icon--note);
mask-position: center;
mask-repeat: no-repeat;
mask-size: contain;
content: "";
}
// Inline code block

View File

@@ -36,8 +36,8 @@
// Footnote container
.footnote {
color: var(--md-default-fg-color--light);
font-size: px2rem(12.8px);
color: var(--md-default-fg-color--light);
// Footnote list - omit left indentation
> ol {
@@ -55,15 +55,15 @@
// Show backreferences on footnote focus without transition
&:focus-within .footnote-backref {
transform: translateX(0);
opacity: 1;
transition: none;
transform: translateX(0);
}
// Show backreferences on footnote hover/target
&:is(:hover, :target) .footnote-backref {
transform: translateX(0);
opacity: 1;
transform: translateX(0);
}
// Adjust spacing on first child
@@ -76,8 +76,8 @@
// Footnote reference
.footnote-ref {
font-weight: 700;
font-size: px2em(12px, 16px);
font-weight: 700;
// Hack: increase specificity to override default
html & {
@@ -93,22 +93,22 @@
// Footnote backreference
.footnote-backref {
display: inline-block;
color: var(--md-typeset-a-color);
// Hack: omit Unicode arrow for replacement with icon
font-size: 0;
color: var(--md-typeset-a-color);
vertical-align: text-bottom;
transform: translateX(px2rem(5px));
opacity: 0;
transition:
color 250ms,
transform 250ms 250ms,
opacity 125ms 250ms;
transform: translateX(px2rem(5px));
// [print]: Show footnote backreferences
@media print {
color: var(--md-typeset-a-color);
transform: translateX(0);
opacity: 1;
transform: translateX(0);
}
// Adjust for right-to-left languages
@@ -126,12 +126,12 @@
display: inline-block;
width: px2rem(16px);
height: px2rem(16px);
content: "";
background-color: currentcolor;
mask-image: var(--md-footnotes-icon);
mask-position: center;
mask-repeat: no-repeat;
mask-size: contain;
content: "";
// Adjust for right-to-left languages
[dir="rtl"] & {

View File

@@ -39,8 +39,8 @@
// Arithmatex content
> * {
width: min-content;
margin-inline: auto !important; // stylelint-disable-line
padding: 0 px2rem(16px);
margin-inline: auto !important; // stylelint-disable-line
touch-action: auto;
// MathJax container - see https://bit.ly/3HR8YJ5

View File

@@ -58,8 +58,8 @@
// Critic block
.critic.block {
display: block;
margin: 1em 0;
padding-inline: px2rem(16px);
margin: 1em 0;
overflow: auto;
box-shadow: none;

View File

@@ -69,9 +69,9 @@
display: block;
min-height: px2rem(20px);
padding-inline-end: px2rem(36px);
cursor: pointer;
border-start-start-radius: px2rem(2px);
border-start-end-radius: px2rem(2px);
cursor: pointer;
// Show outline for keyboard devices
&.focus-visible {
@@ -89,17 +89,17 @@
&::after {
position: absolute;
top: px2em(10px);
inset-inline-end: px2rem(8px);
width: px2rem(20px);
height: px2rem(20px);
content: "";
background-color: currentcolor;
transition: transform 250ms;
transform: rotate(0deg);
inset-inline-end: px2rem(8px);
mask-image: var(--md-details-icon);
mask-position: center;
mask-repeat: no-repeat;
mask-size: contain;
transform: rotate(0deg);
transition: transform 250ms;
content: "";
// Adjust for right-to-left languages
[dir="rtl"] & {

View File

@@ -143,8 +143,8 @@
// .gd = Diff, delete
// .gi = Diff, insert
:is(.gd, .gi) {
margin: 0 px2em(-2px);
padding: 0 px2em(2px);
margin: 0 px2em(-2px);
border-radius: px2rem(2px);
}
@@ -159,8 +159,8 @@
// Highlighted line
.hll {
display: block;
margin: 0 px2em(-16px, 13.6px);
padding: 0 px2em(16px, 13.6px);
margin: 0 px2em(-16px, 13.6px);
background-color: var(--md-code-hl-color);
}
@@ -168,10 +168,10 @@
span.filename {
position: relative;
display: flow-root;
margin-top: 1em;
padding: px2em(9px, 13.6px) px2em(16px, 13.6px);
font-weight: 700;
margin-top: 1em;
font-size: px2em(13.6px);
font-weight: 700;
background-color: var(--md-code-bg-color);
border-bottom: px2rem(1px) solid var(--md-default-fg-color--lightest);
border-top-left-radius: px2rem(2px);
@@ -197,14 +197,14 @@
// don't overlay line numbers, as active annotations have a `z-index` of 2.
z-index: 3;
float: left;
padding-left: px2em(16px, 13.6px);
margin-right: px2em(16px, 13.6px);
margin-left: px2em(-16px, 13.6px);
padding-left: px2em(16px, 13.6px);
color: var(--md-default-fg-color--light);
background-color: var(--md-code-bg-color);
box-shadow: px2rem(-1px) 0 var(--md-default-fg-color--lightest) inset;
content: attr(data-linenos);
user-select: none;
background-color: var(--md-code-bg-color);
box-shadow: px2rem(-1px) 0 var(--md-default-fg-color--lightest) inset;
}
// Code block line anchors - Chrome and Safari seem to have a strange bug
@@ -279,10 +279,10 @@
padding: px2em(10.5px, 13.6px) px2em(16px, 13.6px);
padding-right: 0;
font-size: px2em(13.6px);
user-select: none;
background-color: var(--md-code-bg-color);
border-top-left-radius: px2rem(2px);
border-bottom-left-radius: px2rem(2px);
user-select: none;
}
// Code block line numbers container
@@ -329,8 +329,8 @@
// Code block result container
.highlight + .result {
margin-top: calc(-1em + #{px2em(-2px)});
padding: 0 px2em(16px);
margin-top: calc(-1em + #{px2em(-2px)});
overflow: visible;
border: px2rem(1px) solid var(--md-code-bg-color);
border-top-width: px2rem(2px);

View File

@@ -114,13 +114,13 @@
display: block;
width: var(--md-indicator-width);
height: 2px;
content: "";
background: var(--md-accent-fg-color);
transform: translateX(var(--md-indicator-x));
transition:
width 225ms,
transform 250ms;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
content: "";
transform: translateX(var(--md-indicator-x));
}
}
}
@@ -135,13 +135,13 @@
flex-shrink: 0;
width: auto;
padding: px2em(10px, 12.8px) 1.25em px2em(8px, 12.8px);
color: var(--md-default-fg-color--light);
font-weight: 700;
font-size: px2rem(12.8px);
font-weight: 700;
color: var(--md-default-fg-color--light);
white-space: nowrap;
cursor: pointer;
border-bottom: px2rem(2px) solid transparent;
border-radius: px2rem(2px) px2rem(2px) 0 0;
cursor: pointer;
transition:
background-color 250ms,
color 250ms;
@@ -255,10 +255,10 @@
height: px2rem(18px);
margin-top: px2rem(2px);
color: var(--md-default-fg-color--light);
border-radius: 100%;
cursor: pointer;
transition: background-color 250ms;
pointer-events: initial;
cursor: pointer;
border-radius: 100%;
transition: background-color 250ms;
// Tabbed button on hover
&:hover {
@@ -271,6 +271,7 @@
display: block;
width: 100%;
height: 100%;
content: "";
background-color: currentcolor;
transition:
background-color 250ms,
@@ -279,7 +280,6 @@
mask-position: center;
mask-repeat: no-repeat;
mask-size: contain;
content: "";
}
}
@@ -290,6 +290,7 @@
justify-content: start;
width: px2rem(24px);
height: px2rem(38px);
pointer-events: none;
background:
linear-gradient(
to right,
@@ -297,7 +298,6 @@
transparent
);
transition: opacity 125ms;
pointer-events: none;
// Adjust for right-to-left languages
[dir="rtl"] & {
@@ -338,8 +338,8 @@
// Top-level tabbed labels
.md-content__inner > .tabbed-set .tabbed-labels {
max-width: 100vw;
margin: 0 px2rem(-16px);
padding-inline-start: px2rem(16px);
margin: 0 px2rem(-16px);
scroll-padding-inline-start: px2rem(16px);
// Hack: some browsers ignore the right padding on flex containers,
@@ -352,15 +352,15 @@
// Tabbed control previous
~ .tabbed-control--prev {
width: px2rem(40px);
margin-inline-start: px2rem(-16px);
padding-inline-start: px2rem(16px);
margin-inline-start: px2rem(-16px);
}
// Tabbed control next
~ .tabbed-control--next {
width: px2rem(40px);
margin-inline-end: px2rem(-16px);
padding-inline-end: px2rem(16px);
margin-inline-end: px2rem(-16px);
}
}
}

View File

@@ -61,15 +61,15 @@
.task-list-indicator::before {
position: absolute;
top: 0.15em;
inset-inline-start: px2em(-24px);
width: px2em(20px);
height: px2em(20px);
content: "";
background-color: var(--md-default-fg-color--lightest);
inset-inline-start: px2em(-24px);
mask-image: var(--md-tasklist-icon);
mask-position: center;
mask-repeat: no-repeat;
mask-size: contain;
content: "";
}
// Tasklist indicator in checked state

View File

@@ -24,8 +24,8 @@
// Rules
// ----------------------------------------------------------------------------
// All definitions
.mermaid {
// Mermaid variables
:root > * {
--md-mermaid-font-family: var(--md-text-font-family), sans-serif;
// Colors
@@ -34,8 +34,12 @@
--md-mermaid-node-fg-color: var(--md-accent-fg-color);
--md-mermaid-label-bg-color: var(--md-default-bg-color);
--md-mermaid-label-fg-color: var(--md-code-fg-color);
}
// Mermaid container
// ----------------------------------------------------------------------------
// Mermaid container
.mermaid {
margin: 1em 0;
line-height: normal;
}

View File

@@ -30,6 +30,9 @@
// Slate theme, i.e. dark mode
[data-md-color-scheme="slate"] {
// Indicate that the site is rendered with a dark color scheme
color-scheme: dark;
// Slate's hue in the range [0,360] - change this variable to alter the tone
// of the theme, e.g. to make it more redish or greenish. This is a slate-
// specific variable, but the same approach may be adapted to custom themes.
@@ -110,12 +113,6 @@
img[src$="#gh-light-mode-only"] {
display: none;
}
// Show images for dark mode
img[src$="#only-dark"],
img[src$="#gh-dark-mode-only"] {
display: initial;
}
}
// --------------------------------------------------------------------------

View File

@@ -165,8 +165,8 @@
{% set palette = palette | first %}
{% endif %}
{% set scheme = palette.scheme | d("default", true) %}
{% set primary = palette.primary | d("", true) %}
{% set accent = palette.accent | d("", true) %}
{% set primary = palette.primary | d("indigo", true) %}
{% set accent = palette.accent | d("indigo", true) %}
<body
dir="{{ direction }}"
data-md-color-scheme="{{ scheme | replace(' ', '-') }}"
@@ -338,15 +338,15 @@
<!-- Back-to-top button -->
{% if "navigation.top" in features %}
<a
href="#"
<button
type="button"
class="md-top md-icon"
data-md-component="top"
hidden
>
{% include ".icons/material/arrow-up.svg" %}
{{ lang.t("top") }}
</a>
</button>
{% endif %}
</main>
@@ -424,7 +424,11 @@
<!-- Custom JavaScript -->
{% for path in config.extra_javascript %}
<script src="{{ path | url }}"></script>
{% if path.endswith(".mjs") %}
<script type="module" src="{{ path | url }}"></script>
{% else %}
<script src="{{ path | url }}"></script>
{% endif %}
{% endfor %}
{% endblock %}
</body>

View File

@@ -28,16 +28,6 @@ direction:
# may be a matter of taste
features: []
# Sets the primary and accent color palettes as defined in the Material Design
# documentation - possible values can be looked up in the getting started guide
palette:
# Primary color used for header, sidebar and links, default: indigo
primary:
# Accent color for highlighting user interaction, default: indigo
accent:
# Fonts used by Material, automatically loaded from Google Fonts - see the site
# for a list of available fonts
font:

View File

@@ -48,10 +48,10 @@
{% include ".icons/material/arrow-left.svg" %}
</div>
<div class="md-footer__title">
<span class="md-footer__direction">
{{ direction }}
</span>
<div class="md-ellipsis">
<span class="md-footer__direction">
{{ direction }}
</span>
{{ page.previous_page.title }}
</div>
</div>
@@ -68,10 +68,10 @@
rel="next"
>
<div class="md-footer__title">
<span class="md-footer__direction">
{{ direction }}
</span>
<div class="md-ellipsis">
<span class="md-footer__direction">
{{ direction }}
</span>
{{ page.next_page.title }}
</div>
</div>

View File

@@ -23,7 +23,9 @@
<!-- Determine base classes -->
{% set class = "md-header" %}
{% if "navigation.tabs.sticky" in features %}
{% set class = class ~ " md-header--lifted" %}
{% set class = class ~ " md-header--shadow md-header--lifted" %}
{% elif "navigation.tabs" not in features %}
{% set class = class ~ " md-header--shadow" %}
{% endif %}
<!-- Header -->
@@ -70,37 +72,41 @@
</div>
<!-- Color palette -->
{% if not config.theme.palette is mapping %}
<form class="md-header__option" data-md-component="palette">
{% for option in config.theme.palette %}
{% set scheme = option.scheme | d("default", true) %}
<input
class="md-option"
data-md-color-media="{{ option.media }}"
data-md-color-scheme="{{ scheme | replace(' ', '-') }}"
data-md-color-primary="{{ option.primary | replace(' ', '-') }}"
data-md-color-accent="{{ option.accent | replace(' ', '-') }}"
{% if config.theme.palette %}
{% if not config.theme.palette is mapping %}
<form class="md-header__option" data-md-component="palette">
{% for option in config.theme.palette %}
{% set scheme = option.scheme | d("default", true) %}
{% set primary = option.primary | d("indigo", true) %}
{% set accent = option.accent | d("indigo", true) %}
<input
class="md-option"
data-md-color-media="{{ option.media }}"
data-md-color-scheme="{{ scheme | replace(' ', '-') }}"
data-md-color-primary="{{ primary | replace(' ', '-') }}"
data-md-color-accent="{{ accent | replace(' ', '-') }}"
{% if option.toggle %}
aria-label="{{ option.toggle.name }}"
{% else %}
aria-hidden="true"
{% endif %}
type="radio"
name="__palette"
id="__palette_{{ loop.index }}"
/>
{% if option.toggle %}
aria-label="{{ option.toggle.name }}"
{% else %}
aria-hidden="true"
<label
class="md-header__button md-icon"
title="{{ option.toggle.name }}"
for="__palette_{{ loop.index0 or loop.length }}"
hidden
>
{% include ".icons/" ~ option.toggle.icon ~ ".svg" %}
</label>
{% endif %}
type="radio"
name="__palette"
id="__palette_{{ loop.index }}"
/>
{% if option.toggle %}
<label
class="md-header__button md-icon"
title="{{ option.toggle.name }}"
for="__palette_{{ loop.index0 or loop.length }}"
hidden
>
{% include ".icons/" ~ option.toggle.icon ~ ".svg" %}
</label>
{% endif %}
{% endfor %}
</form>
{% endfor %}
</form>
{% endif %}
{% endif %}
<!-- Site language selector -->

View File

@@ -45,7 +45,7 @@
{% set modifier = "--" ~ type %}
{% endif %}
{% set _ = style.append(
".md-tag-icon" ~ modifier ~ "{" ~
".md-tag" ~ modifier ~ "{" ~
"--md-tag-icon:" ~
"url('data:image/svg+xml;charset=utf-8," ~
icon | replace("\n", "") ~

View File

@@ -25,25 +25,52 @@
"language": "bn",
"action.edit": "এই পেজ এডিট করুন",
"action.skip": "কনটেন্টে যান",
"action.view": "পেজের ভিউ",
"announce.dismiss": "আর কখনো দেখাবে না",
"blog.archive": "সংরক্ষণাগার",
"blog.categories": "বিভাগ",
"blog.categories.in": "বিভাগের মধ্যে",
"blog.continue": "পড়তে থাকুন",
"blog.draft": "খসড়া",
"blog.index": "ইনডেক্সে ফিরে যান",
"blog.meta": "মেটাডেটা",
"blog.references": "সম্পর্কিত লিংক",
"clipboard.copy": "ক্লিপবোর্ডে কপি করুন",
"clipboard.copied": "ক্লিপবোর্ডে কপি হয়েছে",
"consent.accept": "গ্রহণ",
"consent.manage": "সেটিংস ব্যবস্থাপনা",
"consent.reject": "প্রত্যাখ্যান",
"footer": "ফুটার",
"footer.next": "পরে",
"footer.previous": "পূর্ববর্তী",
"header": "হেডার",
"meta.comments": "কমেন্ট",
"meta.source": "সোর্স",
"meta.comments": "মন্তব্য",
"meta.source": "উৎস",
"nav": "ন্যাভিগেশন",
"readtime.one": "১ মিনিট পড়া",
"readtime.other": "# মিনিট পড়া",
"rss.created": "আরএসএস ফিড",
"rss.updated": "আপডেট করা বিষয়বস্তুর আরএসএস ফিড",
"search": "অনুসন্ধান করুন",
"search.config.pipeline": " ",
"search.placeholder": "সার্চ",
"search.reset": "মুছে ফেলুন",
"search.placeholder": "অনুসন্ধান করুন",
"search.share": "শেয়ার",
"search.reset": "রিসেট",
"search.result.initializer": "অনুসন্ধান শুরু করা হচ্ছে",
"search.result.placeholder": "সার্চ টাইপ করুন",
"search.result.none": "কিছু পাওয়া যায়নি",
"search.result.one": "১ টা ডকুমেন্ট",
"search.result.other": "# টা ডকুমেন্ট",
"search.result.more.one": "এই পৃষ্ঠায় আরও ১টি আছে",
"search.result.more.other": "এই পৃষ্ঠায় আরও #টি আছে",
"search.result.term.missing": "অনুপস্থিত",
"select.language": "ভাষা নির্বাচন করুণ",
"select.version": "সংস্করণ নির্বাচন করুণ",
"source": "রিপোজিটরিতে যান",
"source.file.contributors": "অবদানকারী",
"source.file.date.created": "তৈরি হয়েছে",
"source.file.date.updated": "শেষ আপডেট",
"tabs": "ট্যাব",
"toc": "টেবিল অফ কনটেন্ট"
"toc": "সূচি তালিকা",
"top": "উপরে ফিরে যাও"
}[key] }}{% endmacro %}

View File

@@ -25,19 +25,51 @@
"language": "cs",
"action.edit": "Upravit tuto stránku",
"action.skip": "Přeskočit obsah",
"action.view": "Zobrazit zdroj této stránky",
"announce.dismiss": "Již nezobrazovat",
"blog.archive": "Archiv",
"blog.categories": "Kategorie",
"blog.categories.in": "v",
"blog.continue": "Pokračovat ve čtení",
"blog.draft": "Návrh",
"blog.index": "Zpět na index",
"blog.meta": "Metadata",
"blog.references": "Související odkazy",
"clipboard.copy": "Kopírovat do schránky",
"clipboard.copied": "Zkopírováno do schránky",
"consent.accept": "Akceptovat",
"consent.manage": "Spravovat nastavení",
"consent.reject": "Odmítnout",
"footer": "Zápatí",
"footer.next": "Další",
"footer.previous": "Předchozí",
"header": "Záhlaví",
"meta.comments": "Komentáře",
"meta.source": "Zdroj",
"nav": "Navigace",
"readtime.one": "1 min čtení",
"readtime.other": "# min čtení",
"rss.created": "RSS kanál",
"rss.updated": "RSS zdroj aktualizovaného obsahu",
"search": "Vyhledávání",
"search.placeholder": "Hledat",
"search.share": "Sdílet",
"search.reset": "Vyčistit",
"search.result.initializer": "Inicializace vyhledávání",
"search.result.placeholder": "Pište co se má vyhledat",
"search.result.none": "Nenalezeny žádné dokumenty",
"search.result.one": "Nalezený dokument: 1",
"search.result.other": "Nalezené dokumenty: #",
"search.result.more.one": "1 další na této stránce",
"search.result.more.other": "# více na této stránce",
"search.result.term.missing": "Chybějící",
"select.language": "Zvolte jazyk",
"select.version": "Vyberte verzi",
"source": "Přejít do repozitáře",
"source.file.contributors": "Přispěvatelé",
"source.file.date.created": "Vytvořeno",
"source.file.date.updated": "Poslední aktualizace",
"toc": "Obsah"
"tabs": "Karty",
"toc": "Obsah",
"top": "Zpět na začátek"
}[key] }}{% endmacro %}

View File

@@ -25,20 +25,52 @@
"language": "da",
"action.edit": "Redigér denne side",
"action.skip": "Gå til indholdet",
"action.view": "Vis kildetekst på denne side",
"announce.dismiss": "Vis ikke dette igen",
"blog.archive": "Arkiv",
"blog.categories": "Kategorier",
"blog.categories.in": "i",
"blog.continue": "Læs mere",
"blog.draft": "Udkast",
"blog.index": "Gå tilbage",
"blog.meta": "Metadata",
"blog.references": "Relateret indhold",
"clipboard.copy": "Kopiér til udklipsholderen",
"clipboard.copied": "Kopieret til udklipsholderen",
"consent.accept": "Accepter",
"consent.manage": "Administrer indstillinger",
"consent.reject": "Afvis",
"footer": "Sidefod",
"footer.next": "Næste",
"footer.previous": "Forrige",
"header": "Sidehoved",
"meta.comments": "Kommentarer",
"meta.source": "Kilde",
"nav": "Navigation",
"readtime.one": "1 minuts læsetid",
"readtime.other": "# minuts læstid",
"rss.created": "RSS feed",
"rss.updated": "RSS feed af opdateret indhold",
"search": "Søg",
"search.config.lang": "da",
"search.placeholder": "Søg",
"search.share": "Del",
"search.reset": "Nulstil søgning",
"search.result.initializer": "Start søgning",
"search.result.placeholder": "Indtast søgeord",
"search.result.none": "Ingen resultater fundet",
"search.result.one": "1 resultat",
"search.result.other": "# resultater",
"search.result.more.one": "1 resultat mere på denne side",
"search.result.more.other": "# resultater mere på denne side",
"search.result.term.missing": "Mangler",
"select.language": "Vælg sprog",
"select.version": "Vælg version",
"source": "Åbn arkiv",
"source.file.contributors": "Bidragydere",
"source.file.date.created": "Oprettet",
"source.file.date.updated": "Sidste ændring",
"toc": "Indholdsfortegnelse"
"tabs": "Faner",
"toc": "Indholdsfortegnelse",
"top": "Tilbage til start"
}[key] }}{% endmacro %}

View File

@@ -25,8 +25,20 @@
"language": "el",
"action.edit": "Επεξεργασία αυτής της σελίδας",
"action.skip": "Μετάβαση στο περιεχόμενο",
"action.view": "Προβολή πηγαίου κώδικα",
"announce.dismiss": "Μην το ξαναδείξετε αυτό",
"blog.archive": "Aρχείο",
"blog.categories": "Κατηγορίες",
"blog.categories.in": "Στο",
"blog.continue": "Περισσότερα",
"blog.draft": "Πρόχειρο",
"blog.index": "Eπιστροφή",
"blog.references": "Σχετικοί σύνδεσμοι",
"clipboard.copy": "Αντιγραφή στο πρόχειρο",
"clipboard.copied": "Αντιγράφηκε στο πρόχειρο",
"consent.accept": "Αποδοχή",
"consent.manage": "Περισσότερες επιλογές",
"consent.reject": "Απόρριψη",
"footer": "Υποσέλιδο",
"footer.next": "Επόμενο",
"footer.previous": "Προηγούμενο",
@@ -34,21 +46,26 @@
"meta.comments": "Σχόλια",
"meta.source": "Πηγή",
"nav": "Πλοήγηση",
"readtime.one": "1 λεπτό διάβασμα",
"readtime.other": "# λεπτά διάβασμα",
"rss.created": "Ροές Δεδομένων RSS",
"rss.updated": "Ροές Δεδομένων RSS. Τελευταία νέα",
"search": "Αναζήτηση",
"search.placeholder": "Αναζήτηση",
"search.share": "Διαμοίραση",
"search.reset": "Καθαρισμός",
"search.result.initializer": "Αρχικοποίηση αναζήτησης",
"search.result.placeholder": "Πληκτρολογήστε για να αρχίσει η αναζήτηση",
"search.result.none": "Δεν βρέθηκαν αντίστοιχα αρχεία",
"search.result.one": "1 έγγραφο ταιριάζει",
"search.result.other": "# έγγραφα ταιριάζουν",
"search.result.none": "δεν βρήκε κάποιο έγγραφο",
"search.result.one": "1 έγγραφο που ταιριάζει",
"search.result.other": "# έγγραφα που ταιριάζουν",
"search.result.more.one": "1 ακόμα σε αυτήν τη σελίδα",
"search.result.more.other": "# ακόμα σε αυτήν τη σελίδα",
"search.result.term.missing": "Λείπει",
"select.language": "Επιλογή γλώσσας",
"select.version": "Επιλογή έκδοσης",
"source": "Μετάβαση στο αποθετήριο",
"source.file.contributors": "Συνεισφέροντες",
"source.file.date.created": "Δημιουργήθηκε",
"source.file.date.updated": "τελευταία ενημέρωση",
"tabs": "Καρτέλες",

View File

@@ -26,20 +26,52 @@
"direction": "rtl",
"action.edit": "این صفحه را ویرایش کنید",
"action.skip": "پرش به محتویات",
"action.view": "محتویات این صفحه را نشان بده",
"announce.dismiss": "این را دیگر نشان نده",
"blog.archive": "بایگانی",
"blog.categories": "دسته‌بندی‌ها",
"blog.categories.in": "در",
"blog.continue": "ادامه به خواندن",
"blog.draft": "پیش‌نویس",
"blog.index": "برگشت به فهرست",
"blog.meta": "فراداده",
"blog.references": "پیوندهای مربوط",
"clipboard.copy": "کپی کردن",
"clipboard.copied": "کپی شد",
"consent.accept": "تایید",
"consent.manage": "مدیریت تنظیمات",
"consent.reject": "رد کردن",
"footer": "پاورقی",
"footer.next": "بعدی",
"footer.previous": "قبلی",
"header": "سرتیتر",
"meta.comments": "نظرات",
"meta.source": "منبع",
"nav": "هدایت",
"readtime.one": "1 دقیقه زمان خواندن",
"readtime.other": "# دقیقه زمان خواندن",
"rss.created": "خوراک آراس‌اس",
"rss.updated": "خوراک آراساس محتویات به‌روز شده",
"search": "جستجو",
"search.config.pipeline": " ",
"search.placeholder": "جستجو",
"search.share": "هم‌رسانی",
"search.reset": "بازنشانی",
"search.result.initializer": "راه‌اندازی جستجو",
"search.result.placeholder": "برای شروع جستجو تایپ کنید",
"search.result.none": "سندی یافت نشد",
"search.result.one": "1 سند یافت شد",
"search.result.other": "# سند یافت شد",
"search.result.more.one": "1 مورد دیگر در این صفحه",
"search.result.more.other": "# مورد دیگر در این صفحه",
"search.result.term.missing": "موجود نیست",
"select.language": "انتخاب زبان",
"select.version": "انتخاب ویرایش",
"source": "رفتن به مخزن",
"source.file.contributors": "مشارکت کنندگان",
"source.file.date.created": "ایجاد شده",
"source.file.date.updated": "اخرین بروزرسانی",
"toc": "فهرست موضوعات"
"tabs": "زبانه‌ها",
"toc": "فهرست موضوعات",
"top": "برگشت به بالا"
}[key] }}{% endmacro %}

View File

@@ -26,7 +26,16 @@
"direction": "rtl",
"action.edit": "עריכת הדף הזה",
"action.skip": "לדלג לתוכן",
"action.view": "צפה במקור של דף זה",
"announce.dismiss": "לא להציג את זה שוב",
"blog.archive": "ארכיון",
"blog.categories": "קטגוריות",
"blog.categories.in": "בתוך",
"blog.continue": "המשך לקרוא",
"blog.draft": "טיוטה",
"blog.index": "חזרה לאינדקס",
"blog.meta": "מטא-נתונים",
"blog.references": "קישורים קשורים",
"clipboard.copy": "העתקה ללוח",
"clipboard.copied": "הועתק ללוח",
"consent.accept": "לקבל",
@@ -39,6 +48,10 @@
"meta.comments": "הערות",
"meta.source": "מקור",
"nav": "ניווט",
"readtime.one": "קריאה 1 דקות",
"readtime.other": "# דקות קריאה",
"rss.created": "RSS הזנת",
"rss.updated": "הזנת RSS של תוכן מעודכן",
"search": "חיפוש",
"search.config.pipeline": " ",
"search.placeholder": "חיפוש",
@@ -47,7 +60,7 @@
"search.result.initializer": "אתחול חיפוש",
"search.result.placeholder": "יש להקליד כדי להתחיל לחפש",
"search.result.none": "אין מסמכים תואמים",
"search.result.one": "1 מסמך תואם",
"search.result.one": "מסמך1 תואם",
"search.result.other": "# מסמך תואם",
"search.result.more.one": "עוד אחד בדף הזה",
"search.result.more.other": "עוד # בדף הזה",
@@ -55,6 +68,7 @@
"select.language": "בחירת שפה",
"select.version": "בחירת גרסה",
"source": "לעבור אל המאגר",
"source.file.contributors": "תורמים",
"source.file.date.created": "נוצר",
"source.file.date.updated": "עדכון אחרון",
"tabs": "לשוניות",

View File

@@ -25,31 +25,49 @@
"language": "hy",
"action.edit": "Խմբագրել այս էջը",
"action.skip": "Անցնել պարունակությանը",
"action.view": "Դիտել այս էջի սկզբնաղբյուրը",
"announce.dismiss": "Այլևս չցուցադրել",
"blog.archive": "Արխիվ",
"blog.categories": "Կատեգորիաներ",
"blog.categories.in": "in",
"blog.continue": "Շարունակել կարդալ",
"blog.draft": "Սևագիր",
"blog.index": "Հետ դեպի ինդեքս",
"blog.meta": "Մետատվյալներ",
"blog.references": "Առնչվող հղումներ",
"clipboard.copy": "Պատճենել",
"clipboard.copied": "Պատճենված է",
"footer": "Վերջնագիր",
"consent.accept": "Ընդունել",
"consent.manage": "Կառավարել կարգավորումները",
"consent.reject": "Մերժել",
"footer": "Էջատակ",
"footer.next": "Հաջորդը",
"footer.previous": "Նախորդը",
"header": "Գլխագիր",
"meta.comments": "Մեկնաբանությունները",
"meta.source": "Աղբյուր",
"nav": "Տեղորոշում",
"search": "Փնտրում",
"readtime.one": "Ընթերցում՝ 1 րոպե",
"readtime.other": "Ընթերցում՝ # րոպե",
"rss.created": "RSS հոսք",
"rss.updated": "Արդիացված բովանդակության RSS հոսք",
"search": "Որոնում",
"search.config.pipeline": " ",
"search.placeholder": "Փնտրել",
"search.placeholder": "Որոնում",
"search.share": "Կիսվել",
"search.reset": "Ջնջել",
"search.result.initializer": "Փնտրում",
"search.result.placeholder": "Մուտքագրեք փնտրելու համար",
"search.result.none": "Համապատասխանություններ չկան",
"search.result.one": "1 համապատասխանություն",
"search.result.other": "# համապատասխանություններ",
"search.result.initializer": "Որոնում",
"search.result.placeholder": "Մուտքագրեք որոնելու համար",
"search.result.none": "Արդյունքներ չկան",
"search.result.one": "1 արդյունք",
"search.result.other": "# արդյունք",
"search.result.more.one": "ևս 1-ը այս էջում",
"search.result.more.other": "ևս #-ը այս էջում",
"search.result.term.missing": "Բացակայում է",
"select.language": "Ընտրել լեզուն",
"select.version": "Ընտրել տարբերակը",
"source": "Դեպի պահոց",
"source.file.contributors": "Հեղինակողներ",
"source.file.date.created": "Ստեղծված է",
"source.file.date.updated": "Վերջին թարմացումը",
"tabs": "Ներդիրներ",

View File

@@ -29,6 +29,7 @@
"announce.dismiss": "Jangan lihat ini lagi",
"blog.archive": "Arsip",
"blog.categories": "Kategori",
"blog.categories.in": "dalam",
"blog.continue": "Lanjut membaca",
"blog.draft": "Draf",
"blog.index": "Kembali ke indeks",

View File

@@ -23,28 +23,53 @@
<!-- Translations: Icelandic -->
{% macro t(key) %}{{ {
"language": "is",
"action.edit": "Ritvinna þessa síðu",
"action.skip": "Hoppa yfir í efni",
"clipboard.copy": "Afrita í klemmuspjald",
"clipboard.copied": "Afritað í klemmuspjald",
"action.edit": "Breyta þessari síðu",
"action.skip": "Hoppa yfir í efnið",
"action.view": "Skoða frumgögn þessarar síðu",
"announce.dismiss": "Ekki sýna þetta aftur",
"blog.archive": "Safn",
"blog.categories": "Flokkar",
"blog.categories.in": "í",
"blog.continue": "Lesa meira",
"blog.draft": "Uppkast",
"blog.index": "Til baka í yfirlit",
"blog.meta": "Lýsigögn",
"blog.references": "Þessu tengt",
"clipboard.copy": "Afrita á klemmuspjald",
"clipboard.copied": "Afritað á klemmuspjald",
"consent.accept": "Samþykkja",
"consent.manage": "Breyta stillingum",
"consent.reject": "Hafna",
"footer": "Síðufótur",
"footer.next": "Næsta",
"footer.previous": "Fyrra",
"footer.previous": "Fyrri",
"header": "Haus",
"meta.comments": "Athugasemdir",
"meta.source": "Grunnur",
"meta.comments": "Umræður",
"meta.source": "Frumgögn",
"nav": "Valmynd",
"search.placeholder": "Leit",
"readtime.one": "1 mín lestur",
"readtime.other": "# mín lestur",
"rss.created": "RSS veita",
"rss.updated": "RSS veita fyrir uppfært innihald",
"search": "Leita",
"search.placeholder": "Leita",
"search.share": "Deila",
"search.reset": "Hreinsa",
"search.result.placeholder": "Sláðu inn til að hefja leit",
"search.result.none": "Engin skjöl fundust",
"search.result.one": "1 skjal fannst",
"search.result.other": "# skjöl fundust",
"search.result.initializer": "Ræsi leitarvél",
"search.result.placeholder": "Byrjaðu að skrifa til að hefja leit",
"search.result.none": "Engar síður fundust",
"search.result.one": "1 síða fannst",
"search.result.other": "# síður fundust",
"search.result.more.one": "1 til viðbótar á þessari síðu",
"search.result.more.other": "# til viðbótar á þessari síðu",
"source": "Fara í gagnahirslu (e. repository)",
"search.result.more.other": "# til viðbótar á þessari síðu",
"search.result.term.missing": "Vantar",
"select.language": "Veldu tungumál",
"select.version": "Veldu útgáfu",
"source": "Fara í gagnageymslu",
"source.file.contributors": "Meðhöfundar",
"source.file.date.created": "Búið til",
"source.file.date.updated": "Síðasta uppfærsla",
"source.file.date.updated": "Síðast uppfært",
"tabs": "Flipar",
"toc": "Efnisyfirlit"
"toc": "Efnisyfirlit",
"top": "Fara aftur efst"
}[key] }}{% endmacro %}

View File

@@ -70,7 +70,7 @@
"select.version": "バージョン切り替え",
"source": "リポジトリへ",
"source.file.contributors": "投稿者",
"source.file.date.created": "作成した",
"source.file.date.created": "作成",
"source.file.date.updated": "最終更新日",
"tabs": "タブ",
"toc": "目次",

View File

@@ -0,0 +1,75 @@
<!--
Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
-->
<!-- Translations: Kannada -->
{% macro t(key) %}{{ {
"language": "kn",
"action.edit": "ಈ ಪುಟವನ್ನು ತಿದ್ದುಪಡಿ ಮಾಡಿ",
"action.skip": "ವಿಷಯಕ್ಕೆ ತೆರಳಿ",
"action.view": "ಈ ಪುಟದ ಮೂಲವನ್ನು ವೀಕ್ಷಿಸಿ",
"announce.dismiss": "ಇದನ್ನು ಮತ್ತೊಮ್ಮೆ ತೋರಿಸಬೇಡಿ",
"blog.archive": "ಹಳೆಯ ಲೇಖನ",
"blog.categories": "ವರ್ಗಗಳು",
"blog.categories.in": "ರಲ್ಲಿ",
"blog.continue": "ಓದು ಮುಂದುವರೆಸಿ",
"blog.draft": "ಆರಂಭಿಕ ಬರವಣಿಗೆ",
"blog.index": "ಸೂಚ್ಯಂಕಕ್ಕೆ ಹಿಂತಿರುಗಿ",
"blog.meta": "ಮಾಹಿತಿಯ ಬಗ್ಗೆ ಮಾಹಿತಿ",
"blog.references": "ಸಂಬಂಧಿತ ಉಲ್ಲೇಖಗಳು",
"clipboard.copy": "ಇದನ್ನು ನಕಲಿಸಿ",
"clipboard.copied": "ಇದನ್ನು ನಕಲು ಮಾಡಿದೆ",
"consent.accept": "ನಾನು ಇದನ್ನು ಒಪ್ಪಿಕೊಳ್ಳುತ್ತೇನೆ",
"consent.manage": "ಸಂರಚನೆಯನ್ನು ನಿರ್ವಹಿಸಿ",
"consent.reject": "ನಾನು ಇದನ್ನು ತಿರಸ್ಕರಿಸುತ್ತೇನೆ",
"footer": "ಅಡಿಟಿಪ್ಪಣಿ",
"footer.next": "ಮುಂದಿನ ಸಂಚಿಕೆ",
"footer.previous": "ಹಿಂದಿನ ಸಂಚಿಕೆ",
"header": "ಮೇಲ್ಟಿಪ್ಪಣಿ",
"meta.comments": "ಪ್ರತಿಕ್ರಿಯೆಗಳು",
"meta.source": "ಮೂಲ",
"nav": "ಸಂಚರಣೆ",
"readtime.one": "ಓದಲು ೧ ನಿಮಿಷ ತೆಗೆದುಕೊಳ್ಳುತ್ತದೆ",
"readtime.other": "ಓದಲು # ನಿಮಿಷಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳುತ್ತದೆ",
"rss.created": "ಆರ್ಎಸ್ಎಸ್ ಸೇವೆ",
"rss.updated": "ಆರ್ಎಸ್ಎಸ್ ಸೇವೆಯಿಂದ ಇತ್ತೀಚಿನ ನವೀಕರಣ",
"search": "ಹುಡುಕಿ",
"search.placeholder": "ಹುಡುಕಿ",
"search.share": "ಹಂಚಿಕೊಳ್ಳಿ",
"search.reset": "ಅಳಿಸು",
"search.result.initializer": "ಹುಡುಕಾಟವನ್ನು ಪ್ರಾರಂಭಿಸಲಾಗುತ್ತಿದೆ",
"search.result.placeholder": "ಬರೆಯುವ ಮೂಲಕ ಹುಡುಕಲು ಪ್ರಾರಂಭಿಸಿ",
"search.result.none": "ಹೊಂದಾಣಿಕೆಯಾಗುವ ದಾಖಲೆಗಳಿಲ್ಲ",
"search.result.one": "೧ ಹೊಂದಾಣಿಕೆಯ ದಾಖಲೆಯಿದೆ",
"search.result.other": "# ಹೊಂದಾಣಿಕೆಯ ದಾಖಲೆಗಳಿವೆ",
"search.result.more.one": "ಈ ಪುಟದಲ್ಲಿ ಇನ್ನೂ ಒಂದು ಕಂಡುಬಂದಿದೆ",
"search.result.more.other": "ಈ ಪುಟದಲ್ಲಿ ಇನ್ನೂ # ಇವೆ",
"search.result.term.missing": "ಕಾಣೆಯಾಗಿದೆ",
"select.language": "ಭಾಷೆಯನ್ನು ಆಯ್ಕೆಮಾಡಿ",
"select.version": "ಆವೃತ್ತಿಯನ್ನು ಆಯ್ಕೆಮಾಡಿ",
"source": "ಭಂಡಾರಕ್ಕೆ ಹೋಗಿ",
"source.file.contributors": "ಕೊಡುಗೆದಾರರು",
"source.file.date.created": "ರಚಿಸಿದ ದಿನಾಂಕ",
"source.file.date.updated": "ಕೊನೆಯ ನವೀಕರಣ ದಿನಾಂಕ",
"tabs": "ವಿವಿಧ ಕಿಟಕಿಗಳು",
"toc": "ವಿಷಯಗಳ ಪಟ್ಟಿ",
"top": "ಮೇಲಕ್ಕೆ ಹಿಂತಿರುಗಿ"
}[key] }}{% endmacro %}

View File

@@ -27,14 +27,30 @@
"action.skip": "콘텐츠로 이동",
"action.view": "페이지소스 보기",
"announce.dismiss": "다시 안보기",
"blog.archive": "아카이브",
"blog.categories": "카테고리",
"blog.categories.in": "카테고리",
"blog.continue": "계속 읽기",
"blog.draft": "임시 저장",
"blog.index": "Index로 돌아가기",
"blog.meta": "메타데이터",
"blog.references": "관련 링크",
"clipboard.copy": "클립보드로 복사",
"clipboard.copied": "클립보드에 복사됨",
"consent.accept": "동의 허락",
"consent.manage": "동의 허락 관리",
"consent.reject": "동의 거부",
"footer": "하단/푸터",
"footer.next": "다음",
"footer.previous": "이전",
"header": "상단/헤더",
"meta.comments": "댓글",
"meta.source": "출처",
"nav": "네비게이션",
"readtime.one": "읽는시간 1분",
"readtime.other": "읽는시간 #분",
"rss.created": "RSS 피드 생성완료",
"rss.updated": "RSS 피드 업데이트완료",
"search": "검색",
"search.config.pipeline": " ",
"search.placeholder": "검색",
@@ -51,8 +67,10 @@
"select.language": "언어설정",
"select.version": "버전 선택",
"source": "저장소로 이동",
"source.file.contributors": "참여자들",
"source.file.date.created": "작성일",
"source.file.date.updated": "마지막 업데이트",
"tabs": "탭",
"toc": "목차",
"top": "맨위로"
}[key] }}{% endmacro %}

View File

@@ -0,0 +1,64 @@
<!--
Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
-->
<!-- Translations: Kurdish (Soranî) -->
{% macro t(key) %}{{ {
"language": "ku",
"direction": "rtl",
"action.edit": "دەستکاری ئەم پەڕە بکە",
"action.skip": "ئەم ناوەڕۆکە بپەڕێنە",
"action.view": "سەرچاوەی ئەم لاپەڕەیە نیشان بدە",
"announce.dismiss": "دووبارە ئەمە پیشان مەدە",
"clipboard.copy": "لەبەرگتنەوە بۆ کلیپبۆرد",
"clipboard.copied": "لەبەرگیرایەوە بۆ کلیپ بۆرد",
"consent.accept": "ڕازیبوون",
"consent.manage": "بەڕیوەبردنی ڕیکخستنەکان",
"consent.reject": "ڕەتکردنەوە",
"footer": "ژێرپەڕە",
"footer.next": "دواتر",
"footer.previous": "پێشتر",
"header": "ناونیشانی بەڕه",
"meta.comments": "لێدوانەکان",
"meta.source": "سەرجاوە",
"nav": "ڕێنیشاندەر",
"search": "گەڕان",
"search.config.pipeline": " ",
"search.placeholder": "گەڕان",
"search.share": "گەڕان",
"search.reset": "سڕینەوە",
"search.result.initializer": "ئامادەکردنی گەڕان",
"search.result.placeholder": "بنووسە بۆ دەستپێکردن بە گەڕان",
"search.result.none": "هیچ بەڵگەنامەیەکی هاوتا نیە",
"search.result.one": "١ بەڵگەنامەی هاوتا",
"search.result.other": "بەڵگەنامەی هاوتا #",
"search.result.more.one": "١ دانەی تر لەسەر ئەم پەڕەیە",
"search.result.more.other": "دانەی تر لەسەر ئەم پەڕەیە #",
"search.result.term.missing": "ونبوو",
"select.language": "زمان دیاریبکە",
"select.version": "وەشان دیاریبکە",
"source": "بڕۆ بۆ کۆگا",
"source.file.date.created": "دروسکت کرا",
"source.file.date.updated": "دوایین نوێکردنەوە",
"tabs": "تابەکان",
"toc": "خشتەی ناوەڕۆکەکان",
"top": "گەڕانەوە بۆ سەرەوە"
}[key] }}{% endmacro %}

View File

@@ -25,8 +25,21 @@
"language": "lt",
"action.edit": "Redaguoti šį puslapį",
"action.skip": "Pereiti prie turinio",
"action.view": "Žiūrėti puslapio šaltinius",
"announce.dismiss": "Daugiau neberodyti",
"blog.archive": "Archyvas",
"blog.categories": "Kategorijos",
"blog.categories.in": "į",
"blog.continue": "Skaityti toliau",
"blog.draft": "Ruošinys",
"blog.index": "Grįžti į indeksą",
"blog.meta": "Meta duomenys",
"blog.references": "Susieja saitai",
"clipboard.copy": "Kopijuoti į iškarpinę",
"clipboard.copied": "Nukopijuota į iškarpinę",
"consent.accept": "Sutikti",
"consent.manage": "Redaguoti nustatymus",
"consent.reject": "Atmesti",
"footer": "Poraštė",
"footer.next": "Sekantis",
"footer.previous": "Ankstesnis",
@@ -34,6 +47,10 @@
"meta.comments": "Komentarai",
"meta.source": "Išeitinis kodas",
"nav": "Navigacija",
"readtime.one": "1 min skaitymo",
"readtime.other": "# min skaitymo",
"rss.created": "RSS šaltinis",
"rss.updated": "RSS šaltinis atnaujinimams",
"search": "Paieška",
"search.config.pipeline": " ",
"search.placeholder": "Paieška",
@@ -50,6 +67,7 @@
"select.language": "Pasirinkti kalbą",
"select.version": "Pasrinkti versiją",
"source": "Eiti į saugyklą",
"source.file.contributors": "Dalininkai",
"source.file.date.created": "Sukurta",
"source.file.date.updated": "Paskutinis atnaujinimas",
"tabs": "Skirtukai",

View File

@@ -25,7 +25,16 @@
"language": "nb",
"action.edit": "Rediger denne siden",
"action.skip": "Gå til innhold",
"action.view": "Vis kildekoden til denne siden",
"announce.dismiss": "Ikke vis dette igjen",
"blog.archive": "Arkiv",
"blog.categories": "Kategorier",
"blog.categories.in": "i",
"blog.continue": "Fortsett å lese",
"blog.draft": "Kladd",
"blog.index": "Tilbake til oversikt",
"blog.meta": "Metadata",
"blog.references": "Relaterte lenker",
"clipboard.copy": "Kopier til utklippstavlen",
"clipboard.copied": "Kopiert til utklippstavlen",
"consent.accept": "Akseptert",
@@ -38,6 +47,10 @@
"meta.comments": "Kommentarer",
"meta.source": "Kilde",
"nav": "Navigasjon",
"readtime.one": "lesteid: 1 min",
"readtime.other": "lesetid: # min",
"rss.created": "RSS feed",
"rss.updated": "Oppdatert RSS feed",
"search": "Søk",
"search.config.lang": "no",
"search.placeholder": "Søk",
@@ -54,6 +67,7 @@
"select.language": "Velg språk",
"select.version": "Velg versjon",
"source": "Gå til kilde",
"source.file.contributors": "Bidragsytere",
"source.file.date.created": "Opprettet",
"source.file.date.updated": "Sist oppdatert",
"tabs": "Faner",

View File

@@ -25,8 +25,21 @@
"language": "pt",
"action.edit": "Editar esta página",
"action.skip": "Ir para o conteúdo",
"action.view": "Ver fonte desta página",
"announce.dismiss": "Não mostrar novamente",
"blog.archive": "Arquivo",
"blog.categories": "Categorias",
"blog.categories.in": "em",
"blog.continue": "Continuar leitura",
"blog.draft": "Rascunho",
"blog.index": "Voltar ao índice",
"blog.meta": "Metadados",
"blog.references": "Ligações relacionadas",
"clipboard.copy": "Copiar para área de transferência",
"clipboard.copied": "Copiado para área de transferência",
"consent.accept": "Aceitar",
"consent.manage": "Gerir configurações",
"consent.reject": "Rejeitar",
"footer": "Rodapé",
"footer.next": "Próximo",
"footer.previous": "Anterior",
@@ -34,6 +47,10 @@
"meta.comments": "Comentários",
"meta.source": "Fonte",
"nav": "Navegação",
"readtime.one": "1 min de leitura",
"readtime.other": "# min de leitura",
"rss.created": "canal RSS",
"rss.updated": "canal RSS com conteúdo atualizado",
"search": "Pesquisar",
"search.config.lang": "pt",
"search.placeholder": "Buscar",
@@ -50,6 +67,7 @@
"select.language": "Selecione o idioma",
"select.version": "Selecione a versão",
"source": "Ir ao repositório",
"source.file.contributors": "Colaboradores",
"source.file.date.created": "Criada",
"source.file.date.updated": "Última atualização",
"tabs": "Abas",

View File

@@ -25,20 +25,52 @@
"language": "ro",
"action.edit": "Editeaza această pagină",
"action.skip": "Sari la conținut",
"action.view": "Vezi sursa acestei pagini",
"announce.dismiss": "Nu mai arăta asta",
"blog.archive": "Arhivează",
"blog.categories": "Categorii",
"blog.categories.in": "în",
"blog.continue": "Continuă să citești",
"blog.draft": "Ciornă",
"blog.index": "Înapoi la index",
"blog.meta": "Metadata",
"blog.references": "Link-uri relevante",
"clipboard.copy": "Copiază în clipboard",
"clipboard.copied": "Copiat în clipboard",
"consent.accept": "Accept",
"consent.manage": "Gestionați setările",
"consent.reject": "Refuz",
"footer": "Subsol",
"footer.next": "Următor",
"footer.previous": "Anterior",
"header": "Antet",
"meta.comments": "Comentarii",
"meta.source": "Sursă",
"nav": "Navigație",
"readtime.one": "1 minut de citit",
"readtime.other": "# minut de citit",
"rss.created": "Flux RSS",
"rss.updated": "Flux RSS cu conținut actualizat",
"search": "Caută",
"search.config.lang": "ro",
"search.placeholder": "Căutare",
"search.share": "Distribuie",
"search.reset": "Resetează",
"search.result.initializer": "Inițializare căutare",
"search.result.placeholder": "Tastează pentru a începe căutarea",
"search.result.none": "Nu a fost găsit niciun document",
"search.result.one": "1 document găsit",
"search.result.other": "# documente găsite",
"search.result.more.one": "Încă 1 pe această pagină",
"search.result.more.other": "Încă # pe această pagină",
"search.result.term.missing": "Lipsă",
"select.language": "Selectează limba",
"select.version": "Selectează versuine",
"source": "Accesează repository-ul",
"source.file.contributors": "Contribuitori",
"source.file.date.created": "Creată",
"source.file.date.updated": "Ultima actualizare",
"toc": "Cuprins"
"tabs": "File",
"toc": "Cuprins",
"top": "Înapoi sus"
}[key] }}{% endmacro %}

View File

@@ -0,0 +1,75 @@
<!--
Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
-->
<!-- Translations: Sanskrit -->
{% macro t(key) %}{{ {
"language": "sa",
"action.edit": "एतत् पृष्ठं सम्पादयतु",
"action.skip": "सामग्रीं त्यजन्तु",
"action.view": "अस्य पृष्ठस्य स्रोतः पश्यन्तु",
"announce.dismiss": "एतत् पुनः न दर्शयतु",
"blog.archive": "लेखागार",
"blog.categories": "श्रेणियाँ",
"blog.categories.in": "इत्यस्मिन्‌",
"blog.continue": "पठनं निरन्तरं कुर्वन्तु",
"blog.draft": "प्रारूप",
"blog.index": "अनुक्रमणिकां प्रति पुनः आगच्छन्तु",
"blog.meta": "परिदत्तांश",
"blog.references": "सन्दर्भाः",
"clipboard.copy": "एतत् प्रतिलिख्यताम्",
"clipboard.copied": "प्रतिलिपितः भवति",
"consent.accept": "अहं तत् स्वीकुर्वन् अस्मि",
"consent.manage": "वविन्यासं प्रबन्धयन्तु",
"consent.reject": "अहं तत् निराकरोमि",
"footer": "पादलेखः",
"footer.next": "अग्रिमः",
"footer.previous": "पूर्वकृत",
"header": "शीर्षकम्",
"meta.comments": "विचाराः",
"meta.source": "स्रोतः",
"nav": "मार्गदर्शनम्",
"readtime.one": "१ निमेषं पठितुं",
"readtime.other": "# निमेषं पठितुं",
"rss.created": "आरएसएस सेवा",
"rss.updated": "आरएसएस सेवातः नवीनतमं अद्यतनम्",
"search": "अन्वेषण",
"search.placeholder": "अन्वेषण",
"search.share": "साझां कुर्वन्तु",
"search.reset": "तत् स्वच्छं कुर्वन्तु",
"search.result.initializer": "अन्वेषणस्य आरम्भः",
"search.result.placeholder": "अन्वेषणं आरभ्य लिखन्तु",
"search.result.none": "मेलयुक्ताः दस्तावेजाः नास्ति",
"search.result.one": "१ मेलकर्ता दस्तावेजः अस्ति",
"search.result.other": "# मेलनदस्तावेजाः सन्ति",
"search.result.more.one": "अस्मिन् पृष्ठे १ अधिकं अस्ति",
"search.result.more.other": "अस्मिन् पृष्ठे # अधिकाः सन्ति",
"search.result.term.missing": "असमेत",
"select.language": "भाषां चिनोतु",
"select.version": "संस्करणं चिनोतु",
"source": "भण्डारं गच्छन्तु",
"source.file.contributors": "अंशदाता",
"source.file.date.created": "ननिर्माणस्य तिथिः",
"source.file.date.updated": "परिवर्तनस्य तिथिः",
"tabs": "दस्तावेजस्य प्रमुखः",
"toc": "सामग्रीसारणी",
"top": "पुनः उपरिभागं प्रति गच्छन्तु"
}[key] }}{% endmacro %}

View File

@@ -25,10 +25,21 @@
"language": "sv",
"action.edit": "Redigera sidan",
"action.skip": "Gå till innehållet",
"action.view": "Visa källkoden för denna sida",
"announce.dismiss": "Visa inte igen",
"blog.archive": "Arkivera",
"blog.categories": "Kategorier",
"blog.categories.in": "i",
"blog.continue": "Fortsätt läsa",
"blog.draft": "Utkast",
"blog.index": "Tillbaka till index",
"blog.meta": "Metadata",
"blog.references": "Relaterade länkar",
"clipboard.copy": "Kopiera till urklipp",
"clipboard.copied": "Kopierat till urklipp",
"consent.accept": "Acceptera",
"consent.manage": "Hantera inställningar",
"consent.reject": "Acceptera inte",
"footer": "Sidfot",
"footer.next": "Nästa",
"footer.previous": "Föregående",
@@ -36,6 +47,10 @@
"meta.comments": "Kommentarer",
"meta.source": "Källa",
"nav": "Navigation",
"readtime.one": "1 min lästid",
"readtime.other": "# min lästid",
"rss.created": "RSS-flöde",
"rss.updated": "RSS-flöde av uppdaterat innehåll",
"search": "Sök",
"search.config.lang": "sv",
"search.placeholder": "Sök",
@@ -46,14 +61,15 @@
"search.result.none": "Inga sökresultat",
"search.result.one": "1 sökresultat",
"search.result.other": "# sökresultat",
"search.result.more.one": "1 till på denna sidan",
"search.result.more.other": "# till på denna sidan",
"search.result.more.one": "1 till på denna sida",
"search.result.more.other": "# till på denna sida",
"search.result.term.missing": "Saknas",
"select.language": "Välj språk",
"select.version": "Välj version",
"source": "Gå till datakatalog",
"source.file.contributors": "Författare",
"source.file.date.created": "Skapad",
"source.file.date.updated": "Senaste uppdaterad",
"source.file.date.updated": "Senast uppdaterad",
"tabs": "Flikar",
"toc": "Innehållsförteckning",
"top": "Tillbaka till toppen"

View File

@@ -0,0 +1,75 @@
<!--
Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
-->
<!-- Translations: Telugu -->
{% macro t(key) %}{{ {
"language": "te",
"action.edit": "ఈ పేజీలో దిద్దుబాట్లు చేయండి",
"action.skip": "సమాచారానికి వెళ్లండి",
"action.view": "నేను ఈ పేజీ యొక్క మూలాన్ని చూడాలనుకుంటున్నాను",
"announce.dismiss": "దీన్ని మళ్లీ చూపవద్దు",
"blog.archive": "పాత వ్యాసం",
"blog.categories": "వర్గాలు",
"blog.categories.in": "లో",
"blog.continue": "చదవడం కొనసాగించండి",
"blog.draft": "ప్రారంభ రచన",
"blog.index": "సూచికకు తిరిగి వెళ్ళు",
"blog.meta": "సమాచారం గురించి సమాచారం",
"blog.references": "సంబంధిత సూచనలు",
"clipboard.copy": "దీనిని అనుకరించు",
"clipboard.copied": "దీనిని అతికించు",
"consent.accept": "నేను దీనిని అంగీకరిస్తున్నాను",
"consent.manage": "ఆకృతీకరణను నిర్వహించండి",
"consent.reject": "నేను దీనిని తిరస్కరిస్తున్నాను",
"footer": "అడిటిప్పణి",
"footer.next": "తదుపరి భాగం",
"footer.previous": "మునుపటి భాగం",
"header": "శీర్షిక విభాగం",
"meta.comments": "అభిప్రాయాలు",
"meta.source": "మూలం",
"nav": "మార్గదర్శక పట్టీ",
"readtime.one": "చదవడానికి ఒక నిమిషం పడుతుంది",
"readtime.other": "చదవడానికి # నిమిషాలు పడుతుంది",
"rss.created": "ఆర్ఎస్ఎస్ సేవ",
"rss.updated": "ఆర్ఎస్ఎస్ సేవ నుండి తాజా నవీకరణ",
"search": "వెతకండి",
"search.placeholder": "వెతకండి",
"search.share": "పంచుకోండి",
"search.reset": "తుడిచివేయు",
"search.result.initializer": "శోధనను ప్రారంభిస్తోంది",
"search.result.placeholder": "రాయడం ద్వారా వెతకడం ప్రారంభించండి",
"search.result.none": "సరిపోలే పత్రాలు లేవు",
"search.result.one": "ఒక సరిపోలే పత్రం",
"search.result.other": "# సరిపోలే పత్రాలు",
"search.result.more.one": "ఈ పేజీలో మరొకటి",
"search.result.more.other": "ఈ పేజీలో ఇంకా # ఉన్నాయి",
"search.result.term.missing": "తప్పిపోయింది",
"select.language": "భాషను ఎంచుకోండి",
"select.version": "సంస్కరణను ఎంచుకోండి",
"source": "భండారానికి వెళ్ళండి",
"source.file.contributors": "సహకారులు",
"source.file.date.created": "సృష్టించబడింది",
"source.file.date.updated": "చివరి నవీకరణ",
"tabs": "వివిధ కిటికీలు",
"toc": "విషయ సూచిక",
"top": "పైకి తిరిగి వెళ్ళు"
}[key] }}{% endmacro %}

View File

@@ -25,20 +25,52 @@
"language": "th",
"action.edit": "แก้ไขหน้านี้",
"action.skip": "ข้ามไปที่เนื้อหา",
"action.view": "ดูแหล่งที่มาของหน้านี้",
"announce.dismiss": "อย่าแสดงสิ่งนี้อีก",
"blog.archive": "คลังเก็บเอกสาร",
"blog.categories": "หมวดหมู่",
"blog.categories.in": "ใย",
"blog.continue": "อ่านต่อไป",
"blog.draft": "ฉบับร่าง",
"blog.index": "กลับไปยังหน้าแรก",
"blog.meta": "คำอธิบายข้อมูล",
"blog.references": "ลิงก์ที่เกี่ยวข้อง",
"clipboard.copy": "คัดลอก",
"clipboard.copied": "คัดลอกแล้ว",
"consent.accept": "ยอมรับ",
"consent.manage": "จัดการการตั้งค่า",
"consent.reject": "ปฏิเสธ",
"footer": "ส่วนท้าย",
"footer.next": "ต่อไป",
"footer.previous": "ก่อนหน้า",
"header": "หัวข้อ",
"meta.comments": "ความคิดเห็น",
"meta.source": "แหล่งที่มา",
"nav": "ตัวนำทาง",
"readtime.one": "อ่าน 1 นาที",
"readtime.other": "อ่าน # นาที",
"rss.created": "ฟีด RSS",
"rss.updated": "ฟีด RSS ของเนื้อหาที่อัปเดต",
"search": "ค้นหา",
"search.config.lang": "th",
"search.placeholder": "ค้นหา",
"search.share": "แบ่งปัน",
"search.reset": "ล้าง",
"search.result.initializer": "กำลังเริ่มต้นการค้นหา",
"search.result.placeholder": "พิมพ์เพื่อเริ่มค้นหา",
"search.result.none": "ไม่พบเอกสารที่ตรงกัน",
"search.result.one": "พบเอกสารที่ตรงกัน",
"search.result.other": "พบ # เอกสารที่ตรงกัน",
"source": "ไปที่ Repository",
"search.result.more.one": "อีกหนึ่งในหน้านี้",
"search.result.more.other": "# เพิ่มเติมในหน้านี้",
"search.result.term.missing": "ไม่พบ",
"select.language": "เลือกภาษา",
"select.version": "เลือกเวอร์ชัน",
"source": "ไปที่พื้นที่เก็บข้อมูล",
"source.file.contributors": "ผู้มีส่วนร่วม",
"source.file.date.created": "สร้าง",
"source.file.date.updated": "สร้าง",
"toc": "สารบัญ"
"tabs": "แท็บ",
"toc": "สารบัญ",
"top": "กลับไปด้านบนสุด"
}[key] }}{% endmacro %}

View File

@@ -25,20 +25,52 @@
"language": "tr",
"action.edit": "Düzenle",
"action.skip": "Ana içeriğe geç",
"action.view": "Sayfanın kaynağını görüntüle",
"announce.dismiss": "Bir daha gösterme",
"blog.archive": "Arşiv",
"blog.categories": "Kategoriler",
"blog.categories.in": "in",
"blog.continue": "Okumaya devam et",
"blog.draft": "Taslak",
"blog.index": "Dizine geri dön",
"blog.meta": "Metadata",
"blog.references": "İlgili bağlantılar",
"clipboard.copy": "Kopyala",
"clipboard.copied": "Kopyalandı",
"consent.accept": "Kabul et",
"consent.manage": "Ayarları yönet",
"consent.reject": "Reddet",
"footer": "Altbilgi",
"footer.next": "Sonraki",
"footer.previous": "Önceki",
"header": "Başlık",
"meta.comments": "Yorumlar",
"meta.source": "Kaynak",
"nav": "Navigasyon",
"readtime.one": "1 dakika okuma",
"readtime.other": "# dakika okuma",
"rss.created": "RSS beslemesi",
"rss.updated": "Güncellenmiş içeriğin RSS beslemesi",
"search": "Ara",
"search.config.lang": "tr",
"search.placeholder": "Ara",
"search.share": "Paylaş",
"search.reset": "Temizle",
"search.result.initializer": "Arama başlatılıyor",
"search.result.placeholder": "Aramaya başlamak için yazın",
"search.result.none": "Eşleşen doküman bulunamadı",
"search.result.one": "1 doküman bulundu",
"search.result.other": "# doküman bulundu",
"search.result.more.one": "Bu sayfada 1 tane daha",
"search.result.more.other": "Bu sayfada # tane daha",
"search.result.term.missing": "Eksik",
"select.language": "Dil seç",
"select.version": "Versiyon seç",
"source": "Depoya git",
"source.file.contributors": "Katkıda bulunanlar",
"source.file.date.created": "Oluşturuldu",
"source.file.date.updated": "Son Güncelleme",
"toc": "İçindekiler"
"tabs": "Sekmeler",
"toc": "İçindekiler",
"top": "Başa dön"
}[key] }}{% endmacro %}

View File

@@ -25,23 +25,54 @@
"language": "zh-Hant",
"action.edit": "編輯此頁",
"action.skip": "跳轉至",
"action.view": "查看源代碼",
"announce.dismiss": "不再顯示此訊息",
"blog.archive": "存檔",
"blog.categories": "分類",
"blog.categories.in": "分類在",
"blog.continue": "繼續閲讀",
"blog.draft": "草稿",
"blog.index": "回到首頁",
"blog.meta": "元數據",
"blog.references": "相關鏈接",
"clipboard.copy": "拷貝",
"clipboard.copied": "已拷貝",
"consent.accept": "接受",
"consent.manage": "管理設置",
"consent.reject": "拒絕",
"footer": "頁脚",
"footer.next": "下一頁",
"footer.previous": "上一頁",
"header": "頁首",
"meta.comments": "評論",
"meta.source": "來源",
"search.config.lang": "ja",
"search.config.pipeline": "stemmer",
"search.config.separator": "[\\s\\-,。]+",
"nav": "導航",
"readtime.one": "需要 1 分鐘閲讀",
"readtime.other": "需要 # 分鐘閲讀",
"rss.created": "簡易資訊聚合",
"rss.updated": "更新之部分的簡易資訊聚合",
"search": "搜尋",
"search.placeholder": "搜尋",
"search.share": "分享",
"search.reset": "清空",
"search.result.initializer": "正在初始化搜尋引擎",
"search.result.placeholder": "鍵入以開始檢索",
"search.result.none": "沒有找到符合條件的結果",
"search.result.one": "找到 1 个符合條件的結果",
"search.result.other": "# 個符合條件的結果",
"search.result.other": "找到 # 個符合條件的結果",
"search.result.more.one": "此頁尚有 1 個符合的項目",
"search.result.more.other": "此頁尚有 # 個符合的項目",
"search.result.term.missing": "缺失",
"select.language": "選擇語言",
"select.version": "選擇版本",
"source": "前往倉庫",
"source.file.contributors": "貢獻者",
"source.file.date.created": "建立日期",
"source.file.date.updated": "最後更新",
"toc": "目錄"
"tabs": "標籤頁",
"toc": "目錄",
"top": "回到頂部"
}[key] }}{% endmacro %}

View File

@@ -22,23 +22,42 @@
<!-- Translations: Chinese (Taiwanese) -->
{% macro t(key) %}{{ {
"language": "zh-Hant",
"language": "zh-TW",
"action.edit": "編輯此頁",
"action.skip": "跳轉到",
"action.view": "查看此頁原始碼",
"announce.dismiss": "不再顯示此訊息",
"blog.archive": "封存",
"blog.categories": "分類",
"blog.categories.in": "於",
"blog.continue": "繼續閱讀",
"blog.draft": "草稿",
"blog.index": "回到主頁",
"blog.meta": "元數據",
"blog.references": "相關連結",
"clipboard.copy": "複製",
"clipboard.copied": "已複製",
"consent.accept": "同意",
"consent.manage": "管理設定",
"consent.reject": "拒絕",
"footer": "頁腳",
"footer.next": "下一頁",
"footer.previous": "上一頁",
"header": "頁首",
"meta.comments": "留言",
"meta.source": "來源",
"nav": "導覽列",
"readtime.one": "需要 1 分鐘閱讀時間",
"readtime.other": "需要 # 分鐘閱讀時間",
"rss.created": "RSS 訂閱",
"rss.updated": "RSS 訂閱內容已更新",
"search": "搜尋",
"search.config.lang": "ja",
"search.config.pipeline": "stemmer",
"search.config.separator": "[\\s\\- 、。,.?;]+",
"search.placeholder": "搜尋",
"search.share": "分享",
"search.reset": "清除",
"search.result.initializer": "正在初始化搜尋引擎",
"search.result.placeholder": "打字進行搜尋",
"search.result.none": "沒有符合的項目",
@@ -46,8 +65,14 @@
"search.result.other": "找到 # 個符合的項目",
"search.result.more.one": "此頁尚有 1 個符合的項目",
"search.result.more.other": "此頁尚有 # 個符合的項目",
"search.result.term.missing": "缺少字詞",
"select.language": "選擇語言",
"select.version": "選擇版本",
"source": "前往倉庫",
"source.file.contributors": "貢獻者",
"source.file.date.created": "建立日期",
"source.file.date.updated": "最後更新",
"toc": "目錄"
"tabs": "標籤",
"toc": "目錄",
"top": "回到頂端"
}[key] }}{% endmacro %}

View File

@@ -32,7 +32,7 @@
{% if config.extra.tags %}
{% set icon = " md-tag-icon" %}
{% if tag.type %}
{% set icon = icon ~ " md-tag-icon--" ~ tag.type %}
{% set icon = icon ~ " md-tag--" ~ tag.type %}
{% endif %}
{% endif %}

View File

@@ -28,7 +28,7 @@
<!-- Table of contents list -->
{% if toc_item.children %}
<nav class="md-nav" aria-label="{{ toc_item.title }}">
<nav class="md-nav" aria-label="{{ toc_item.title | striptags }}">
<ul class="md-nav__list">
{% for toc_item in toc_item.children %}
{% include "partials/toc-item.html" %}

View File

@@ -432,7 +432,8 @@ class Parser(HTMLParser):
# Remove element from skip list
el = self.context.pop()
if el in self.skip:
self.skip.remove(el)
if el.tag not in ["script", "style", "object"]:
self.skip.remove(el)
return
# Render closing tag if kept

View File

@@ -57,8 +57,19 @@ class SocialPluginConfig(Config):
# Options for social cards
cards = opt.Type(bool, default = True)
cards_dir = opt.Type(str, default = "assets/images/social")
cards_color = opt.Type(dict, default = dict())
cards_font = opt.Optional(opt.Type(str))
cards_layout_options = opt.Type(dict, default = {})
# Deprecated options
cards_color = opt.Deprecated(
option_type = opt.Type(dict, default = {}),
message =
"Deprecated, use 'cards_layout_options.background_color' "
"and 'cards_layout_options.color' with 'default' layout"
)
cards_font = opt.Deprecated(
option_type = opt.Type(str),
message = "Deprecated, use 'cards_layout_options.font_family'"
)
# -----------------------------------------------------------------------------
@@ -67,6 +78,7 @@ class SocialPlugin(BasePlugin[SocialPluginConfig]):
def __init__(self):
self._executor = concurrent.futures.ThreadPoolExecutor(4)
self.custom_dir = None
# Retrieve configuration
def on_config(self, config):
@@ -74,6 +86,24 @@ class SocialPlugin(BasePlugin[SocialPluginConfig]):
if not self.config.cards:
return
# Move color options
if self.config.cards_color:
# Move background color to new option
value = self.config.cards_color.get("fill")
if value:
self.config.cards_layout_options["background_color"] = value
# Move color to new option
value = self.config.cards_color.get("text")
if value:
self.config.cards_layout_options["color"] = value
# Move font family to new option
if self.config.cards_font:
value = self.config.cards_font
self.config.cards_layout_options["font_family"] = value
# Check if required dependencies are installed
if not dependencies:
log.error(
@@ -109,7 +139,18 @@ class SocialPlugin(BasePlugin[SocialPluginConfig]):
self.color = colors.get(primary, self.color)
# Retrieve color overrides
self.color = { **self.color, **self.config.cards_color }
options = self.config.cards_layout_options
self.color = {
"fill": options.get("background_color", self.color["fill"]),
"text": options.get("color", self.color["text"])
}
# Retrieve custom_dir path
for user_config in config.user_configs:
custom_dir = user_config.get("theme", {}).get("custom_dir")
if custom_dir:
self.custom_dir = custom_dir
break
# Retrieve logo and font
self._resized_logo_promise = self._executor.submit(self._load_resized_logo, config)
@@ -343,8 +384,15 @@ class SocialPlugin(BasePlugin[SocialPluginConfig]):
if "logo" in theme:
_, extension = os.path.splitext(theme["logo"])
# Load SVG and convert to PNG
path = os.path.join(config.docs_dir, theme["logo"])
# Allow users to put the logo inside their custom_dir (theme["logo"] case)
if self.custom_dir:
custom_dir_logo = os.path.join(self.custom_dir, theme["logo"])
if os.path.exists(custom_dir_logo):
path = custom_dir_logo
# Load SVG and convert to PNG
if extension == ".svg":
return self._load_logo_svg(path)
@@ -352,10 +400,11 @@ class SocialPlugin(BasePlugin[SocialPluginConfig]):
return Image.open(path).convert("RGBA")
# Handle icons
logo = "material/library"
icon = theme["icon"] or {}
if "logo" in icon and icon["logo"]:
logo = icon["logo"]
else:
logo = "material/library"
# Resolve path of package
base = os.path.abspath(os.path.join(
@@ -363,8 +412,15 @@ class SocialPlugin(BasePlugin[SocialPluginConfig]):
"../.."
))
# Load icon data and fill with color
path = f"{base}/.icons/{logo}.svg"
# Allow users to put the logo inside their custom_dir (theme["icon"]["logo"] case)
if self.custom_dir:
custom_dir_logo = os.path.join(self.custom_dir, ".icons", f"{logo}.svg")
if os.path.exists(custom_dir_logo):
path = custom_dir_logo
# Load icon data and fill with color
return self._load_logo_svg(path, self.color["text"])
# Load SVG file and convert to PNG
@@ -382,28 +438,41 @@ class SocialPlugin(BasePlugin[SocialPluginConfig]):
# Retrieve font
def _load_font(self, config):
name = self.config.cards_font
name = self.config.cards_layout_options.get("font_family")
if not name:
# Retrieve from theme (default: Roboto)
theme = config.theme
if theme["font"]:
if isinstance(theme["font"], dict) and "text" in theme["font"]:
name = theme["font"]["text"]
else:
name = "Roboto"
# Retrieve font files, if not already done
files = os.listdir(self.cache)
files = [file for file in files if file.endswith(".ttf") or file.endswith(".otf")] or (
self._load_font_from_google(name)
)
# Google fonts can return varients like OpenSans_Condensed-Regular.ttf so
# we only use the font requested e.g. OpenSans-Regular.ttf
font_filename_base = name.replace(' ', '')
filename_regex = re.escape(font_filename_base)+r"-(\w+)\.[ot]tf$"
# Map available font weights to file paths
font = dict()
for file in files:
match = re.search(r"-(\w+)\.[ot]tf$", file)
if match:
font[match.group(1)] = os.path.join(self.cache, file)
# Check for cached files - note these may be in subfolders
for currentpath, folders, files in os.walk(self.cache):
for file in files:
# Map available font weights to file paths
fname = os.path.join(currentpath, file)
match = re.search(filename_regex, fname)
if match:
font[match.group(1)] = fname
# If none found, fetch from Google and try again
if len(font) == 0:
self._load_font_from_google(name)
for currentpath, folders, files in os.walk(self.cache):
for file in files:
# Map available font weights to file paths
fname = os.path.join(currentpath, file)
match = re.search(filename_regex, fname)
if match:
font[match.group(1)] = fname
# Return available font weights with fallback
return defaultdict(lambda: font["Regular"], font)

View File

@@ -19,7 +19,6 @@
# IN THE SOFTWARE.
import logging
import os
import sys
from collections import defaultdict
@@ -36,6 +35,9 @@ from mkdocs.plugins import BasePlugin
# Tags plugin configuration scheme
class TagsPluginConfig(Config):
enabled = opt.Type(bool, default = True)
# Options for tags
tags_file = opt.Optional(opt.Type(str))
# -----------------------------------------------------------------------------
@@ -46,6 +48,10 @@ class TagsPlugin(BasePlugin[TagsPluginConfig]):
# Initialize plugin
def on_config(self, config):
if not self.config.enabled:
return
# Initialize tags
self.tags = defaultdict(list)
self.tags_file = None
@@ -64,12 +70,20 @@ class TagsPlugin(BasePlugin[TagsPluginConfig]):
# Hack: 2nd pass for tags index page(s)
def on_nav(self, nav, config, files):
if not self.config.enabled:
return
# Resolve tags index page
file = self.config.tags_file
if file:
self.tags_file = self._get_tags_file(files, file)
# Build and render tags index page
def on_page_markdown(self, markdown, page, config, files):
if not self.config.enabled:
return
# Render tags index page
if page.file == self.tags_file:
return self._render_tag_index(markdown)
@@ -79,6 +93,10 @@ class TagsPlugin(BasePlugin[TagsPluginConfig]):
# Inject tags into page (after search and before minification)
def on_page_context(self, context, page, config, nav):
if not self.config.enabled:
return
# Provide tags for page
if "tags" in page.meta:
context["tags"] = [
self._render_tag(tag)
@@ -116,7 +134,7 @@ class TagsPlugin(BasePlugin[TagsPluginConfig]):
classes.append("md-tag-icon")
type = self.tags_map.get(tag)
if type:
classes.append(f"md-tag-icon--{type}")
classes.append(f"md-tag--{type}")
# Render section for tag and a link to each page
classes = " ".join(classes)