publish updates from main (#22709)

Automated pull request for publishing docs updates.

---------

Co-authored-by: Kristiyan Velkov <40764277+kristiyan-velkov@users.noreply.github.com>
Co-authored-by: Arthur <arthur.flageul@docker.com>
This commit is contained in:
github-actions[bot] 2025-05-28 09:44:48 +02:00 committed by GitHub
parent 396060f240
commit 1b2d5b6d39
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
104 changed files with 5217 additions and 4111 deletions

1
.github/labeler.yml vendored
View File

@ -179,7 +179,6 @@ hugo:
- hugo_stats.json
- i18n/**
- layouts/**
- postcss.config.js
- static/**
- tailwind.config.js

View File

@ -1,81 +0,0 @@
@layer components {
.prose {
.highlight,
:not(pre) > code {
font-size: 0.875em;
border: 1px solid;
border-radius: theme("spacing.1");
background: theme("colors.white");
border-color: theme("colors.gray.light.300");
.dark & {
background: theme("colors.gray.dark.200");
border-color: theme("colors.gray.dark.300");
}
}
:not(pre) > code {
background: theme("colors.gray.light.200");
display: inline-block;
margin: 0;
font-weight: 400;
overflow-wrap: anywhere;
padding: 0 4px;
}
table:not(.lntable) code {
overflow-wrap: unset;
white-space: nowrap;
}
/* Indented code blocks */
pre:not(.chroma) {
@apply my-4 overflow-x-auto p-3;
font-size: 0.875em;
border: 1px solid;
border-radius: theme("spacing.1");
background: theme("colors.white");
border-color: theme("colors.gray.light.300");
.dark & {
background: theme("colors.gray.dark.200");
border-color: theme("colors.gray.dark.300");
}
}
.highlight {
@apply my-4 overflow-x-auto p-3;
/* LineTableTD */
.lntd {
vertical-align: top;
padding: 0;
margin: 0;
font-weight: 400;
padding: 0 4px;
&:first-child {
width: 0;
}
}
/* LineTableTD */
.lntd {
vertical-align: top;
padding: 0;
margin: 0;
border: 0;
}
/* LineTable */
.lntable {
display: table;
width: 100%;
border-spacing: 0;
padding: 0;
margin: 0;
border: 0;
/* LineNumberColumnHighlight */
.lntd:first-child .hl {
display: block;
}
}
}
}
}

100
assets/css/components.css Normal file
View File

@ -0,0 +1,100 @@
@layer components {
.card {
@apply mt-2 mb-2 flex flex-col gap-2 rounded-sm border border-gray-200 p-3;
@apply dark:border-gray-700 dark:bg-gray-900;
@apply transition-shadow duration-200;
&:hover,
&:focus {
@apply border-gray-300 dark:border-gray-600;
}
}
.card-link:hover {
@apply !no-underline;
}
.card-header {
@apply mb-2 flex items-center gap-2;
@apply text-gray-700 dark:text-gray-100;
}
.card-icon {
@apply text-gray-700 dark:text-gray-100;
}
.card-img,
.card-img svg {
@apply m-0 flex max-h-5 min-h-5 max-w-5 min-w-5 items-center justify-center fill-current;
}
.card-title {
@apply font-semibold;
}
.card-link {
@apply block text-inherit no-underline hover:underline;
}
.card-description {
@apply text-gray-600;
@apply dark:text-gray-300;
}
.admonition {
@apply relative mb-4 flex w-full flex-col items-start gap-3 rounded-sm px-6 py-4;
@apply bg-gray-50 dark:bg-gray-900;
}
.admonition-header {
@apply flex flex-wrap items-center gap-2;
}
.admonition-title {
@apply font-semibold;
}
.admonition-content {
@apply w-full min-w-0 flex-1 flex-wrap overflow-x-auto break-words;
color: var(--tw-prose-body);
}
.admonition-note {
@apply border-blue-400 bg-blue-50 text-blue-900;
@apply dark:border-blue-600 dark:bg-blue-950 dark:text-blue-100;
}
.admonition-tip {
@apply border-green-400 bg-green-100 text-green-900;
@apply dark:border-green-600 dark:bg-green-950 dark:text-green-100;
}
.admonition-warning {
@apply border-yellow-400 bg-yellow-50 text-yellow-900;
@apply dark:border-yellow-600 dark:bg-yellow-950 dark:text-yellow-100;
}
.admonition-danger {
@apply border-red-400 bg-red-50 text-red-900;
@apply dark:border-red-600 dark:bg-red-950 dark:text-red-100;
}
.admonition-important {
@apply border-purple-400 bg-purple-50 text-purple-900;
@apply dark:border-purple-600 dark:bg-purple-950 dark:text-purple-100;
}
.admonition-icon {
@apply flex-shrink-0;
width: 24px;
height: 24px;
min-width: 24px;
min-height: 24px;
display: flex;
align-items: center;
justify-content: center;
}
.download-links {
@apply block;
@apply text-gray-800;
@apply dark:text-gray-200;
}
.download-links a {
@apply link;
}
.download-links-subcontainer {
@apply flex flex-wrap gap-2;
}
.card-image {
@apply h-12 w-12 overflow-hidden;
}
}
.summary-bar {
@apply my-1 mt-4 flex flex-col rounded-sm border-1 border-gray-100 bg-gray-50 p-4 dark:border-gray-800 dark:bg-gray-900;
}

View File

@ -1,89 +1,106 @@
/* global styles */
@layer base {
[x-cloak=""] {
[x-cloak=""] {
display: none !important;
}
/* alpine cloak for small screens only */
[x-cloak="sm"] {
@media (width <= 768px) {
display: none !important;
}
/* alpine cloak for small screens only */
[x-cloak="sm"] {
@media (width <= 768px) {
display: none !important;
}
}
}
:root {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
:root {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
scrollbar-color: theme(colors.gray.light.400) theme(colors.black / 0.05);
&.dark {
scrollbar-color: theme(colors.gray.dark.800) theme(colors.white / 0.10);
}
}
mark {
@apply bg-transparent font-bold text-blue-light dark:text-blue-dark;
}
/* Hide the clear (X) button for search inputs */
/* Chrome, Safari, Edge, and Opera */
input[type="search"]::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
}
/* Firefox */
input[type="search"]::-moz-search-cancel-button {
display: none;
}
/* Internet Explorer and Edge (legacy) */
input[type="search"]::-ms-clear {
display: none;
scrollbar-color: var(--color-gray-400) rgba(0, 0, 0, 0.05);
&.dark {
scrollbar-color: var(--color-gray-700) rgba(255, 255, 255, 0.1);
}
}
/* utility classes */
mark {
@apply bg-transparent font-bold text-blue-500 dark:text-blue-800;
}
@layer utilities {
.link {
@apply text-blue-light underline underline-offset-2 dark:text-blue-dark;
/* Hide the clear (X) button for search inputs */
/* Chrome, Safari, Edge, and Opera */
input[type="search"]::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
}
/* Firefox */
input[type="search"]::-moz-search-cancel-button {
display: none;
}
/* Internet Explorer and Edge (legacy) */
input[type="search"]::-ms-clear {
display: none;
}
.prose {
code {
@apply !bg-gray-100;
}
.invertible {
@apply dark:hue-rotate-180 dark:invert dark:filter;
}
.bg-pattern-blue {
background-color: theme(colors.white / 50%);
background-image: url('/assets/images/bg-pattern-blue.webp');
background-blend-mode: overlay;
background-size: cover;
background-repeat: none;
& .highlight,
& :not(pre) > code {
.dark & {
background-color: theme(colors.black / 70%);
}
}
.bg-pattern-purple {
background-color: theme(colors.white / 50%);
background-image: url('/assets/images/bg-pattern-purple.webp');
background-blend-mode: overlay;
background-size: cover;
background-repeat: none;
.dark & {
background-color: theme(colors.black / 70%);
}
}
.bg-pattern-verde {
background-color: theme(colors.white / 50%);
background-image: url('/assets/images/bg-pattern-verde.webp');
background-blend-mode: overlay;
background-size: cover;
background-repeat: none;
.dark & {
background-color: theme(colors.black / 70%);
background: var(--color-gray-900) !important;
border-color: var(--color-gray-700) !important;
}
}
}
.prose {
li {
@apply my-2;
> :last-child,
> :first-child {
margin: 0;
}
}
hr {
@apply mt-8 mb-4;
}
:where(h1):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
color: var(--tw-prose-headings);
font-weight: 500 !important;
margin-top: 0;
margin-bottom: 0.2em !important;
line-height: 1.1111111;
}
> h2 {
@apply mt-5! mb-3! text-3xl!;
a {
@apply hover:no-underline!;
}
}
> h3 {
@apply text-2xl!;
a {
@apply hover:no-underline!;
}
}
> h4 {
a {
@apply hover:no-underline!;
}
}
> h5 {
a {
@apply hover:no-underline!;
}
}
ol {
list-style-type: decimal;
}
ol ol {
list-style-type: lower-alpha;
}
ol ol ol {
list-style-type: lower-roman;
}
}

View File

@ -1,29 +0,0 @@
@layer utilities {
.icon-svg {
svg {
font-size: 24px;
width: 1em;
height: 1em;
display: inline-block;
fill: currentColor;
}
}
.icon-xs {
svg {
font-size: 12px;
}
}
.icon-sm {
svg {
font-size: 16px;
}
}
.icon-lg {
svg {
font-size: 32px;
}
}
}

View File

@ -1,12 +0,0 @@
.prose ol {
list-style-type: decimal;
}
.prose ol ol {
list-style-type: lower-alpha;
}
.prose ol ol ol {
list-style-type: lower-roman;
}

45
assets/css/style.css Normal file
View File

@ -0,0 +1,45 @@
/* Main CSS entry point */
@import "tailwindcss";
@plugin "@tailwindcss/typography";
@source "hugo_stats.json";
@font-face {
font-family: "Roboto Flex";
src: url("/assets/fonts/RobotoFlex.woff2") format("woff2");
font-weight: 100 1000; /* Range of weights Roboto Flex supports */
font-stretch: 100%; /* Range of width Roboto Flex supports */
font-style: oblique 0deg 10deg; /* Range of oblique angle Roboto Flex supports */
font-display: fallback;
}
/* Roboto Mono */
@font-face {
font-family: "Roboto Mono";
src: url("/assets/fonts/RobotoMono-Regular.woff2") format("woff2");
font-weight: 100 700; /* Define the range of weight the variable font supports */
font-style: normal;
font-display: fallback;
}
/* Roboto Mono Italic */
@font-face {
font-family: "Roboto Mono";
src: url("/assets/fonts/RobotoMono-Italic.woff2") format("woff2");
font-weight: 100 700; /* Define the range of weight the variable font supports */
font-style: italic;
font-display: fallback;
}
@layer theme {
@import "theme.css";
}
@layer base {
@import "global.css";
}
@import "utilities.css";
@import "syntax-dark.css";
@import "syntax-light.css";
@import "components.css";
@variant dark (&:where(.dark, .dark *));

View File

@ -1,16 +0,0 @@
/* see also: tailwind.config.js */
@import "tailwindcss/base";
@import "/assets/css/global";
@import "/assets/css/typography";
@import "/assets/css/hack";
@import "tailwindcss/components";
@import "/assets/css/code";
@import "/assets/css/toc";
@import "tailwindcss/utilities";
@import "/assets/css/syntax-light";
@import "/assets/css/syntax-dark";
@import "/assets/css/icons";
@import "/assets/css/lists";

View File

@ -1,343 +1,342 @@
@layer utilities {
.syntax-dark {
/* Other */
.x {
color: theme("colors.white");
}
/* Error */
.err {
color: theme("colors.red.dark.500");
}
/* CodeLine */
.cl {
}
/* LineHighlight */
.hl {
min-width: fit-content;
background-color: theme("colors.gray.dark.300");
}
.lntd:first-child .hl,
& > .chroma > code > .hl {
margin-left: -4px;
border-left: 4px solid theme("colors.gray.dark.400");
}
/* LineNumbersTable */
.lnt {
white-space: pre;
user-select: none;
margin-right: 0.4em;
padding: 0 0.4em 0 0.4em;
color: theme("colors.gray.dark.400");
}
/* LineNumbers */
.ln {
white-space: pre;
user-select: none;
margin-right: 0.4em;
padding: 0 0.4em 0 0.4em;
color: theme("colors.gray.dark.400");
}
/* Line */
.line {
display: flex;
}
/* Keyword */
.k {
color: theme("colors.amber.dark.700");
}
/* KeywordConstant */
.kc {
color: theme("colors.violet.dark.700");
}
/* KeywordDeclaration */
.kd {
color: theme("colors.amber.dark.700");
}
/* KeywordNamespace */
.kn {
color: theme("colors.amber.dark.700");
}
/* KeywordPseudo */
.kp {
color: theme("colors.amber.dark.700");
}
/* KeywordReserved */
.kr {
color: theme("colors.amber.dark.700");
}
/* KeywordType */
.kt {
color: theme("colors.amber.dark.700");
}
/* Name */
.n {
color: theme("colors.violet.dark.700");
}
/* NameAttribute */
.na {
color: theme("colors.amber.dark.700");
}
/* NameBuiltin */
.nb {
color: theme("colors.amber.dark.700");
}
/* NameBuiltinPseudo */
.bp {
color: theme("colors.violet.dark.700");
}
/* NameClass */
.nc {
color: theme("colors.white");
}
/* NameConstant */
.no {
color: theme("colors.white");
}
/* NameDecorator */
.nd {
color: theme("colors.violet.dark.700");
}
/* NameEntity */
.ni {
color: theme("colors.amber.dark.700");
}
/* NameException */
.ne {
color: theme("colors.red.dark.700");
}
/* NameFunction */
.nf {
color: theme("colors.blue.dark.600");
}
/* NameFunctionMagic */
.fm {
color: theme("colors.blue.dark.600");
}
/* NameLabel */
.nl {
color: theme("colors.amber.dark.500");
}
/* NameNamespace */
.nn {
color: theme("colors.white");
}
/* NameOther */
.nx {
color: theme("colors.white");
}
/* NameProperty */
.py {
color: theme("colors.white");
}
/* NameTag */
.nt {
color: theme("colors.green.dark.600");
}
/* NameVariable */
.nv {
color: theme("colors.white");
}
/* NameVariableClass */
.vc {
color: theme("colors.violet.dark.600");
}
/* NameVariableGlobal */
.vg {
color: theme("colors.violet.dark.600");
}
/* NameVariableInstance */
.vi {
color: theme("colors.violet.dark.600");
}
/* NameVariableMagic */
.vm {
color: theme("colors.violet.dark.600");
}
/* Literal */
.l {
color: theme("colors.white");
}
/* LiteralDate */
.ld {
color: theme("colors.green.dark.600");
}
/* LiteralString */
.s {
color: theme("colors.white");
}
/* LiteralStringAffix */
.sa {
color: theme("colors.green.dark.600");
}
/* LiteralStringBacktick */
.sb {
color: theme("colors.green.dark.600");
}
/* LiteralStringChar */
.sc {
color: theme("colors.green.dark.600");
}
/* LiteralStringDelimiter */
.dl {
color: theme("colors.green.dark.600");
}
/* LiteralStringDoc */
.sd {
color: theme("colors.green.dark.600");
}
/* LiteralStringDouble */
.s2 {
color: theme("colors.green.dark.600");
}
/* LiteralStringEscape */
.se {
color: theme("colors.white");
}
/* LiteralStringHeredoc */
.sh {
color: theme("colors.green.dark.600");
}
/* LiteralStringInterpol */
.si {
color: theme("colors.green.dark.600");
}
/* LiteralStringOther */
.sx {
color: theme("colors.green.dark.600");
}
/* LiteralStringRegex */
.sr {
color: theme("colors.blue.dark.500");
}
/* LiteralStringSingle */
.s1 {
color: theme("colors.green.dark.600");
}
/* LiteralStringSymbol */
.ss {
color: theme("colors.blue.dark.600");
}
/* LiteralNumber */
.m {
color: theme("colors.blue.dark.600");
}
/* LiteralNumberBin */
.mb {
color: theme("colors.blue.dark.600");
}
/* LiteralNumberFloat */
.mf {
color: theme("colors.blue.dark.600");
}
/* LiteralNumberHex */
.mh {
color: theme("colors.blue.dark.600");
}
/* LiteralNumberInteger */
.mi {
color: theme("colors.blue.dark.600");
}
/* LiteralNumberIntegerLong */
.il {
color: theme("colors.blue.dark.600");
}
/* LiteralNumberOct */
.mo {
color: theme("colors.blue.dark.600");
}
/* Operator */
.o {
color: theme("colors.blue.dark.700");
}
/* OperatorWord */
.ow {
color: theme("colors.amber.dark.700");
}
/* Punctuation */
.p {
color: theme("colors.gray.dark.500");
}
/* Comment */
.c {
color: theme("colors.gray.dark.500");
}
/* CommentHashbang */
.ch {
color: theme("colors.gray.dark.500");
}
/* CommentMultiline */
.cm {
color: theme("colors.gray.dark.500");
}
/* CommentSingle */
.c1 {
color: theme("colors.gray.dark.500");
}
/* CommentSpecial */
.cs {
color: theme("colors.gray.dark.500");
}
/* CommentPreproc */
.cp {
color: theme("colors.gray.dark.500");
}
/* CommentPreprocFile */
.cpf {
color: theme("colors.gray.dark.500");
}
/* Generic */
.g {
color: theme("colors.white");
}
/* GenericDeleted */
.gd {
color: theme("colors.red.dark.500");
}
/* GenericEmph */
.ge {
color: theme("colors.white");
}
/* GenericError */
.gr {
color: theme("colors.red.dark.500");
}
/* GenericHeading */
.gh {
color: theme("colors.gray.dark.600");
}
/* GenericInserted */
.gi {
color: theme("colors.green.dark.500");
}
/* GenericOutput */
.go {
color: theme("colors.white");
}
/* GenericPrompt */
.gp {
user-select: none;
color: theme("colors.green.dark.400");
}
/* GenericStrong */
.gs {
color: theme("colors.white");
}
/* GenericSubheading */
.gu {
color: theme("colors.gray.dark.600");
}
/* GenericTraceback */
.gt {
color: theme("colors.red.dark.500");
}
/* GenericUnderline */
.gl {
color: theme("colors.white");
text-decoration: underline;
}
/* TextWhitespace */
.w {
color: theme("colors.gray.dark.100");
}
@utility syntax-dark {
/* Other */
.x {
color: var(--color-white-main);
}
/* Error */
.err {
color: var(--color-red-500);
}
/* CodeLine */
.cl {
color: var(--color-gray-200);
}
/* LineHighlight */
.hl {
min-width: fit-content;
background-color: var(--color-gray-800);
}
.lntd:first-child .hl,
& > .chroma > code > .hl {
margin-left: -4px;
border-left: 4px solid var(--color-gray-900);
}
/* LineNumbersTable */
.lnt {
white-space: pre;
user-select: none;
margin-right: 0.4em;
padding: 0 0.4em 0 0.4em;
color: var(--color-gray-900);
}
/* LineNumbers */
.ln {
white-space: pre;
user-select: none;
margin-right: 0.4em;
padding: 0 0.4em 0 0.4em;
color: var(--color-gray-900);
}
/* Line */
.line {
display: flex;
}
/* Keyword */
.k {
color: var(--color-yellow-700);
}
/* KeywordConstant */
.kc {
color: var(--color-violet-300);
}
/* KeywordDeclaration */
.kd {
color: var(--color-yellow-700);
}
/* KeywordNamespace */
.kn {
color: var(--color-yellow-700);
}
/* KeywordPseudo */
.kp {
color: var(--color-yellow-700);
}
/* KeywordReserved */
.kr {
color: var(--color-yellow-700);
}
/* KeywordType */
.kt {
color: var(--color-yellow-700);
}
/* Name */
.n {
color: var(--color-violet-300);
}
/* NameAttribute */
.na {
color: var(--color-yellow-700);
}
/* NameBuiltin */
.nb {
color: var(--color-yellow-700);
}
/* NameBuiltinPseudo */
.bp {
color: var(--color-violet-300);
}
/* NameClass */
.nc {
color: var(--color-white-main);
}
/* NameConstant */
.no {
color: var(--color-white-main);
}
/* NameDecorator */
.nd {
color: var(--color-violet-300);
}
/* NameEntity */
.ni {
color: var(--color-yellow-700);
}
/* NameException */
.ne {
color: var(--color-red-700);
}
/* NameFunction */
.nf {
color: var(--color-blue-400);
}
/* NameFunctionMagic */
.fm {
color: var(--color-blue-400);
}
/* NameLabel */
.nl {
color: var(--color-yellow-500);
}
/* NameNamespace */
.nn {
color: var(--color-white-main);
}
/* NameOther */
.nx {
color: var(--color-white-main);
}
/* NameProperty */
.py {
color: var(--color-violet-300);
}
/* NameTag */
.nt {
color: var(--color-green-300);
}
/* NameVariable */
.nv {
color: var(--color-green-500);
}
/* NameVariableClass */
.vc {
color: var(--color-violet-600);
}
/* NameVariableGlobal */
.vg {
color: var(--color-violet-600);
}
/* NameVariableInstance */
.vi {
color: var(--color-violet-600);
}
/* NameVariableMagic */
.vm {
color: var(--color-violet-600);
}
/* Literal */
.l {
color: var(--color-white-main);
}
/* LiteralDate */
.ld {
color: var(--color-green-600);
}
/* LiteralString */
.s {
color: var(--color-white-main);
}
/* LiteralStringAffix */
.sa {
color: var(--color-green-600);
}
/* LiteralStringBacktick */
.sb {
color: var(--color-green-600);
}
/* LiteralStringChar */
.sc {
color: var(--color-green-600);
}
/* LiteralStringDelimiter */
.dl {
color: var(--color-green-600);
}
/* LiteralStringDoc */
.sd {
color: var(--color-green-600);
}
/* LiteralStringDouble */
.s2 {
color: var(--color-green-600);
}
/* LiteralStringEscape */
.se {
color: var(--color-white-main);
}
/* LiteralStringHeredoc */
.sh {
color: var(--color-green-600);
}
/* LiteralStringInterpol */
.si {
color: var(--color-green-600);
}
/* LiteralStringOther */
.sx {
color: var(--color-green-600);
}
/* LiteralStringRegex */
.sr {
color: var(--color-blue-400);
}
/* LiteralStringSingle */
.s1 {
color: var(--color-green-600);
}
/* LiteralStringSymbol */
.ss {
color: var(--color-blue-400);
}
/* LiteralNumber */
.m {
color: var(--color-blue-400);
}
/* LiteralNumberBin */
.mb {
color: var(--color-blue-400);
}
/* LiteralNumberFloat */
.mf {
color: var(--color-blue-400);
}
/* LiteralNumberHex */
.mh {
color: var(--color-blue-400);
}
/* LiteralNumberInteger */
.mi {
color: var(--color-blue-400);
}
/* LiteralNumberIntegerLong */
.il {
color: var(--color-blue-400);
}
/* LiteralNumberOct */
.mo {
color: var(--color-blue-400);
}
/* Operator */
.o {
color: var(--color-blue-200);
}
/* OperatorWord */
.ow {
color: var(--color-yellow-700);
}
/* Punctuation */
.p {
color: var(--color-gray-500);
}
/* Comment */
.c {
color: var(--color-gray-500);
}
/* CommentHashbang */
.ch {
color: var(--color-gray-500);
}
/* CommentMultiline */
.cm {
color: var(--color-gray-500);
}
/* CommentSingle */
.c1 {
color: var(--color-gray-500);
}
/* CommentSpecial */
.cs {
color: var(--color-gray-500);
}
/* CommentPreproc */
.cp {
color: var(--color-gray-500);
}
/* CommentPreprocFile */
.cpf {
color: var(--color-gray-500);
}
/* Generic */
.g {
color: var(--color-white-main);
}
/* GenericDeleted */
.gd {
color: var(--color-red-500);
}
/* GenericEmph */
.ge {
color: var(--color-white-main);
}
/* GenericError */
.gr {
color: var(--color-red-500);
}
/* GenericHeading */
.gh {
color: var(--color-gray-600);
}
/* GenericInserted */
.gi {
color: var(--color-green-500);
}
/* GenericOutput */
.go {
color: var(--color-white-main);
}
/* GenericPrompt */
.gp {
user-select: none;
color: var(--color-green-500);
}
/* GenericStrong */
.gs {
color: var(--color-white-main);
}
/* GenericSubheading */
.gu {
color: var(--color-gray-600);
}
/* GenericTraceback */
.gt {
color: var(--color-red-500);
}
/* GenericUnderline */
.gl {
color: var(--color-white-main);
text-decoration: underline;
}
/* TextWhitespace */
.w {
color: var(--color-gray-100);
}
}

View File

@ -1,343 +1,342 @@
@layer utilities {
.syntax-light {
/* Other */
.x {
color: theme("colors.black");
}
/* Error */
.err {
color: theme("colors.red.light.500");
}
/* CodeLine */
.cl {
}
/* LineHighlight */
.hl {
min-width: fit-content;
background-color: theme("colors.blue.light.100");
}
.lntd:first-child .hl,
& > .chroma > code > .hl {
margin-left: -4px;
border-left: 4px solid theme("colors.blue.light.300");
}
/* LineNumbersTable */
.lnt {
white-space: pre;
user-select: none;
margin-right: 0.4em;
padding: 0 0.4em 0 0.4em;
color: theme("colors.gray.light.400");
}
/* LineNumbers */
.ln {
white-space: pre;
user-select: none;
margin-right: 0.4em;
padding: 0 0.4em 0 0.4em;
color: theme("colors.gray.light.400");
}
/* Line */
.line {
display: flex;
}
/* Keyword */
.k {
color: theme("colors.amber.light.500");
}
/* KeywordConstant */
.kc {
color: theme("colors.violet.light.400");
}
/* KeywordDeclaration */
.kd {
color: theme("colors.amber.light.500");
}
/* KeywordNamespace */
.kn {
color: theme("colors.amber.light.500");
}
/* KeywordPseudo */
.kp {
color: theme("colors.amber.light.500");
}
/* KeywordReserved */
.kr {
color: theme("colors.amber.light.500");
}
/* KeywordType */
.kt {
color: theme("colors.amber.light.500");
}
/* Name */
.n {
color: theme("colors.violet.light.400");
}
/* NameAttribute */
.na {
color: theme("colors.amber.light.500");
}
/* NameBuiltin */
.nb {
color: theme("colors.amber.light.500");
}
/* NameBuiltinPseudo */
.bp {
color: theme("colors.violet.light.400");
}
/* NameClass */
.nc {
color: theme("colors.black");
}
/* NameConstant */
.no {
color: theme("colors.black");
}
/* NameDecorator */
.nd {
color: theme("colors.violet.light.400");
}
/* NameEntity */
.ni {
color: theme("colors.amber.light.500");
}
/* NameException */
.ne {
color: theme("colors.red.light.700");
}
/* NameFunction */
.nf {
color: theme("colors.blue.light.600");
}
/* NameFunctionMagic */
.fm {
color: theme("colors.blue.light.600");
}
/* NameLabel */
.nl {
color: theme("colors.amber.light.700");
}
/* NameNamespace */
.nn {
color: theme("colors.black");
}
/* NameOther */
.nx {
color: theme("colors.black");
}
/* NameProperty */
.py {
color: theme("colors.black");
}
/* NameTag */
.nt {
color: theme("colors.green.light.600");
}
/* NameVariable */
.nv {
color: theme("colors.black");
}
/* NameVariableClass */
.vc {
color: theme("colors.violet.light.600");
}
/* NameVariableGlobal */
.vg {
color: theme("colors.violet.light.600");
}
/* NameVariableInstance */
.vi {
color: theme("colors.violet.light.600");
}
/* NameVariableMagic */
.vm {
color: theme("colors.violet.light.600");
}
/* Literal */
.l {
color: theme("colors.black");
}
/* LiteralDate */
.ld {
color: theme("colors.black");
}
/* LiteralString */
.s {
color: theme("colors.black");
}
/* LiteralStringAffix */
.sa {
color: theme("colors.green.light.600");
}
/* LiteralStringBacktick */
.sb {
color: theme("colors.green.light.600");
}
/* LiteralStringChar */
.sc {
color: theme("colors.green.light.600");
}
/* LiteralStringDelimiter */
.dl {
color: theme("colors.green.light.600");
}
/* LiteralStringDoc */
.sd {
color: #8f5902;
}
/* LiteralStringDouble */
.s2 {
color: theme("colors.green.light.600");
}
/* LiteralStringEscape */
.se {
color: theme("colors.black");
}
/* LiteralStringHeredoc */
.sh {
color: theme("colors.green.light.600");
}
/* LiteralStringInterpol */
.si {
color: theme("colors.green.light.600");
}
/* LiteralStringOther */
.sx {
color: theme("colors.green.light.600");
}
/* LiteralStringRegex */
.sr {
color: theme("colors.blue.light.500");
}
/* LiteralStringSingle */
.s1 {
color: theme("colors.green.light.600");
}
/* LiteralStringSymbol */
.ss {
color: theme("colors.green.light.600");
}
/* LiteralNumber */
.m {
color: theme("colors.blue.light.600");
}
/* LiteralNumberBin */
.mb {
color: theme("colors.blue.light.600");
}
/* LiteralNumberFloat */
.mf {
color: theme("colors.blue.light.600");
}
/* LiteralNumberHex */
.mh {
color: theme("colors.blue.light.600");
}
/* LiteralNumberInteger */
.mi {
color: theme("colors.blue.light.600");
}
/* LiteralNumberIntegerLong */
.il {
color: theme("colors.blue.light.600");
}
/* LiteralNumberOct */
.mo {
color: theme("colors.blue.light.600");
}
/* Operator */
.o {
color: theme("colors.blue.light.400");
}
/* OperatorWord */
.ow {
color: theme("colors.amber.light.500");
}
/* Punctuation */
.p {
color: theme("colors.gray.light.400");
}
/* Comment */
.c {
color: theme("colors.gray.light.400");
}
/* CommentHashbang */
.ch {
color: theme("colors.gray.light.400");
}
/* CommentMultiline */
.cm {
color: theme("colors.gray.light.400");
}
/* CommentSingle */
.c1 {
color: theme("colors.gray.light.400");
}
/* CommentSpecial */
.cs {
color: theme("colors.gray.light.400");
}
/* CommentPreproc */
.cp {
color: theme("colors.gray.light.400");
}
/* CommentPreprocFile */
.cpf {
color: theme("colors.gray.light.400");
}
/* Generic */
.g {
color: theme("colors.black");
}
/* GenericDeleted */
.gd {
color: theme("colors.red.light.500");
}
/* GenericEmph */
.ge {
color: theme("colors.black");
}
/* GenericError */
.gr {
color: theme("colors.red.light.500");
}
/* GenericHeading */
.gh {
color: theme("colors.gray.light.600");
}
/* GenericInserted */
.gi {
color: theme("colors.green.light.500");
}
/* GenericOutput */
.go {
color: theme("colors.black");
}
/* GenericPrompt */
.gp {
user-select: none;
color: theme("colors.green.light.400");
}
/* GenericStrong */
.gs {
color: theme("colors.black");
}
/* GenericSubheading */
.gu {
color: theme("colors.gray.light.600");
}
/* GenericTraceback */
.gt {
color: theme("colors.red.light.500");
}
/* GenericUnderline */
.gl {
color: theme("colors.black");
text-decoration: underline;
}
/* TextWhitespace */
.w {
color: theme("colors.gray.light.100");
}
@utility syntax-light {
/* Other */
.x {
color: var(--color-black-main);
}
/* Error */
.err {
color: var(--color-red-500);
}
/* CodeLine */
.cl {
color: var(--color-gray-700);
}
/* LineHighlight */
.hl {
min-width: fit-content;
background-color: var(--color-blue-100);
}
.lntd:first-child .hl,
& > .chroma > code > .hl {
margin-left: -4px;
border-left: 4px solid var(--color-blue-300);
}
/* LineNumbersTable */
.lnt {
white-space: pre;
user-select: none;
margin-right: 0.4em;
padding: 0 0.4em 0 0.4em;
color: var(--color-gray-400);
}
/* LineNumbers */
.ln {
white-space: pre;
user-select: none;
margin-right: 0.4em;
padding: 0 0.4em 0 0.4em;
color: var(--color-gray-400);
}
/* Line */
.line {
display: flex;
}
/* Keyword */
.k {
color: var(--color-yellow-700);
}
/* KeywordConstant */
.kc {
color: var(--color-violet-400);
}
/* KeywordDeclaration */
.kd {
color: var(--color-yellow-700);
}
/* KeywordNamespace */
.kn {
color: var(--color-yellow-700);
}
/* KeywordPseudo */
.kp {
color: var(--color-yellow-700);
}
/* KeywordReserved */
.kr {
color: var(--color-yellow-700);
}
/* KeywordType */
.kt {
color: var(--color-yellow-700);
}
/* Name */
.n {
color: var(--color-violet-400);
}
/* NameAttribute */
.na {
color: var(--color-yellow-700);
}
/* NameBuiltin */
.nb {
color: var(--color-yellow-800);
}
/* NameBuiltinPseudo */
.bp {
color: var(--color-violet-400);
}
/* NameClass */
.nc {
color: var(--color-black-main);
}
/* NameConstant */
.no {
color: var(--color-black-main);
}
/* NameDecorator */
.nd {
color: var(--color-violet-400);
}
/* NameEntity */
.ni {
color: var(--color-yellow-700);
}
/* NameException */
.ne {
color: var(--color-red-700);
}
/* NameFunction */
.nf {
color: var(--color-blue-500);
}
/* NameFunctionMagic */
.fm {
color: var(--color-blue-500);
}
/* NameLabel */
.nl {
color: var(--color-yellow-700);
}
/* NameNamespace */
.nn {
color: var(--color-black-main);
}
/* NameOther */
.nx {
color: var(--color-black-main);
}
/* NameProperty */
.py {
color: var(--color-black-main);
}
/* NameTag */
.nt {
color: var(--color-blue-400);
}
/* NameVariable */
.nv {
color: var(--color-black-main);
}
/* NameVariableClass */
.vc {
color: var(--color-violet-600);
}
/* NameVariableGlobal */
.vg {
color: var(--color-violet-600);
}
/* NameVariableInstance */
.vi {
color: var(--color-violet-600);
}
/* NameVariableMagic */
.vm {
color: var(--color-violet-600);
}
/* Literal */
.l {
color: var(--color-black-main);
}
/* LiteralDate */
.ld {
color: var(--color-black-main);
}
/* LiteralString */
.s {
color: var(--color-black-main);
}
/* LiteralStringAffix */
.sa {
color: var(--color-green-700);
}
/* LiteralStringBacktick */
.sb {
color: var(--color-green-700);
}
/* LiteralStringChar */
.sc {
color: var(--color-green-700);
}
/* LiteralStringDelimiter */
.dl {
color: var(--color-green-700);
}
/* LiteralStringDoc */
.sd {
color: #8f5902;
}
/* LiteralStringDouble */
.s2 {
color: var(--color-green-700);
}
/* LiteralStringEscape */
.se {
color: var(--color-black-main);
}
/* LiteralStringHeredoc */
.sh {
color: var(--color-green-700);
}
/* LiteralStringInterpol */
.si {
color: var(--color-green-700);
}
/* LiteralStringOther */
.sx {
color: var(--color-green-700);
}
/* LiteralStringRegex */
.sr {
color: var(--color-blue-500);
}
/* LiteralStringSingle */
.s1 {
color: var(--color-green-700);
}
/* LiteralStringSymbol */
.ss {
color: var(--color-green-700);
}
/* LiteralNumber */
.m {
color: var(--color-blue-500);
}
/* LiteralNumberBin */
.mb {
color: var(--color-blue-500);
}
/* LiteralNumberFloat */
.mf {
color: var(--color-blue-500);
}
/* LiteralNumberHex */
.mh {
color: var(--color-blue-500);
}
/* LiteralNumberInteger */
.mi {
color: var(--color-blue-500);
}
/* LiteralNumberIntegerLong */
.il {
color: var(--color-blue-500);
}
/* LiteralNumberOct */
.mo {
color: var(--color-blue-500);
}
/* Operator */
.o {
color: var(--color-blue-400);
}
/* OperatorWord */
.ow {
color: var(--color-yellow-700);
}
/* Punctuation */
.p {
color: var(--color-gray-400);
}
/* Comment */
.c {
color: var(--color-gray-400);
}
/* CommentHashbang */
.ch {
color: var(--color-gray-400);
}
/* CommentMultiline */
.cm {
color: var(--color-gray-400);
}
/* CommentSingle */
.c1 {
color: var(--color-gray-400);
}
/* CommentSpecial */
.cs {
color: var(--color-gray-400);
}
/* CommentPreproc */
.cp {
color: var(--color-gray-400);
}
/* CommentPreprocFile */
.cpf {
color: var(--color-gray-400);
}
/* Generic */
.g {
color: var(--color-black-main);
}
/* GenericDeleted */
.gd {
color: var(--color-red-500);
}
/* GenericEmph */
.ge {
color: var(--color-black-main);
}
/* GenericError */
.gr {
color: var(--color-red-500);
}
/* GenericHeading */
.gh {
color: var(--color-gray-600);
}
/* GenericInserted */
.gi {
color: var(--color-green-500);
}
/* GenericOutput */
.go {
color: var(--color-black-main);
}
/* GenericPrompt */
.gp {
user-select: none;
color: var(--color-green-400);
}
/* GenericStrong */
.gs {
color: var(--color-black-main);
}
/* GenericSubheading */
.gu {
color: var(--color-gray-600);
}
/* GenericTraceback */
.gt {
color: var(--color-red-500);
}
/* GenericUnderline */
.gl {
color: var(--color-black-main);
text-decoration: underline;
}
/* TextWhitespace */
.w {
color: var(--color-gray-100);
}
}

203
assets/css/theme.css Normal file
View File

@ -0,0 +1,203 @@
@theme inline {
--font-sans: "roboto flex", sans-serif;
--font-mono: "roboto flex mono", ui-monospace, SFMono-Regular, monospace;
--default-font-family: var(--font-sans);
--text-xs: 0.7143rem;
--text-xs--letter-spacing: 0.015em;
--text-xs--font-weight: 500;
--text-sm: 0.851rem;
--text-base: 14px;
--text-lg: 1.1429rem;
--text-lg--line-height: 1.75;
--text-xl: 1.2857rem;
--text-xl--letter-spacing: -0.015em;
--text-xl--font-weight: 500;
--text-2xl: 1.5rem;
--text-2xl--letter-spacing: -0.015em;
--text-2xl--font-weight: 500;
--text-3xl: 2rem;
--text-3xl--font-weight: 500;
--text-4xl: 2.5rem;
--text-4xl--letter-spacing: -0.015em;
--text-4xl--font-weight: 500;
--color-background-light: #f9f9fa;
--color-background-dark: #10151b;
--color-primary-blue: var(--color-blue);
--color-divider-light: hsla(0, 0%, 0%, 0.1);
--color-divider-dark: hsla(0, 0%, 100%, 0.05);
--card-bg-dark: #1d262d;
--card-border-dark: #516980;
--card-bg-dark: var(--color-gray-900);
--card-border-dark: var(--color-gray-700);
--color-navbar-bg: var(--color-background-light);
--color-navbar-bg-dark: var(--color-background-dark);
--color-navbar-text: var(--color-gray-700);
--color-navbar-text-dark: var(--tw-prose-body);
--color-navbar-border-color-light: var(--tw-prose-inverse-body);
--navbar-font-size: 1rem;
--navbar-group-font-title-size: 1rem;
--color-navbar-text-dark: var(--color-gray-200);
--color-navbar-group-text-dark: var(--tw-prose-body);
--color-blue: var(--color-blue-400);
--color-blue-100: rgba(217, 229, 252, 1);
--color-blue-200: rgba(170, 196, 248, 1);
--color-blue-300: rgba(123, 164, 244, 1);
--color-blue-400: rgba(75, 131, 241, 1);
--color-blue-50: rgba(246, 248, 254, 1);
--color-blue-500: rgba(37, 96, 255, 1);
--color-blue-600: rgba(13, 77, 242, 1);
--color-blue-700: rgba(0, 61, 181, 1);
--color-blue-800: rgba(0, 41, 120, 1);
--color-blue-900: rgba(0, 29, 86, 1);
--color-blue-950: rgba(0, 21, 60, 1);
--color-blue-focus: rgba(37, 96, 255, 0.24);
--color-blue-focusvisible: rgba(37, 96, 255, 0.32);
--color-blue-hover: rgba(37, 96, 255, 0.12);
--color-blue-outlinedborder: rgba(37, 96, 255, 0.56);
--color-blue-selected: rgba(37, 96, 255, 0.16);
--color-gray: var(--color-gray-600);
--color-gray-100: rgba(231, 234, 239, 1);
--color-gray-200: rgba(200, 207, 218, 1);
--color-gray-300: rgba(169, 180, 198, 1);
--color-gray-400: rgba(139, 153, 178, 1);
--color-gray-50: rgba(249, 250, 251, 1);
--color-gray-500: rgba(108, 126, 157, 1);
--color-gray-600: rgba(86, 101, 129, 1);
--color-gray-700: rgba(67, 76, 95, 1);
--color-gray-800: rgba(44, 51, 63, 1);
--color-gray-900: rgba(30, 33, 41, 1);
--color-gray-950: rgb(18, 21, 31);
--color-gray-focus: rgba(108, 126, 157, 0.24);
--color-gray-focusvisible: rgba(108, 126, 157, 0.32);
--color-gray-hover: rgba(108, 126, 157, 0.12);
--color-gray-outlinedborder: rgba(108, 126, 157, 0.56);
--color-gray-selected: rgba(108, 126, 157, 0.16);
--color-green-100: rgba(235, 249, 238, 1);
--color-green-200: rgba(208, 241, 215, 1);
--color-green-300: rgba(169, 229, 189, 1);
--color-green-400: rgba(129, 217, 162, 1);
--color-green-50: rgba(245, 252, 247, 1);
--color-green-500: rgba(90, 206, 140, 1);
--color-green-600: rgba(56, 189, 125, 1);
--color-green-700: rgba(45, 149, 104, 1);
--color-green-800: rgba(33, 110, 75, 1);
--color-green-900: rgba(23, 75, 50, 1);
--color-green-950: rgba(17, 55, 26, 1);
--color-green-focus: rgba(56, 189, 125, 0.24);
--color-green-focusvisible: rgba(56, 189, 125, 0.32);
--color-green-hover: rgba(56, 189, 125, 0.12);
--color-green-outlinedborder: rgba(56, 189, 125, 0.56);
--color-green-selected: rgba(56, 189, 125, 0.16);
--color-orange-100: rgba(255, 233, 217, 1);
--color-orange-200: rgba(255, 216, 187, 1);
--color-orange-300: rgba(255, 196, 153, 1);
--color-orange-400: rgba(255, 169, 107, 1);
--color-orange-50: rgba(255, 249, 245, 1);
--color-orange-500: rgba(255, 135, 49, 1);
--color-orange-600: rgba(255, 107, 0, 1);
--color-orange-700: rgba(218, 92, 0, 1);
--color-orange-800: rgba(173, 72, 0, 1);
--color-orange-900: rgba(137, 58, 1, 1);
--color-orange-950: rgba(94, 40, 0, 1);
--color-orange-focus: rgba(255, 107, 0, 0.24);
--color-orange-focusvisible: rgba(255, 107, 0, 0.32);
--color-orange-hover: rgba(255, 107, 0, 0.12);
--color-orange-outlinedborder: rgba(255, 107, 0, 0.56);
--color-orange-selected: rgba(255, 107, 0, 0.16);
--color-pink-100: rgba(255, 230, 251, 1);
--color-pink-200: rgba(255, 201, 246, 1);
--color-pink-300: rgba(255, 166, 240, 1);
--color-pink-400: rgba(252, 113, 220, 1);
--color-pink-50: rgba(255, 247, 254, 1);
--color-pink-500: rgba(237, 73, 199, 1);
--color-pink-600: rgba(201, 24, 171, 1);
--color-pink-700: rgba(171, 0, 137, 1);
--color-pink-800: rgba(131, 0, 105, 1);
--color-pink-900: rgba(109, 0, 81, 1);
--color-pink-950: rgba(85, 0, 51, 1);
--color-pink-focus: rgba(201, 24, 171, 0.24);
--color-pink-focusvisible: rgba(201, 24, 171, 0.32);
--color-pink-hover: rgba(201, 24, 171, 0.12);
--color-pink-outlinedborder: rgba(201, 24, 171, 0.56);
--color-pink-selected: rgba(201, 24, 171, 0.16);
--color-red-100: rgba(255, 223, 223, 1);
--color-red-200: rgba(255, 194, 194, 1);
--color-red-300: rgba(255, 168, 168, 1);
--color-red-400: rgba(255, 117, 117, 1);
--color-red-50: rgba(255, 245, 245, 1);
--color-red-500: rgba(255, 87, 87, 1);
--color-red-600: rgba(244, 47, 57, 1);
--color-red-700: rgba(228, 12, 44, 1);
--color-red-800: rgba(179, 9, 9, 1);
--color-red-900: rgba(137, 0, 0, 1);
--color-red-950: rgba(110, 0, 0, 1);
--color-red-focus: rgba(244, 47, 57, 0.24);
--color-red-focusvisible: rgba(244, 47, 57, 0.32);
--color-red-hover: rgba(244, 47, 57, 0.12);
--color-red-outlinedborder: rgba(244, 47, 57, 0.56);
--color-red-selected: rgba(244, 47, 57, 0.16);
--color-teal-100: rgba(223, 246, 246, 1);
--color-teal-200: rgba(195, 240, 241, 1);
--color-teal-300: rgba(160, 229, 232, 1);
--color-teal-400: rgba(106, 220, 222, 1);
--color-teal-50: rgba(243, 252, 252, 1);
--color-teal-500: rgba(47, 208, 210, 1);
--color-teal-600: rgba(27, 189, 191, 1);
--color-teal-700: rgba(44, 158, 160, 1);
--color-teal-800: rgba(24, 116, 115, 1);
--color-teal-900: rgba(18, 85, 85, 1);
--color-teal-950: rgba(9, 61, 61, 1);
--color-teal-focus: rgba(27, 189, 191, 0.24);
--color-teal-focusvisible: rgba(27, 189, 191, 0.32);
--color-teal-hover: rgba(27, 189, 191, 0.12);
--color-teal-outlinedborder: rgba(27, 189, 191, 0.56);
--color-teal-selected: rgba(27, 189, 191, 0.16);
--color-violet: var(--color-violet-500);
--color-violet-100: rgba(239, 224, 255, 1);
--color-violet-200: rgba(211, 183, 255, 1);
--color-violet-300: rgba(174, 130, 255, 1);
--color-violet-400: rgba(152, 96, 255, 1);
--color-violet-50: rgba(252, 249, 255, 1);
--color-violet-500: rgba(125, 46, 255, 1);
--color-violet-600: rgba(109, 0, 235, 1);
--color-violet-700: rgba(87, 0, 187, 1);
--color-violet-800: rgba(69, 0, 147, 1);
--color-violet-900: rgba(55, 0, 118, 1);
--color-violet-950: rgba(37, 0, 80, 1);
--color-violet-focus: rgba(125, 46, 255, 0.24);
--color-violet-focusvisible: rgba(125, 46, 255, 0.32);
--color-violet-hover: rgba(125, 46, 255, 0.12);
--color-violet-outlinedborder: rgba(125, 46, 255, 0.56);
--color-violet-selected: rgba(125, 46, 255, 0.16);
--color-white-main: rgba(255, 255, 255, 1);
--color-yellow-100: rgba(255, 245, 219, 1);
--color-yellow-200: rgba(255, 241, 204, 1);
--color-yellow-300: rgba(255, 232, 173, 1);
--color-yellow-400: rgba(255, 218, 122, 1);
--color-yellow-50: rgba(255, 251, 240, 1);
--color-yellow-500: rgba(255, 204, 72, 1);
--color-yellow-600: rgba(248, 182, 15, 1);
--color-yellow-700: rgba(235, 156, 0, 1);
--color-yellow-800: rgba(184, 110, 0, 1);
--color-yellow-900: rgba(133, 73, 0, 1);
--color-yellow-950: rgba(100, 55, 0, 1);
--color-yellow-focus: rgba(235, 156, 0, 0.24);
--color-yellow-focusvisible: rgba(235, 156, 0, 0.32);
--color-yellow-hover: rgba(235, 156, 0, 0.12);
--color-yellow-outlinedborder: rgba(235, 156, 0, 0.56);
--color-yellow-selected: rgba(235, 156, 0, 0.16);
}

View File

@ -1,14 +0,0 @@
@layer components {
#TableOfContents {
.toc a {
@apply block max-w-full truncate py-1 pl-2 hover:font-medium hover:no-underline;
&[aria-current="true"],
&:hover {
@apply border-l-2 border-l-gray-light bg-gradient-to-r from-gray-light-100 font-medium text-black dark:border-l-gray-dark dark:from-gray-dark-200 dark:text-white;
}
&:not([aria-current="true"]) {
@apply text-gray-light-600 hover:text-black dark:text-gray-dark-700 dark:hover:text-white;
}
}
}
}

View File

@ -1,77 +0,0 @@
@layer base {
/*
* Font faces for Roboto Flex and Roboto Mono.
*
* - https://fonts.google.com/specimen/Roboto+Flex
* - https://fonts.google.com/specimen/Roboto+Mono
*
* The TTF fonts have been compressed to woff2,
* preserving the latin character subset.
*
* */
/* Roboto Flex */
@font-face {
font-family: 'Roboto Flex';
src: url('/assets/fonts/RobotoFlex.woff2') format('woff2');
font-weight: 100 1000; /* Range of weights Roboto Flex supports */
font-stretch: 100%; /* Range of width Roboto Flex supports */
font-style: oblique 0deg 10deg; /* Range of oblique angle Roboto Flex supports */
font-display: fallback;
}
/* Roboto Mono */
@font-face {
font-family: 'Roboto Mono';
src: url('/assets/fonts/RobotoMono-Regular.woff2') format('woff2');
font-weight: 100 700; /* Define the range of weight the variable font supports */
font-style: normal;
font-display: fallback;
}
/* Roboto Mono Italic */
@font-face {
font-family: 'Roboto Mono';
src: url('/assets/fonts/RobotoMono-Italic.woff2') format('woff2');
font-weight: 100 700; /* Define the range of weight the variable font supports */
font-style: italic;
font-display: fallback;
}
.prose {
li {
@apply my-2;
> :last-child,
> :first-child {
margin: 0;
}
}
a {
font-weight: 400;
}
hr {
@apply mb-4 mt-8;
}
h1 {
@apply my-4 text-4xl;
line-height: 1.167;
}
h2 {
@apply mb-4 mt-8 text-3xl;
line-height: 1.2;
}
h3 {
@apply text-2xl;
line-height: 1.167;
}
h4 {
@apply text-xl;
line-height: 1.235;
}
h5 {
@apply text-lg;
line-height: 1.75;
}
}
}

242
assets/css/utilities.css Normal file
View File

@ -0,0 +1,242 @@
@utility icon-svg {
svg {
font-size: 24px;
width: 1em;
height: 1em;
display: inline-block;
fill: currentColor;
}
}
@utility icon-xs {
svg {
font-size: 12px;
}
}
@utility icon-sm {
svg {
font-size: 16px;
}
}
@utility icon-lg {
svg {
font-size: 32px;
}
}
@utility text-primary-blue {
color: var(--color-primary-blue);
}
@utility link {
@apply text-blue no-underline dark:text-blue-400;
font-weight: inherit;
&:hover {
@apply underline underline-offset-3;
}
}
@utility invertible {
@apply dark:hue-rotate-180 dark:invert dark:filter;
}
@utility bg-pattern-blue {
background-color: rgba(255, 255, 255, 0.5);
background-image: url("/assets/images/bg-pattern-blue.webp");
background-blend-mode: overlay;
background-size: cover;
background-repeat: no-repeat;
.dark & {
background-color: rgba(0, 0, 0, 0.741);
}
}
@utility bg-pattern-purple {
background-color: rgba(255, 255, 255, 0.5);
background-image: url("/assets/images/bg-pattern-purple.webp");
background-blend-mode: overlay;
background-size: cover;
background-repeat: no-repeat;
.dark & {
background-color: rgba(0, 0, 0, 0.741);
}
}
@utility bg-background-toc {
background-color: var(--color-navbar-bg);
.dark & {
background-color: var(--color-navbar-bg-dark);
}
}
@utility bg-pattern-verde {
background-color: rgba(255, 255, 255, 0.5);
background-image: url("/assets/images/bg-pattern-verde.webp");
background-blend-mode: overlay;
background-size: cover;
background-repeat: no-repeat;
.dark & {
background-color: rgba(0, 0, 0, 0.741);
}
}
@utility icon-svg {
svg {
font-size: 24px;
width: 1em;
height: 1em;
display: inline-block;
fill: currentColor;
}
}
@utility icon-xs {
svg {
font-size: 12px;
}
}
@utility icon-sm {
svg {
font-size: 16px;
}
}
@utility icon-lg {
svg {
font-size: 32px;
}
}
@utility navbar-font {
font-size: var(--navbar-font-size);
color: var(--color-navbar-text);
.dark & {
color: var(--color-navbar-text-dark);
}
}
@utility navbar-group-font-title {
font-size: var(--color-navbar-group-font-title-size);
@apply font-semibold uppercase;
color: var(--color-navbar-text);
.dark & {
color: var(--color-navbar-text-dark);
}
}
@utility prose {
.highlight,
:not(pre) > code {
font-size: 0.875em;
border: 1px solid;
border-radius: 0.25rem; /* theme("spacing.1") fallback */
background: var(--color-white-main);
border-color: var(--color-gray-300);
.dark & {
background: var(--color-gray-200);
border-color: var(--color-gray-400);
}
&::before,
&::after {
content: none !important;
}
}
:not(pre) > code {
background: var(--color-gray-200);
display: inline-block;
margin: 0;
font-weight: 400;
overflow-wrap: anywhere;
padding: 0 4px;
}
table:not(.lntable) code {
overflow-wrap: unset;
white-space: nowrap;
}
/* Indented code blocks */
pre:not(.chroma) {
@apply my-4 overflow-x-auto p-3;
font-size: 0.875em;
border: 1px solid;
border-radius: 0.25rem; /* theme("spacing.1") fallback */
background: var(--color-white-main);
border-color: var(--color-gray-300);
.dark & {
background: var(--color-gray-200);
border-color: var(--color-gray-400);
}
}
.highlight {
@apply my-4 overflow-x-auto p-3;
/* LineTableTD */
.lntd {
vertical-align: top;
padding: 0;
margin: 0;
font-weight: 400;
padding: 0 4px;
&:first-child {
width: 0;
}
}
/* LineTableTD */
.lntd {
vertical-align: top;
padding: 0;
margin: 0;
border: 0;
}
/* LineTable */
.lntable {
display: table;
width: 100%;
border-spacing: 0;
padding: 0;
margin: 0;
border: 0;
/* LineNumberColumnHighlight */
.lntd:first-child .hl {
display: block;
}
}
}
}
@utility section-card {
@apply flex h-full flex-col gap-2 rounded-sm border p-4 drop-shadow-xs hover:drop-shadow-lg;
@apply text-gray dark:text-gray-200;
@apply border-gray-100 bg-gray-50 hover:border-gray-200 dark:border-gray-600 dark:bg-gray-900 hover:dark:border-gray-500;
}
@utility section-card-text {
@apply leading-snug text-gray-800 dark:text-gray-200;
}
@utility section-card-title {
@apply text-xl font-semibold text-gray-900 dark:text-gray-100;
}
@utility sub-button {
@apply flex w-full items-start gap-2 rounded-sm px-2 py-2 text-left text-gray-700 transition-colors hover:bg-gray-50 dark:text-gray-100 dark:hover:bg-gray-800;
}
@utility toc {
a {
@apply block max-w-full truncate py-1 pl-2 hover:font-medium hover:no-underline;
&[aria-current="true"],
&:hover {
@apply border-l-2 border-x-gray-200 bg-gradient-to-r from-gray-50 font-medium text-black dark:border-l-gray-300 dark:from-gray-900 dark:text-white;
}
&:not([aria-current="true"]) {
@apply text-gray-600 hover:text-black dark:text-gray-100 dark:hover:text-white;
}
}
}

View File

@ -0,0 +1,8 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="blue" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0_26_122" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
<path d="M17.9549 21.7542C16.8041 22.871 15.5344 22.6969 14.3241 22.1703C13.0373 21.6331 11.861 21.5991 10.5021 22.1703C8.80981 22.9007 7.91165 22.6884 6.89246 21.7542C1.13826 15.8301 1.98759 6.80604 8.52741 6.46631C10.1135 6.55125 11.224 7.34324 12.1583 7.40906C13.5469 7.12666 14.8761 6.31768 16.3625 6.42385C18.1482 6.56823 19.4837 7.27317 20.3755 8.54079C16.7022 10.749 17.5728 15.5902 20.9467 16.9491C20.2715 18.7221 19.4052 20.4738 17.9528 21.769L17.9549 21.7542ZM12.0309 6.40261C11.8589 3.76971 13.9928 1.60393 16.4474 1.3916C16.785 4.42794 13.6871 6.69988 12.0309 6.40261Z" fill="currentColor"/>
</mask>
<g mask="url(#mask0_26_122)">
<rect width="24" height="24" fill="currentColor" fill-opacity="0.9"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 931 B

View File

Before

Width:  |  Height:  |  Size: 613 B

After

Width:  |  Height:  |  Size: 613 B

8
assets/icons/Linux.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 732 B

After

Width:  |  Height:  |  Size: 732 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

8
assets/icons/Windows.svg Normal file
View File

@ -0,0 +1,8 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0_26_117" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
<path d="M2.8584 11.5731H10.2447V4.31147L2.8584 5.34754V11.5731ZM2.8584 18.6499L10.2447 19.682V12.503H2.8584V18.6499ZM11.0617 4.19737V11.5731H20.89V2.82031L11.0591 4.19737H11.0617ZM11.0617 19.7961L20.89 21.1732V12.5043H11.0591V19.7961H11.0617Z" fill="currentColor"/>
</mask>
<g mask="url(#mask0_26_117)">
<rect width="24" height="24" fill="currentColor" fill-opacity="0.9"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 594 B

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

7
assets/icons/toolbox.svg Normal file
View File

@ -0,0 +1,7 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.1604 16.8125C14.3454 16.4613 14.8724 16.4613 15.0575 16.8125C15.1827 17.0508 15.2459 17.1704 15.3296 17.2737C15.4038 17.3652 15.49 17.4472 15.5863 17.5178C15.6948 17.5974 15.8201 17.6576 16.0707 17.7768C16.4403 17.9527 16.4403 18.454 16.0707 18.6299C15.8201 18.7491 15.6948 18.8093 15.5863 18.8889C15.49 18.9595 15.4038 19.0415 15.3296 19.133C15.2459 19.2363 15.1827 19.3551 15.0575 19.5933C14.8725 19.9451 14.3453 19.9451 14.1604 19.5933C14.0351 19.3551 13.9719 19.2363 13.8882 19.133C13.814 19.0415 13.7278 18.9595 13.6315 18.8889C13.523 18.8093 13.3977 18.7491 13.1471 18.6299C12.7774 18.454 12.7775 17.9527 13.1471 17.7768C13.3977 17.6576 13.523 17.5974 13.6315 17.5178C13.7278 17.4472 13.814 17.3652 13.8882 17.2737C13.9719 17.1704 14.0351 17.0508 14.1604 16.8125Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.93855 11.9528C6.18684 11.7089 6.58915 11.7089 6.83747 11.9528L9.10245 14.1805C9.34736 14.4214 9.34724 14.8242 9.10245 15.0652L5.7662 18.3473L5.60021 18.496C4.7982 19.1516 3.64836 19.2319 2.82725 18.5792L2.65672 18.4278C1.83844 17.6224 1.78233 16.2321 2.50252 15.3495L2.65672 15.1807L5.93855 11.9528ZM3.85044 16.3094C3.61193 16.544 3.61271 17.0649 3.85044 17.299L3.9221 17.3568C3.99403 17.404 4.06853 17.4204 4.14887 17.4172C4.27136 17.4121 4.4317 17.3561 4.57248 17.2177L7.21028 14.6224L6.38755 13.8139L3.85044 16.3094Z" fill="currentColor"/>
<path d="M18.508 14.7449C18.693 14.3936 19.22 14.3936 19.4051 14.7449C19.5304 14.9832 19.5936 15.1028 19.6772 15.206C19.7514 15.2976 19.8377 15.3796 19.9339 15.4502C20.0425 15.5297 20.168 15.5892 20.4183 15.7083C20.7882 15.8842 20.7882 16.3864 20.4183 16.5623C20.1679 16.6814 20.0425 16.7409 19.9339 16.8204C19.8376 16.891 19.7515 16.9738 19.6772 17.0654C19.5936 17.1686 19.5303 17.2875 19.4051 17.5257C19.2202 17.8774 18.6929 17.8774 18.508 17.5257C18.3828 17.2874 18.3195 17.1686 18.2359 17.0654C18.1616 16.9738 18.0755 16.891 17.9792 16.8204C17.8707 16.7409 17.7451 16.6813 17.4948 16.5623C17.1251 16.3863 17.125 15.8841 17.4948 15.7083C17.7453 15.5891 17.8706 15.5297 17.9792 15.4502C18.0754 15.3796 18.1617 15.2976 18.2359 15.206C18.3196 15.1028 18.3827 14.9832 18.508 14.7449Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.53683 4.30615C8.19308 4.17877 8.90012 4.10059 9.56507 4.16702C10.2334 4.23384 10.9066 4.45295 11.4264 4.96415L14.4461 7.93477C14.7509 8.23479 14.5896 8.6711 14.5241 9.03377C14.9209 9.07759 15.5454 9.01593 15.853 9.31815L17.4658 10.9045C17.6126 11.049 17.6788 11.2555 17.6426 11.4567L17.4249 12.6607L17.4005 12.7534C17.3693 12.8432 17.3177 12.9254 17.249 12.9932L15.3269 14.884L15.2534 14.9462C15.1753 15.0024 15.0847 15.0405 14.9885 15.0573L13.7649 15.2708L13.6878 15.2795C13.5343 15.2877 13.3826 15.2414 13.2614 15.1483L13.2034 15.0975L11.5897 13.5103C11.4029 13.3261 11.4006 13.0743 11.3729 12.8322L10.9012 13.2959C10.6528 13.5399 10.2506 13.54 10.0023 13.2959L7.73729 11.0682C7.43105 10.7667 7.54835 10.3692 7.81893 10.103L7.97041 8.8754L6.9055 8.72577C6.80325 8.71138 6.70638 8.67262 6.6234 8.61377L6.54539 8.54902L4.14343 6.18565C3.79161 5.83906 3.97995 5.22677 4.46817 5.1304C5.3554 4.90181 6.24072 4.59734 7.14678 4.38927L7.53683 4.30615ZM9.39272 5.7709C9.07191 5.73885 8.69879 5.75781 8.2888 5.8164L7.8661 5.88727C7.43972 5.97006 7.00368 6.0878 6.52543 6.2259L7.4942 7.1779L8.2117 7.2794L8.37588 7.3109C9.18373 7.50483 9.73066 8.25226 9.63038 9.06615L9.47889 10.2938C9.47241 10.3462 9.46246 10.3983 9.45077 10.4495L10.4839 11.4663C10.9068 11.2103 11.4341 11.1464 11.9189 11.3079C12.5185 11.5079 12.947 12.0182 13.0292 12.623L14.0107 13.5882L14.3635 13.5269L15.8312 12.0832L15.9056 11.6737L14.8869 10.6709C14.8569 10.6693 14.8222 10.6665 14.7817 10.6648C14.7283 10.6625 14.6555 10.6599 14.5858 10.656L14.3336 10.6359C13.8765 10.5853 13.4609 10.3551 13.1852 9.99978C12.9097 9.64421 12.7979 9.19376 12.8768 8.7564L12.8868 8.7039L10.2327 6.0929C10.0903 5.95302 9.87595 5.84351 9.5433 5.79015L9.39272 5.7709Z" fill="currentColor"/>
<path d="M18.7184 6.60652C18.9958 6.07886 19.7872 6.07886 20.0646 6.60652C20.2524 6.96391 20.3463 7.14291 20.4718 7.29777C20.5832 7.43517 20.7129 7.55849 20.8573 7.6644C21.0201 7.78372 21.2084 7.87255 21.5839 8.05115C22.1387 8.31498 22.1387 9.06832 21.5839 9.33215C21.2082 9.51082 21.0202 9.6004 20.8573 9.71977C20.7129 9.82568 20.5832 9.94902 20.4718 10.0864C20.3464 10.2412 20.2524 10.4204 20.0646 10.7777C19.7871 11.3049 18.9959 11.3049 18.7184 10.7777C18.5306 10.4204 18.4366 10.2412 18.3112 10.0864C18.1998 9.94903 18.0701 9.82568 17.9257 9.71977C17.7628 9.60041 17.5748 9.51082 17.1991 9.33215C16.6443 9.06832 16.6443 8.31498 17.1991 8.05115C17.5746 7.87254 17.7629 7.78373 17.9257 7.6644C18.0701 7.55848 18.1998 7.43517 18.3112 7.29777C18.4367 7.14291 18.5306 6.96392 18.7184 6.60652Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -0,0 +1,8 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0_5432_2123" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="1" y="1" width="22" height="22">
<path d="M18 10.0001L14 6.00006M2.5 21.5001L5.88437 21.124C6.29786 21.0781 6.5046 21.0551 6.69785 20.9925C6.86929 20.937 7.03245 20.8586 7.18289 20.7594C7.35245 20.6476 7.49955 20.5005 7.79373 20.2063L21 7.00006C22.1046 5.89549 22.1046 4.10463 21 3.00006C19.8955 1.89549 18.1046 1.89549 17 3.00006L3.79373 16.2063C3.49955 16.5005 3.35246 16.6476 3.24064 16.8172C3.14143 16.9676 3.06301 17.1308 3.00751 17.3022C2.94496 17.4955 2.92198 17.7022 2.87604 18.1157L2.5 21.5001Z" stroke="#6C7E9D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</mask>
<g mask="url(#mask0_5432_2123)">
<rect width="24" height="24" fill="currentColor" fill-opacity="0.9"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 888 B

View File

@ -0,0 +1,8 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0_5432_1323" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="1" y="2" width="21" height="21">
<path d="M12 10.5V7M12 14H12.01M7 18V20.3355C7 20.8684 7 21.1348 7.10923 21.2716C7.20422 21.3906 7.34827 21.4599 7.50054 21.4597C7.67563 21.4595 7.88367 21.2931 8.29976 20.9602L10.6852 19.0518C11.1725 18.662 11.4162 18.4671 11.6875 18.3285C11.9282 18.2055 12.1844 18.1156 12.4492 18.0613C12.7477 18 13.0597 18 13.6837 18H16.2C17.8802 18 18.7202 18 19.362 17.673C19.9265 17.3854 20.3854 16.9265 20.673 16.362C21 15.7202 21 14.8802 21 13.2V7.8C21 6.11984 21 5.27976 20.673 4.63803C20.3854 4.07354 19.9265 3.6146 19.362 3.32698C18.7202 3 17.8802 3 16.2 3H7.8C6.11984 3 5.27976 3 4.63803 3.32698C4.07354 3.6146 3.6146 4.07354 3.32698 4.63803C3 5.27976 3 6.11984 3 7.8V14C3 14.93 3 15.395 3.10222 15.7765C3.37962 16.8117 4.18827 17.6204 5.22354 17.8978C5.60504 18 6.07003 18 7 18Z" stroke="#6C7E9D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</mask>
<g mask="url(#mask0_5432_1323)">
<rect width="24" height="24" fill="currentColor" fill-opacity="0.9"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -31,27 +31,25 @@ section and choose the best installation path for you.
> employees OR more than $10 million USD in annual revenue) requires a [paid
> subscription](https://www.docker.com/pricing/).
<div class="not-prose">
{{< card
title="Docker Desktop for Mac"
description="A native application using the macOS sandbox security model that delivers all Docker tools to your Mac."
link="/desktop/setup/install/mac-install/"
icon="/assets/images/apple_48.svg" >}}
<br>
icon="/icons/AppleMac.svg" >}}
{{< card
title="Docker Desktop for Windows"
description="A native Windows application that delivers all Docker tools to your Windows computer."
link="/desktop/setup/install/windows-install/"
icon="/assets/images/windows_48.svg" >}}
<br>
icon="/icons/Windows.svg" >}}
{{< card
title="Docker Desktop for Linux"
description="A native Linux application that delivers all Docker tools to your Linux computer."
link="/desktop/setup/install/linux/"
icon="/assets/images/linux_48.svg" >}}
icon="/icons/Linux.svg" >}}
</div>
> [!NOTE]
>

View File

@ -29,21 +29,18 @@ This guide will walk you through the installation process, enabling you to exper
{{< card
title="Docker Desktop for Mac"
description="[Download (Apple Silicon)](https://desktop.docker.com/mac/main/arm64/Docker.dmg?utm_source=docker&utm_medium=webreferral&utm_campaign=docs-driven-download-mac-arm64) | [Download (Intel)](https://desktop.docker.com/mac/main/amd64/Docker.dmg?utm_source=docker&utm_medium=webreferral&utm_campaign=docs-driven-download-mac-amd64) | [Install instructions](/desktop/setup/install/mac-install)"
icon="/assets/images/apple_48.svg" >}}
<br>
icon="/icons/AppleMac.svg" >}}
{{< card
title="Docker Desktop for Windows"
description="[Download](https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe?utm_source=docker&utm_medium=webreferral&utm_campaign=docs-driven-download-windows) | [Install instructions](/desktop/setup/install/windows-install)"
icon="/assets/images/windows_48.svg" >}}
<br>
icon="/icons/Windows.svg" >}}
{{< card
title="Docker Desktop for Linux"
description="[Install instructions](/desktop/setup/install/linux/)"
icon="/assets/images/linux_48.svg" >}}
icon="/icons/Linux.svg" >}}
Once it's installed, complete the setup process and you're all set to run a Docker container.
@ -94,4 +91,3 @@ Docker Desktop simplifies container management for developers by streamlining th
Now that you have Docker Desktop installed and ran your first container, it's time to start developing with containers.
{{< button text="Develop with containers" url="develop-with-containers" >}}

View File

@ -0,0 +1,50 @@
---
title: Angular language-specific guide
linkTitle: Angular
description: Containerize and develop Angular apps using Docker
keywords: getting started, angular, docker, language, Dockerfile
summary: |
This guide explains how to containerize Angular applications using Docker.
toc_min: 1
toc_max: 2
languages: [js]
params:
time: 20 minutes
---
The Angular language-specific guide shows you how to containerize an Angular application using Docker, following best practices for creating efficient, production-ready containers.
[Angular](https://angular.dev/) is a robust and widely adopted framework for building dynamic, enterprise-grade web applications. However, managing dependencies, environments, and deployments can become complex as applications scale. Docker streamlines these challenges by offering a consistent, isolated environment for development and production.
>
> **Acknowledgment**
>
> Docker extends its sincere gratitude to [Kristiyan Velkov](https://www.linkedin.com/in/kristiyan-velkov-763130b3/) for authoring this guide. As a Docker Captain and experienced Front-end engineer, his expertise in Docker, DevOps, and modern web development has made this resource essential for the community, helping developers navigate and optimize their Docker workflows.
---
## What will you learn?
In this guide, you will learn how to:
- Containerize and run an Angular application using Docker.
- Set up a local development environment for Angular inside a container.
- Run tests for your Angular application within a Docker container.
- Configure a CI/CD pipeline using GitHub Actions for your containerized app.
- Deploy the containerized Angular application to a local Kubernetes cluster for testing and debugging.
You'll start by containerizing an existing Angular application and work your way up to production-level deployments.
---
## Prerequisites
Before you begin, ensure you have a working knowledge of:
- Basic understanding of [TypeScript](https://www.typescriptlang.org/) and [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript).
- Familiarity with [Node.js](https://nodejs.org/en) and [npm](https://docs.npmjs.com/about-npm) for managing dependencies and running scripts.
- Familiarity with [Angular](https://angular.io/) fundamentals.
- Understanding of core Docker concepts such as images, containers, and Dockerfiles. If you're new to Docker, start with the [Docker basics](/get-started/docker-concepts/the-basics/what-is-a-container.md) guide.
Once you've completed the Angular getting started modules, youll be fully prepared to containerize your own Angular application using the detailed examples and best practices outlined in this guide.

View File

@ -0,0 +1,323 @@
---
title: Automate your builds with GitHub Actions
linkTitle: Automate your builds with GitHub Actions
weight: 60
keywords: CI/CD, GitHub( Actions), Angular
description: Learn how to configure CI/CD using GitHub Actions for your Angular application.
---
## Prerequisites
Complete all the previous sections of this guide, starting with [Containerize an Angular application](containerize.md).
You must also have:
- A [GitHub](https://github.com/signup) account.
- A [Docker Hub](https://hub.docker.com/signup) account.
---
## Overview
In this section, you'll set up a CI/CD pipeline using [GitHub Actions](https://docs.github.com/en/actions) to automatically:
- Build your Angular application inside a Docker container.
- Run tests in a consistent environment.
- Push the production-ready image to [Docker Hub](https://hub.docker.com).
---
## Connect your GitHub repository to Docker Hub
To enable GitHub Actions to build and push Docker images, youll securely store your Docker Hub credentials in your new GitHub repository.
### Step 1: Generate Docker Hub Credentials and Set GitHub Secrets"
1. Create a Personal Access Token (PAT) from [Docker Hub](https://hub.docker.com)
1. Go to your **Docker Hub account → Account Settings → Security**.
2. Generate a new Access Token with **Read/Write** permissions.
3. Name it something like `docker-angular-sample`.
4. Copy and save the token — youll need it in Step 4.
2. Create a repository in [Docker Hub](https://hub.docker.com/repositories/)
1. Go to your **Docker Hub account → Create a repository**.
2. For the Repository Name, use something descriptive — for example: `angular-sample`.
3. Once created, copy and save the repository name — youll need it in Step 4.
3. Create a new [GitHub repository](https://github.com/new) for your Angular project
4. Add Docker Hub credentials as GitHub repository secrets
In your newly created GitHub repository:
1. Navigate to:
**Settings → Secrets and variables → Actions → New repository secret**.
2. Add the following secrets:
| Name | Value |
|-------------------|--------------------------------|
| `DOCKER_USERNAME` | Your Docker Hub username |
| `DOCKERHUB_TOKEN` | Your Docker Hub access token (created in Step 1) |
| `DOCKERHUB_PROJECT_NAME` | Your Docker Project Name (created in Step 2) |
These secrets allow GitHub Actions to authenticate securely with Docker Hub during automated workflows.
5. Connect Your Local Project to GitHub
Link your local project `docker-angular-sample` to the GitHub repository you just created by running the following command from your project root:
```console
$ git remote set-url origin https://github.com/{your-username}/{your-repository-name}.git
```
>[!IMPORTANT]
>Replace `{your-username}` and `{your-repository}` with your actual GitHub username and repository name.
To confirm that your local project is correctly connected to the remote GitHub repository, run:
```console
$ git remote -v
```
You should see output similar to:
```console
origin https://github.com/{your-username}/{your-repository-name}.git (fetch)
origin https://github.com/{your-username}/{your-repository-name}.git (push)
```
This confirms that your local repository is properly linked and ready to push your source code to GitHub.
6. Push your source code to GitHub
Follow these steps to commit and push your local project to your GitHub repository:
1. Stage all files for commit.
```console
$ git add -A
```
This command stages all changes — including new, modified, and deleted files — preparing them for commit.
2. Commit the staged changes with a descriptive message.
```console
$ git commit -m "Initial commit"
```
This command creates a commit that snapshots the staged changes with a descriptive message.
3. Push the code to the `main` branch.
```console
$ git push -u origin main
```
This command pushes your local commits to the `main` branch of the remote GitHub repository and sets the upstream branch.
Once completed, your code will be available on GitHub, and any GitHub Actions workflow youve configured will run automatically.
> [!NOTE]
> Learn more about the Git commands used in this step:
> - [Git add](https://git-scm.com/docs/git-add) Stage changes (new, modified, deleted) for commit
> - [Git commit](https://git-scm.com/docs/git-commit) Save a snapshot of your staged changes
> - [Git push](https://git-scm.com/docs/git-push) Upload local commits to your GitHub repository
> - [Git remote](https://git-scm.com/docs/git-remote) View and manage remote repository URLs
---
### Step 2: Set up the workflow
Now you'll create a GitHub Actions workflow that builds your Docker image, runs tests, and pushes the image to Docker Hub.
1. Go to your repository on GitHub and select the **Actions** tab in the top menu.
2. Select **Set up a workflow yourself** when prompted.
This opens an inline editor to create a new workflow file. By default, it will be saved to:
`.github/workflows/main.yml`
3. Add the following workflow configuration to the new file:
```yaml
name: CI/CD Angular Application with Docker
on:
push:
branches: [main]
pull_request:
branches: [main]
types: [opened, synchronize, reopened]
jobs:
build-test-push:
name: Build, Test, and Push Docker Image
runs-on: ubuntu-latest
steps:
# 1. Checkout source code
- name: Checkout source code
uses: actions/checkout@v4
with:
fetch-depth: 0
# 2. Set up Docker Buildx
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# 3. Cache Docker layers
- name: Cache Docker layers
uses: actions/cache@v4
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
# 4. Cache npm dependencies
- name: Cache npm dependencies
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-
# 5. Extract metadata
- name: Extract metadata
id: meta
run: |
echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> "$GITHUB_OUTPUT"
echo "SHORT_SHA=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"
# 6. Build dev Docker image
- name: Build Docker image for tests
uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile.dev
tags: ${{ steps.meta.outputs.REPO_NAME }}-dev:latest
load: true
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache,mode=max
# 7. Run Angular tests with Jasmine
- name: Run Angular Jasmine tests inside container
run: |
docker run --rm \
--workdir /app \
--entrypoint "" \
${{ steps.meta.outputs.REPO_NAME }}-dev:latest \
sh -c "npm ci && npm run test -- --ci --runInBand"
env:
CI: true
NODE_ENV: test
timeout-minutes: 10
# 8. Log in to Docker Hub
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# 9. Build and push production image
- name: Build and push production image
uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile
push: true
platforms: linux/amd64,linux/arm64
tags: |
${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKERHUB_PROJECT_NAME }}:latest
${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKERHUB_PROJECT_NAME }}:${{ steps.meta.outputs.SHORT_SHA }}
cache-from: type=local,src=/tmp/.buildx-cache
```
This workflow performs the following tasks for your Angular application:
- Triggers on every `push` or `pull request` targeting the `main` branch.
- Builds a development Docker image using `Dockerfile.dev`, optimized for testing.
- Executes unit tests using Vitest inside a clean, containerized environment to ensure consistency.
- Halts the workflow immediately if any test fails — enforcing code quality.
- Caches both Docker build layers and npm dependencies for faster CI runs.
- Authenticates securely with Docker Hub using GitHub repository secrets.
- Builds a production-ready image using the `prod` stage in `Dockerfile`.
- Tags and pushes the final image to Docker Hub with both `latest` and short SHA tags for traceability.
> [!NOTE]
> For more information about `docker/build-push-action`, refer to the [GitHub Action README](https://github.com/docker/build-push-action/blob/master/README.md).
---
### Step 3: Run the workflow
After you've added your workflow file, it's time to trigger and observe the CI/CD process in action.
1. Commit and push your workflow file
- Select "Commit changes…" in the GitHub editor.
- This push will automatically trigger the GitHub Actions pipeline.
2. Monitor the workflow execution
- Go to the Actions tab in your GitHub repository.
- Click into the workflow run to follow each step: **build**, **test**, and (if successful) **push**.
3. Verify the Docker image on Docker Hub
- After a successful workflow run, visit your [Docker Hub repositories](https://hub.docker.com/repositories).
- You should see a new image under your repository with:
- Repository name: `${your-repository-name}`
- Tags include:
- `latest` represents the most recent successful build; ideal for quick testing or deployment.
- `<short-sha>` a unique identifier based on the commit hash, useful for version tracking, rollbacks, and traceability.
> [!TIP] Protect your main branch
> To maintain code quality and prevent accidental direct pushes, enable branch protection rules:
> - Navigate to your **GitHub repo → Settings → Branches**.
> - Under Branch protection rules, click **Add rule**.
> - Specify `main` as the branch name.
> - Enable options like:
> - *Require a pull request before merging*.
> - *Require status checks to pass before merging*.
>
> This ensures that only tested and reviewed code is merged into `main` branch.
---
## Summary
In this section, you set up a complete CI/CD pipeline for your containerized Angular application using GitHub Actions.
Here's what you accomplished:
- Created a new GitHub repository specifically for your project.
- Generated a secure Docker Hub access token and added it to GitHub as a secret.
- Defined a GitHub Actions workflow that:
- Build your application inside a Docker container.
- Run tests in a consistent, containerized environment.
- Push a production-ready image to Docker Hub if tests pass.
- Triggered and verified the workflow execution through GitHub Actions.
- Confirmed that your image was successfully published to Docker Hub.
With this setup, your Angular application is now ready for automated testing and deployment across environments — increasing confidence, consistency, and team productivity.
---
## Related resources
Deepen your understanding of automation and best practices for containerized apps:
- [Introduction to GitHub Actions](/guides/gha.md) Learn how GitHub Actions automate your workflows
- [Docker Build GitHub Actions](/manuals/build/ci/github-actions/_index.md) Set up container builds with GitHub Actions
- [Workflow syntax for GitHub Actions](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions) Full reference for writing GitHub workflows
- [Compose file reference](/compose/compose-file/) Full configuration reference for `compose.yaml`
- [Best practices for writing Dockerfiles](/develop/develop-images/dockerfile_best-practices/) Optimize your image for performance and security
---
## Next steps
Next, learn how you can locally test and debug your Angular workloads on Kubernetes before deploying. This helps you ensure your application behaves as expected in a production-like environment, reducing surprises during deployment.

View File

@ -0,0 +1,503 @@
---
title: Containerize an Angular Application
linkTitle: Containerize
weight: 10
keywords: angular, node, image, initialize, build
description: Learn how to containerize an Angular application with Docker by creating an optimized, production-ready image using best practices for performance, security, and scalability.
---
## Prerequisites
Before you begin, make sure the following tools are installed and available on your system:
- You have installed the latest version of [Docker Desktop](/get-started/get-docker.md).
- You have a [git client](https://git-scm.com/downloads). The examples in this section use a command-line based git client, but you can use any client.
> **New to Docker?**
> Start with the [Docker basics](/get-started/docker-concepts/the-basics/what-is-a-container.md) guide to get familiar with key concepts like images, containers, and Dockerfiles.
---
## Overview
This guide walks you through the complete process of containerizing an Angular application with Docker. Youll learn how to create a production-ready Docker image using best practices that improve performance, security, scalability, and deployment efficiency.
By the end of this guide, you will:
- Containerize an Angular application using Docker.
- Create and optimize a Dockerfile for production builds.
- Use multi-stage builds to minimize image size.
- Serve the application efficiently with a custom NGINX configuration.
- Build secure and maintainable Docker images by following best practices.
---
## Get the sample application
Clone the sample application to use with this guide. Open a terminal, navigate to the directory where you want to work, and run the following command
to clone the git repository:
```console
$ git clone https://github.com/kristiyan-velkov/docker-angular-sample
```
---
## Generate a Dockerfile
Docker provides an interactive CLI tool called `docker init` that helps scaffold the necessary configuration files for containerizing your application. This includes generating a `Dockerfile`, `.dockerignore`, `compose.yaml`, and `README.Docker.md`.
To begin, navigate to the root of your project directory:
```console
$ cd docker-angular-sample
```
Then run the following command:
```console
$ docker init
```
Youll see output similar to:
```text
Welcome to the Docker Init CLI!
This utility will walk you through creating the following files with sensible defaults for your project:
- .dockerignore
- Dockerfile
- compose.yaml
- README.Docker.md
Let's get started!
```
The CLI will prompt you with a few questions about your app setup.
For consistency, please use the same responses shown in the example below when prompted:
| Question | Answer |
|------------------------------------------------------------|-----------------|
| What application platform does your project use? | Node |
| What version of Node do you want to use? | 23.11.0-alpine |
| Which package manager do you want to use? | npm |
| Do you want to run "npm run build" before starting server? | yes |
| What directory is your build output to? | dist |
| What command do you want to use to start the app? | npm run start |
| What port does your server listen on? | 8080 |
After completion, your project directory will contain the following new files:
```text
├── docker-angular-sample/
│ ├── Dockerfile
│ ├── .dockerignore
│ ├── compose.yaml
│ └── README.Docker.md
```
---
## Build the Docker image
The default Dockerfile generated by `docker init` serves as a solid starting point for general Node.js applications. However, Angular is a front-end framework that compiles into static assets, so we need to tailor the Dockerfile to optimize for how Angular applications are built and served in a production environment.
### Step 1: Improve the generated Dockerfile and configuration
In this step, youll improve the Dockerfile and configuration files by following best practices:
- Use multi-stage builds to keep the final image clean and small
- Serve the app using NGINX, a fast and secure web server
- Improve performance and security by only including whats needed
These updates help ensure your app is easy to deploy, fast to load, and production-ready.
> [!NOTE]
> A `Dockerfile` is a plain text file that contains step-by-step instructions to build a Docker image. It automates packaging your application along with its dependencies and runtime environment.
> For full details, see the [Dockerfile reference](/reference/dockerfile/).
### Step 2: Configure the Dockerfile
Copy and replace the contents of your existing `Dockerfile` with the configuration below:
```dockerfile
# =========================================
# Stage 1: Build the Angular Application
# =========================================
# =========================================
# Stage 1: Build the Angular Application
# =========================================
ARG NODE_VERSION=22.14.0-alpine
ARG NGINX_VERSION=alpine3.21
# Use a lightweight Node.js image for building (customizable via ARG)
FROM node:${NODE_VERSION} AS builder
# Set the working directory inside the container
WORKDIR /app
# Copy package-related files first to leverage Docker's caching mechanism
COPY package.json package-lock.json ./
# Install project dependencies using npm ci (ensures a clean, reproducible install)
RUN --mount=type=cache,target=/root/.npm npm ci
# Copy the rest of the application source code into the container
COPY . .
# Build the Angular application
RUN npm run build
# =========================================
# Stage 2: Prepare Nginx to Serve Static Files
# =========================================
FROM nginxinc/nginx-unprivileged:${NGINX_VERSION} AS runner
# Use a built-in non-root user for security best practices
USER nginx
# Copy custom Nginx config
COPY nginx.conf /etc/nginx/nginx.conf
# Copy the static build output from the build stage to Nginx's default HTML serving directory
COPY --chown=nginx:nginx --from=builder /app/dist/*/browser /usr/share/nginx/html
# Expose port 8080 to allow HTTP traffic
# Note: The default NGINX container now listens on port 8080 instead of 80
EXPOSE 8080
# Start Nginx directly with custom config
ENTRYPOINT ["nginx", "-c", "/etc/nginx/nginx.conf"]
CMD ["-g", "daemon off;"]
```
> [!NOTE]
> We are using nginx-unprivileged instead of the standard NGINX image to follow security best practices.
> Running as a non-root user in the final image:
>- Reduces the attack surface
>- Aligns with Dockers recommendations for container hardening
>- Helps comply with stricter security policies in production environments
### Step 3: Configure the .dockerignore file
The `.dockerignore` file tells Docker which files and folders to exclude when building the image.
> [!NOTE]
>This helps:
>- Reduce image size
>- Speed up the build process
>- Prevent sensitive or unnecessary files (like `.env`, `.git`, or `node_modules`) from being added to the final image.
>
> To learn more, visit the [.dockerignore reference](/reference/dockerfile.md#dockerignore-file).
Copy and replace the contents of your existing `.dockerignore` with the configuration below:
```dockerignore
# ================================
# Node and build output
# ================================
node_modules
dist
out-tsc
.angular
.cache
.tmp
# ================================
# Testing & Coverage
# ================================
coverage
jest
cypress
cypress/screenshots
cypress/videos
reports
playwright-report
.vite
.vitepress
# ================================
# Environment & log files
# ================================
*.env*
!*.env.production
*.log
*.tsbuildinfo
# ================================
# IDE & OS-specific files
# ================================
.vscode
.idea
.DS_Store
Thumbs.db
*.swp
# ================================
# Version control & CI files
# ================================
.git
.gitignore
# ================================
# Docker & local orchestration
# ================================
Dockerfile
Dockerfile.*
.dockerignore
docker-compose.yml
docker-compose*.yml
# ================================
# Miscellaneous
# ================================
*.bak
*.old
*.tmp
```
### Step 4: Create the `nginx.conf` file
To serve your Angular application efficiently inside the container, youll configure NGINX with a custom setup. This configuration is optimized for performance, browser caching, gzip compression, and support for client-side routing.
Create a file named `nginx.conf` in the root of your project directory, and add the following content:
> [!NOTE]
> To learn more about configuring NGINX, see the [official NGINX documentation](https://nginx.org/en/docs/).
```nginx
worker_processes auto;
pid /tmp/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Logging
access_log off;
error_log /dev/stderr warn;
# Performance
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 1000;
# Compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_min_length 256;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/x-javascript
application/json
application/xml
application/xml+rss
font/ttf
font/otf
image/svg+xml;
server {
listen 8080;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# Angular Routing
location / {
try_files $uri $uri/ /index.html;
}
# Static Assets Caching
location ~* \.(?:ico|css|js|gif|jpe?g|png|woff2?|eot|ttf|svg|map)$ {
expires 1y;
access_log off;
add_header Cache-Control "public, immutable";
}
# Optional: Explicit asset route
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
}
```
### Step 5: Build the Angular application image
With your custom configuration in place, you're now ready to build the Docker image for your Angular application.
The updated setup includes:
- The updated setup includes a clean, production-ready NGINX configuration tailored specifically for Angular.
- Efficient multi-stage Docker build, ensuring a small and secure final image.
After completing the previous steps, your project directory should now contain the following files:
```text
├── docker-angular-sample/
│ ├── Dockerfile
│ ├── .dockerignore
│ ├── compose.yaml
│ ├── nginx.conf
│ └── README.Docker.md
```
Now that your Dockerfile is configured, you can build the Docker image for your Angular application.
> [!NOTE]
> The `docker build` command packages your application into an image using the instructions in the Dockerfile. It includes all necessary files from the current directory (called the [build context](/build/concepts/context/#what-is-a-build-context)).
Run the following command from the root of your project:
```console
$ docker build --tag docker-angular-sample .
```
What this command does:
- Uses the Dockerfile in the current directory (.)
- Packages the application and its dependencies into a Docker image
- Tags the image as docker-angular-sample so you can reference it later
#### Step 6: View local images
After building your Docker image, you can check which images are available on your local machine using either the Docker CLI or [Docker Desktop](/manuals/desktop/use-desktop/images.md). Since you're already working in the terminal, let's use the Docker CLI.
To list all locally available Docker images, run the following command:
```console
$ docker images
```
Example Output:
```shell
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-angular-sample latest 34e66bdb9d40 14 seconds ago 76.4MB
```
This output provides key details about your images:
- **Repository** The name assigned to the image.
- **Tag** A version label that helps identify different builds (e.g., latest).
- **Image ID** A unique identifier for the image.
- **Created** The timestamp indicating when the image was built.
- **Size** The total disk space used by the image.
If the build was successful, you should see `docker-angular-sample` image listed.
---
## Run the containerized application
In the previous step, you created a Dockerfile for your Angular application and built a Docker image using the docker build command. Now its time to run that image in a container and verify that your application works as expected.
Inside the `docker-angular-sample` directory, run the following command in a
terminal.
```console
$ docker compose up --build
```
Open a browser and view the application at [http://localhost:8080](http://localhost:8080). You should see a simple Angular web application.
Press `ctrl+c` in the terminal to stop your application.
### Run the application in the background
You can run the application detached from the terminal by adding the `-d`
option. Inside the `docker-angular-sample` directory, run the following command
in a terminal.
```console
$ docker compose up --build -d
```
Open a browser and view the application at [http://localhost:8080](http://localhost:8080). You should see your Angular application running in the browser.
To confirm that the container is running, use `docker ps` command:
```console
$ docker ps
```
This will list all active containers along with their ports, names, and status. Look for a container exposing port 8080.
Example Output:
```shell
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
eb13026806d1 docker-angular-sample-server "nginx -c /etc/nginx…" About a minute ago Up About a minute 0.0.0.0:8080->8080/tcp docker-angular-sample-server-1
```
To stop the application, run:
```console
$ docker compose down
```
> [!NOTE]
> For more information about Compose commands, see the [Compose CLI
> reference](/reference/cli/docker/compose/_index.md).
---
## Summary
In this guide, you learned how to containerize, build, and run an Angular application using Docker. By following best practices, you created a secure, optimized, and production-ready setup.
What you accomplished:
- Initialized your project using `docker init` to scaffold essential Docker configuration files.
- Replaced the default `Dockerfile` with a multi-stage build that compiles the Angular application and serves the static files using Nginx.
- Replaced the default `.dockerignore` file to exclude unnecessary files and keep the image clean and efficient.
- Built your Docker image using `docker build`.
- Ran the container using `docker compose up`, both in the foreground and in detached mode.
- Verified that the app was running by visiting [http://localhost:8080](http://localhost:8080).
- Learned how to stop the containerized application using `docker compose down`.
You now have a fully containerized Angular application, running in a Docker container, and ready for deployment across any environment with confidence and consistency.
---
## Related resources
Explore official references and best practices to sharpen your Docker workflow:
- [Multi-stage builds](/build/building/multi-stage/) Learn how to separate build and runtime stages.
- [Best practices for writing Dockerfiles](/develop/develop-images/dockerfile_best-practices/) Write efficient, maintainable, and secure Dockerfiles.
- [Build context in Docker](/build/concepts/context/) Learn how context affects image builds.
- [`docker init` CLI reference](/reference/cli/docker/init/) Scaffold Docker assets automatically.
- [`docker build` CLI reference](/reference/cli/docker/build/) Build Docker images from a Dockerfile.
- [`docker images` CLI reference](/reference/cli/docker/images/) Manage and inspect local Docker images.
- [`docker compose up` CLI reference](/reference/cli/docker/compose/up/) Start and run multi-container applications.
- [`docker compose down` CLI reference](/reference/cli/docker/compose/down/) Stop and remove containers, networks, and volumes.
---
## Next steps
With your Angular application now containerized, you're ready to move on to the next step.
In the next section, you'll learn how to develop your application using Docker containers, enabling a consistent, isolated, and reproducible development environment across any machine.

View File

@ -0,0 +1,201 @@
---
title: Test your Angular deployment
linkTitle: Test your deployment
weight: 60
keywords: deploy, kubernetes, angular
description: Learn how to deploy locally to test and debug your Kubernetes deployment
---
## Prerequisites
Before you begin, make sure youve completed the following:
- Complete all the previous sections of this guide, starting with [Containerize Angular application](containerize.md).
- [Enable Kubernetes](/manuals/desktop/features/kubernetes.md#install-and-turn-on-kubernetes) in Docker Desktop.
> **New to Kubernetes?**
> Visit the [Kubernetes basics tutorial](https://kubernetes.io/docs/tutorials/kubernetes-basics/) to get familiar with how clusters, pods, deployments, and services work.
---
## Overview
This section guides you through deploying your containerized Angular application locally using [Docker Desktops built-in Kubernetes](/desktop/kubernetes/). Running your app in a local Kubernetes cluster closely simulates a real production environment, enabling you to test, validate, and debug your workloads with confidence before promoting them to staging or production.
---
## Create a Kubernetes YAML file
Follow these steps to define your deployment configuration:
1. In the root of your project, create a new file named: angular-sample-kubernetes.yaml
2. Open the file in your IDE or preferred text editor.
3. Add the following configuration, and be sure to replace `{DOCKER_USERNAME}` and `{DOCKERHUB_PROJECT_NAME}` with your actual Docker Hub username and repository name from the previous [Automate your builds with GitHub Actions](configure-github-actions.md).
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: angular-sample
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: angular-sample
template:
metadata:
labels:
app: angular-sample
spec:
containers:
- name: angular-container
image: {DOCKER_USERNAME}/{DOCKERHUB_PROJECT_NAME}:latest
imagePullPolicy: Always
ports:
- containerPort: 8080
resources:
limits:
cpu: "500m"
memory: "256Mi"
requests:
cpu: "250m"
memory: "128Mi"
---
apiVersion: v1
kind: Service
metadata:
name: angular-sample-service
namespace: default
spec:
type: NodePort
selector:
app: angular-sample
ports:
- port: 8080
targetPort: 8080
nodePort: 30001
```
This manifest defines two key Kubernetes resources, separated by `---`:
- Deployment
Deploys a single replica of your Angular application inside a pod. The pod uses the Docker image built and pushed by your GitHub Actions CI/CD workflow
(refer to [Automate your builds with GitHub Actions](configure-github-actions.md)).
The container listens on port `8080`, which is typically used by [Nginx](https://nginx.org/en/docs/) to serve your production Angular app.
- Service (NodePort)
Exposes the deployed pod to your local machine.
It forwards traffic from port `30001` on your host to port `8080` inside the container.
This lets you access the application in your browser at [http://localhost:30001](http://localhost:30001).
> [!NOTE]
> To learn more about Kubernetes objects, see the [Kubernetes documentation](https://kubernetes.io/docs/home/).
---
## Deploy and check your application
Follow these steps to deploy your containerized Angular app into a local Kubernetes cluster and verify that its running correctly.
### Step 1. Apply the Kubernetes configuration
In your terminal, navigate to the directory where your `angular-sample-kubernetes.yaml` file is located, then deploy the resources using:
```console
$ kubectl apply -f angular-sample-kubernetes.yaml
```
If everything is configured properly, youll see confirmation that both the Deployment and the Service were created:
```shell
deployment.apps/angular-sample created
service/angular-sample-service created
```
This confirms that both the Deployment and the Service were successfully created and are now running inside your local cluster.
### Step 2. Check the Deployment status
Run the following command to check the status of your deployment:
```console
$ kubectl get deployments
```
You should see output similar to the following:
```shell
NAME READY UP-TO-DATE AVAILABLE AGE
angular-sample 1/1 1 1 14s
```
This confirms that your pod is up and running with one replica available.
### Step 3. Verify the Service exposure
Check if the NodePort service is exposing your app to your local machine:
```console
$ kubectl get services
```
You should see something like:
```shell
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
angular-sample-service NodePort 10.100.185.105 <none> 8080:30001/TCP 1m
```
This output confirms that your app is available via NodePort on port 30001.
### Step 4. Access your app in the browser
Open your browser and navigate to [http://localhost:30001](http://localhost:30001).
You should see your production-ready Angular Sample application running — served by your local Kubernetes cluster.
### Step 5. Clean up Kubernetes resources
Once you're done testing, you can delete the deployment and service using:
```console
$ kubectl delete -f angular-sample-kubernetes.yaml
```
Expected output:
```shell
deployment.apps "angular-sample" deleted
service "angular-sample-service" deleted
```
This ensures your cluster stays clean and ready for the next deployment.
---
## Summary
In this section, you learned how to deploy your Angular application to a local Kubernetes cluster using Docker Desktop. This setup allows you to test and debug your containerized app in a production-like environment before deploying it to the cloud.
What you accomplished:
- Created a Kubernetes Deployment and NodePort Service for your Angular app
- Used `kubectl apply` to deploy the application locally
- Verified the app was running and accessible at `http://localhost:30001`
- Cleaned up your Kubernetes resources after testing
---
## Related resources
Explore official references and best practices to sharpen your Kubernetes deployment workflow:
- [Kubernetes documentation](https://kubernetes.io/docs/home/) Learn about core concepts, workloads, services, and more.
- [Deploy on Kubernetes with Docker Desktop](/manuals/desktop/features/kubernetes.md) Use Docker Desktops built-in Kubernetes support for local testing and development.
- [`kubectl` CLI reference](https://kubernetes.io/docs/reference/kubectl/) Manage Kubernetes clusters from the command line.
- [Kubernetes Deployment resource](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) Understand how to manage and scale applications using Deployments.
- [Kubernetes Service resource](https://kubernetes.io/docs/concepts/services-networking/service/) Learn how to expose your application to internal and external traffic.

View File

@ -0,0 +1,179 @@
---
title: Use containers for Angular development
linkTitle: Develop your app
weight: 30
keywords: angular, development, node
description: Learn how to develop your Angular application locally using containers.
---
## Prerequisites
Complete [Containerize Angular application](containerize.md).
---
## Overview
In this section, you'll learn how to set up both production and development environments for your containerized Angular application using Docker Compose. This setup allows you to serve a static production build via Nginx and to develop efficiently inside containers using a live-reloading dev server with Compose Watch.
Youll learn how to:
- Configure separate containers for production and development
- Enable automatic file syncing using Compose Watch in development
- Debug and live-preview your changes in real-time without manual rebuilds
---
## Automatically update services (Development Mode)
Use Compose Watch to automatically sync source file changes into your containerized development environment. This provides a seamless, efficient development experience without restarting or rebuilding containers manually.
## Step 1: Create a development Dockerfile
Create a file named `Dockerfile.dev` in your project root with the following content:
```dockerfile
# =========================================
# Stage 1: Development - Angular Application
# =========================================
# Define the Node.js version to use (Alpine for a small footprint)
ARG NODE_VERSION=22.14.0-alpine
# Set the base image for development
FROM node:${NODE_VERSION} AS dev
# Set environment variable to indicate development mode
ENV NODE_ENV=development
# Set the working directory inside the container
WORKDIR /app
# Copy only the dependency files first to optimize Docker caching
COPY package.json package-lock.json ./
# Install dependencies using npm with caching to speed up subsequent builds
RUN --mount=type=cache,target=/root/.npm npm ci
# Copy all application source files into the container
COPY . .
# Expose the port Angular uses for the dev server (default is 4200)
EXPOSE 4200
# Start the Angular dev server and bind it to all network interfaces
CMD ["npm", "start", "--", "--host=0.0.0.0"]
```
This file sets up a lightweight development environment for your Angular application using the dev server.
### Step 2: Update your `compose.yaml` file
Open your `compose.yaml` file and define two services: one for production (`angular-prod`) and one for development (`angular-dev`).
Heres an example configuration for an Angular application:
```yaml
services:
angular-prod:
build:
context: .
dockerfile: Dockerfile
image: docker-angular-sample
ports:
- "8080:8080"
angular-dev:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "4200:4200"
develop:
watch:
- action: sync
path: .
target: /app
```
- The `angular-prod` service builds and serves your static production app using Nginx.
- The `angular-dev` service runs your Angular development server with live reload and hot module replacement.
- `watch` triggers file sync with Compose Watch.
> [!NOTE]
> For more details, see the official guide: [Use Compose Watch](/manuals/compose/how-tos/file-watch.md).
After completing the previous steps, your project directory should now contain the following files:
```text
├── docker-angular-sample/
│ ├── Dockerfile
│ ├── Dockerfile.dev
│ ├── .dockerignore
│ ├── compose.yaml
│ ├── nginx.conf
│ └── README.Docker.md
```
### Step 4: Start Compose Watch
Run the following command from the project root to start the container in watch mode
```console
$ docker compose watch angular-dev
```
### Step 5: Test Compose Watch with Angular
To verify that Compose Watch is working correctly:
1. Open the `src/app/app.component.html` file in your text editor.
2. Locate the following line:
```html
<h1>Docker Angular Sample Application</h1>
```
3. Change it to:
```html
<h1>Hello from Docker Compose Watch</h1>
```
4. Save the file.
5. Open your browser at [http://localhost:4200](http://localhost:4200).
You should see the updated text appear instantly, without needing to rebuild the container manually. This confirms that file watching and automatic synchronization are working as expected.
---
## Summary
In this section, you set up a complete development and production workflow for your Angular application using Docker and Docker Compose.
Heres what you accomplished:
- Created a `Dockerfile.dev` to streamline local development with hot reloading
- Defined separate `angular-dev` and `angular-prod` services in your `compose.yaml` file
- Enabled real-time file syncing using Compose Watch for a smoother development experience
- Verified that live updates work seamlessly by modifying and previewing a component
With this setup, you're now equipped to build, run, and iterate on your Angular app entirely within containers—efficiently and consistently across environments.
---
## Related resources
Deepen your knowledge and improve your containerized development workflow with these guides:
- [Using Compose Watch](/manuals/compose/how-tos/file-watch.md) Automatically sync source changes during development
- [Multi-stage builds](/manuals/build/building/multi-stage.md) Create efficient, production-ready Docker images
- [Dockerfile best practices](/build/building/best-practices/) Write clean, secure, and optimized Dockerfiles.
- [Compose file reference](/compose/compose-file/) Learn the full syntax and options available for configuring services in `compose.yaml`.
- [Docker volumes](/storage/volumes/) Persist and manage data between container runs
## Next steps
In the next section, you'll learn how to run unit tests for your Angular application inside Docker containers. This ensures consistent testing across all environments and removes dependencies on local machine setup.

View File

@ -0,0 +1,138 @@
---
title: Run Angular tests in a container
linkTitle: Run your tests
weight: 40
keywords: angular, test, jasmine
description: Learn how to run your Angular tests in a container.
---
## Prerequisites
Complete all the previous sections of this guide, starting with [Containerize Angular application](containerize.md).
## Overview
Testing is a critical part of the development process. In this section, you'll learn how to:
- Run Jasmine unit tests using the Angular CLI inside a Docker container.
- Use Docker Compose to isolate your test environment.
- Ensure consistency between local and container-based testing.
The `docker-angular-sample` project comes pre-configured with Jasmine, so you can get started quickly without extra setup.
---
## Run tests during development
The `docker-angular-sample` application includes a sample test file at the following location:
```console
$ src/app/app.component.spec.ts
```
This test uses Jasmine to validate the AppComponent logic.
### Step 1: Update compose.yaml
Add a new service named `angular-test` to your `compose.yaml` file. This service allows you to run your test suite in an isolated, containerized environment.
```yaml {hl_lines="22-26",linenos=true}
services:
angular-dev:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "5173:5173"
develop:
watch:
- action: sync
path: .
target: /app
angular-prod:
build:
context: .
dockerfile: Dockerfile
image: docker-angular-sample
ports:
- "8080:8080"
angular-test:
build:
context: .
dockerfile: Dockerfile.dev
command: ["npm", "run", "test"]
```
The angular-test service reuses the same `Dockerfile.dev` used for [development](develop.md) and overrides the default command to run tests with `npm run test`. This setup ensures a consistent test environment that matches your local development configuration.
After completing the previous steps, your project directory should contain the following files:
```text
├── docker-angular-sample/
│ ├── Dockerfile
│ ├── Dockerfile.dev
│ ├── .dockerignore
│ ├── compose.yaml
│ ├── nginx.conf
│ └── README.Docker.md
```
### Step 2: Run the tests
To execute your test suite inside the container, run the following command from your project root:
```console
$ docker compose run --rm angular-test
```
This command will:
- Start the `angular-test` service defined in your `compose.yaml` file.
- Execute the `npm run test` script using the same environment as development.
- Automatically removes the container after tests complete, using the [`docker compose run --rm`](/engine/reference/commandline/compose_run) command.
You should see output similar to the following:
```shell
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 1.529 s
```
> [!NOTE]
> For more information about Compose commands, see the [Compose CLI
> reference](/reference/cli/docker/compose/_index.md).
---
## Summary
In this section, you learned how to run unit tests for your Angular application inside a Docker container using Jasmine and Docker Compose.
What you accomplished:
- Created a `angular-test` service in `compose.yaml` to isolate test execution.
- Reused the development `Dockerfile.dev` to ensure consistency between dev and test environments.
- Ran tests inside the container using `docker compose run --rm angular-test`.
- Ensured reliable, repeatable testing across environments without depending on your local machine setup.
---
## Related resources
Explore official references and best practices to sharpen your Docker testing workflow:
- [Dockerfile reference](/reference/dockerfile/) Understand all Dockerfile instructions and syntax.
- [Best practices for writing Dockerfiles](/develop/develop-images/dockerfile_best-practices/) Write efficient, maintainable, and secure Dockerfiles.
- [Compose file reference](/compose/compose-file/) Learn the full syntax and options available for configuring services in `compose.yaml`.
- [`docker compose run` CLI reference](/reference/cli/docker/compose/run/) Run one-off commands in a service container.
---
## Next steps
Next, youll learn how to set up a CI/CD pipeline using GitHub Actions to automatically build and test your Angular application in a containerized environment. This ensures your code is validated on every push or pull request, maintaining consistency and reliability across your development workflow.

View File

@ -1,6 +1,6 @@
---
title: Configure CI/CD for your React.js application
linkTitle: Configure CI/CD
title: Automate your builds with GitHub Actions
linkTitle: Automate your builds with GitHub Actions
weight: 60
keywords: CI/CD, GitHub( Actions), React.js, Next.js
description: Learn how to configure CI/CD using GitHub Actions for your React.js application.

View File

@ -7,7 +7,6 @@ description: Learn how to containerize a React.js application with Docker by cre
---
## Prerequisites
Before you begin, make sure the following tools are installed and available on your system:
@ -135,13 +134,13 @@ FROM node:${NODE_VERSION} AS builder
WORKDIR /app
# Copy package-related files first to leverage Docker's caching mechanism
COPY --link package.json package-lock.json ./
COPY package.json package-lock.json ./
# Install project dependencies using npm ci (ensures a clean, reproducible install)
RUN --mount=type=cache,target=/root/.npm npm ci
# Copy the rest of the application source code into the container
COPY --link . .
COPY . .
# Build the React.js application (outputs to /app/dist)
RUN npm run build
@ -156,10 +155,10 @@ FROM nginxinc/nginx-unprivileged:${NGINX_VERSION} AS runner
USER nginx
# Copy custom Nginx config
COPY --link nginx.conf /etc/nginx/nginx.conf
COPY nginx.conf /etc/nginx/nginx.conf
# Copy the static build output from the build stage to Nginx's default HTML serving directory
COPY --link --from=builder /app/dist /usr/share/nginx/html
COPY --chown=nginx:nginx --from=builder /app/dist /usr/share/nginx/html
# Expose port 8080 to allow HTTP traffic
# Note: The default NGINX container now listens on port 8080 instead of 80

View File

@ -32,7 +32,7 @@ Follow these steps to define your deployment configuration:
2. Open the file in your IDE or preferred text editor.
3. Add the following configuration, and be sure to replace `{DOCKER_USERNAME}` and `{DOCKERHUB_PROJECT_NAME}` with your actual Docker Hub username and repository name from the previous [Configure CI/CD for your React.js application](configure-ci-cd.md).
3. Add the following configuration, and be sure to replace `{DOCKER_USERNAME}` and `{DOCKERHUB_PROJECT_NAME}` with your actual Docker Hub username and repository name from the previous [Automate your builds with GitHub Actions](configure-github-actions.md).
```yaml
@ -77,7 +77,7 @@ This manifest defines two key Kubernetes resources, separated by `---`:
- Deployment
Deploys a single replica of your React.js application inside a pod. The pod uses the Docker image built and pushed by your GitHub Actions CI/CD workflow
(refer to [Configure CI/CD for your React.js application](configure-ci-cd.md)).
(refer to [Automate your builds with GitHub Actions](configure-github-actions.md)).
The container listens on port `8080`, which is typically used by [Nginx](https://nginx.org/en/docs/) to serve your production React app.
- Service (NodePort)

View File

@ -45,13 +45,13 @@ FROM node:${NODE_VERSION} AS dev
WORKDIR /app
# Copy package-related files first to leverage Docker's caching mechanism
COPY --link package.json package-lock.json ./
COPY package.json package-lock.json ./
# Install project dependencies
RUN --mount=type=cache,target=/root/.npm npm install
# Copy the rest of the application source code into the container
COPY --link . .
COPY . .
# Expose the port used by the Vite development server
EXPOSE 5173

View File

@ -25,11 +25,11 @@ params:
link: /engine/
- title: Docker Compose
description: Define and run multi-container applications.
icon: /assets/icons/Compose.svg
icon: /icons/Compose.svg
link: /compose/
- title: Testcontainers
description: Run containers programmatically in your preferred programming language.
icon: /assets/icons/Testcontainers.svg
icon: /icons/Testcontainers.svg
link: /testcontainers/
ai:
- title: Ask Gordon
@ -47,11 +47,11 @@ params:
products:
- title: Docker Desktop
description: Your command center for container development.
icon: /assets/icons/Whale.svg
icon: /icons/Whale.svg
link: /desktop/
- title: Build Cloud
description: Build your images faster in the cloud.
icon: /assets/images/logo-build-cloud.svg
icon: /icons/logo-build-cloud.svg
link: /build-cloud/
- title: Docker Hub
description: Discover, share, and integrate container images.
@ -59,7 +59,7 @@ params:
link: /docker-hub/
- title: Docker Scout
description: Image analysis and policy evaluation.
icon: /assets/icons/Scout.svg
icon: /icons/Scout.svg
link: /scout/
- title: Docker for GitHub Copilot
description: Integrate Docker's capabilities with GitHub Copilot.

View File

@ -50,4 +50,4 @@ The following example assumes you have already installed and set up Claude Deskt
Take a screenshot of docs.docker.com and then invert the colors
```
Once you've given your consent to use the new tools, Claude spins up the Puppeteer MCP server inside a container, navigates to the target URL, captures and modify the page, and returns the screenshot.
Once you've given your consent to use the new tools, Claude spins up the Puppeteer MCP server inside a container, navigates to the target URL, captures and modify the page, and returns the screenshot.

View File

@ -32,6 +32,8 @@ Models are pulled from Docker Hub the first time they're used and stored locally
## Enable Docker Model Runner
### Enable DMR in Docker Desktop
1. Navigate to the **Features in development** tab in settings.
2. Under the **Experimental features** tab, select **Access experimental features**.
3. Select **Apply and restart**.
@ -42,6 +44,15 @@ Models are pulled from Docker Hub the first time they're used and stored locally
You can now use the `docker model` command in the CLI and view and interact with your local models in the **Models** tab in the Docker Desktop Dashboard.
### Enable DMR in Docker Engine
1. Ensure you have installed [Docker Engine](/engine/install/).
2. DMR is available as a package. To install it, run:
```console
apt install docker-model-plugin
```
## Available commands
### Model runner status

View File

@ -18,11 +18,11 @@ intro:
quickstart:
- title: Testcontainers for Go
description: A Go package that makes it simple to create and clean up container-based dependencies for automated integration/smoke tests.
icon: /assets/icons/go.svg
icon: /icons/go.svg
link: https://golang.testcontainers.org/quickstart/
- title: Testcontainers for Java
description: A Java library that supports JUnit tests, providing lightweight, throwaway instances of anything that can run in a Docker container.
icon: /assets/icons/java.svg
icon: /icons/java.svg
link: https://java.testcontainers.org/
---

View File

@ -46,8 +46,8 @@ build:
disableTags: true
# Ensure that CSS/assets changes trigger a dev server rebuild
cachebusters:
- source: assets/watching/hugo_stats\.json
target: styles\.css
- source: assets/notwatching/hugo_stats\.json
target: css
- source: (postcss|tailwind)\.config\.js
target: css
- source: assets/.*\.js
@ -278,8 +278,9 @@ module:
- source: assets
target: assets
# Mount hugo_stats.json to the assets dir to trigger cachebust
- source: hugo_stats.json
target: assets/watching/hugo_stats.json
- disableWatch: true
source: hugo_stats.json
target: assets/notwatching/hugo_stats.json
# Mount the icon files to assets so we can access them with resources.Get
- source: node_modules/@material-symbols/svg-400/rounded
target: assets/icons

View File

@ -5,10 +5,8 @@
"!mt-0",
"--mount",
"--tmpfs",
"-mb-3",
"-mr-8",
"-mt-0.5",
"-mt-4",
"-mt-8",
"-top-16",
"-v",
@ -133,126 +131,143 @@
"Without-systemd",
"[display:none]",
"absolute",
"admonition",
"admonition-content",
"admonition-danger",
"admonition-header",
"admonition-icon",
"admonition-note",
"admonition-tip",
"admonition-title",
"admonition-warning",
"aspect-video",
"bake-action",
"bg-amber-light",
"bg-amber-500",
"bg-background-light",
"bg-background-toc",
"bg-black/50",
"bg-black/70",
"bg-blue-light",
"bg-blue-light-400",
"bg-blue-light-500",
"bg-cover",
"bg-blue",
"bg-blue-400",
"bg-blue-500",
"bg-gradient-to-br",
"bg-gradient-to-r",
"bg-gradient-to-t",
"bg-gray-light-100",
"bg-gray-light-200",
"bg-gray-light-400",
"bg-gray-light-700",
"bg-green-light",
"bg-green-light-400",
"bg-opacity-75",
"bg-gray-00",
"bg-gray-100",
"bg-gray-200",
"bg-gray-400",
"bg-gray-50",
"bg-gray-700",
"bg-green-400",
"bg-green-500",
"bg-navbar-bg",
"bg-pattern-blue",
"bg-pattern-purple",
"bg-pattern-verde",
"bg-red-light",
"bg-red-500",
"bg-transparent",
"bg-violet-light",
"bg-violet-500",
"bg-white",
"bg-white/10",
"block",
"border",
"border-0",
"border-amber-light",
"border-b",
"border-b-4",
"border-blue-light",
"border-blue-light-500",
"border-blue",
"border-divider-light",
"border-gray-light-100",
"border-gray-light-200",
"border-gray-light-400",
"border-green-light",
"border-green-light-400",
"border-gray-200",
"border-gray-300",
"border-gray-400",
"border-gray-600",
"border-green-400",
"border-l-2",
"border-l-4",
"border-l-magenta-light",
"border-red-light",
"border-transparent",
"border-violet-light",
"border-white",
"bottom-0",
"build-push-action",
"card",
"card-content",
"card-description",
"card-header",
"card-icon",
"card-img",
"card-link",
"card-title",
"chroma",
"cls-1",
"cls-2",
"col-start-2",
"containerd-image-store",
"cursor-pointer",
"dark:bg-amber-dark",
"dark:bg-amber-300",
"dark:bg-background-dark",
"dark:bg-blue-dark",
"dark:bg-blue-dark-400",
"dark:bg-gray-dark-100",
"dark:bg-gray-dark-200",
"dark:bg-gray-dark-300",
"dark:bg-gray-dark-400",
"dark:bg-green-dark",
"dark:bg-background-toc",
"dark:bg-blue",
"dark:bg-blue-300",
"dark:bg-blue-400",
"dark:bg-blue-500",
"dark:bg-blue-800",
"dark:bg-gray-300",
"dark:bg-gray-400",
"dark:bg-gray-500",
"dark:bg-gray-800",
"dark:bg-gray-900",
"dark:bg-gray-950",
"dark:bg-green-300",
"dark:bg-green-700",
"dark:bg-green-dark-400",
"dark:bg-opacity-75",
"dark:bg-red-dark",
"dark:bg-violet-dark",
"dark:bg-navbar-bg-dark",
"dark:bg-red-300",
"dark:bg-violet-300",
"dark:bg-violet-400",
"dark:block",
"dark:border-amber-dark",
"dark:border-b-blue-dark-600",
"dark:border-blue-dark",
"dark:border-b-blue-600",
"dark:border-divider-dark",
"dark:border-gray-dark-200",
"dark:border-gray-dark-400",
"dark:border-green-dark",
"dark:border-green-dark-400",
"dark:border-gray-100",
"dark:border-gray-400",
"dark:border-gray-50",
"dark:border-gray-700",
"dark:border-green-400",
"dark:border-l-magenta-dark",
"dark:border-red-dark",
"dark:border-violet-dark",
"dark:fill-blue-dark",
"dark:focus:ring-blue-dark",
"dark:from-background-dark",
"dark:from-blue-dark-200",
"dark:from-blue-dark-400",
"dark:from-gray-dark-100",
"dark:fill-blue-300",
"dark:focus:ring-3-blue-dark",
"dark:from-blue-300",
"dark:from-blue-600",
"dark:hidden",
"dark:hover:bg-blue-dark",
"dark:hover:bg-blue-dark-500",
"dark:hover:bg-gray-dark-200",
"dark:hover:bg-gray-dark-400",
"dark:hover:bg-gray-dark-500",
"dark:hover:text-blue-dark",
"dark:hover:bg-blue-400",
"dark:hover:bg-blue-500",
"dark:hover:bg-blue-700",
"dark:hover:bg-gray-500",
"dark:hover:bg-gray-800",
"dark:hover:bg-gray-900",
"dark:hover:text-blue",
"dark:prose-invert",
"dark:ring-blue-dark-400",
"dark:ring-gray-dark-400",
"dark:ring-3-blue-dark-400",
"dark:ring-3-gray-dark-400",
"dark:syntax-dark",
"dark:text-amber-dark",
"dark:text-blue-dark",
"dark:text-blue",
"dark:text-blue-700",
"dark:text-divider-dark",
"dark:text-gray-dark",
"dark:text-gray-dark-300",
"dark:text-gray-dark-500",
"dark:text-gray-dark-600",
"dark:text-gray-dark-700",
"dark:text-gray-dark-800",
"dark:text-green-dark",
"dark:text-gray",
"dark:text-gray-100",
"dark:text-gray-200",
"dark:text-gray-300",
"dark:text-gray-400",
"dark:text-gray-500",
"dark:text-gray-900",
"dark:text-magenta-dark",
"dark:text-red-dark",
"dark:text-violet-dark",
"dark:text-white",
"dark:to-background-dark",
"dark:to-blue-dark-100",
"dark:to-magenta-dark-400",
"dark:to-blue-400",
"dark:to-blue-500",
"docker/bake-action",
"docker/build-push-action",
"download-links",
"download-links-subcontainer",
"drop-shadow",
"drop-shadow-sm",
"duration-300",
"fill-blue-light",
"fill-blue",
"fixed",
"flex",
"flex-1",
@ -260,21 +275,19 @@
"flex-col",
"flex-col-reverse",
"flex-grow",
"flex-grow-0",
"flex-none",
"flex-shrink",
"flex-wrap",
"focus:ring-blue-light",
"focus:ring-3-blue-light",
"font-bold",
"font-medium",
"font-semibold",
"footnote-backref",
"footnote-ref",
"footnotes",
"from-20%",
"from-background-light",
"from-blue-light-400",
"from-blue-light-600",
"from-blue-400",
"from-blue-600",
"gap-0",
"gap-1",
"gap-10",
"gap-12",
@ -282,7 +295,6 @@
"gap-20",
"gap-3",
"gap-4",
"gap-6",
"gap-8",
"goat",
"grid",
@ -305,20 +317,23 @@
"hidden",
"hidden'",
"highlight",
"hover:bg-blue-light-400",
"hover:bg-gray-light-100",
"hover:bg-gray-light-200",
"hover:bg-gray-light-300",
"hover:bg-blue",
"hover:bg-blue-400",
"hover:bg-blue-500",
"hover:bg-gray-100",
"hover:bg-gray-200",
"hover:bg-gray-300",
"hover:bg-gray-50",
"hover:bg-white/20",
"hover:border-gray-light-200",
"hover:border-white/20",
"hover:dark:bg-gray-dark-200",
"hover:dark:bg-gray-dark-300",
"hover:dark:border-gray-dark",
"hover:dark:text-blue-dark",
"hover:drop-shadow-lg",
"hover:dark:bg-blue-500",
"hover:dark:bg-gray-300",
"hover:dark:bg-gray-700",
"hover:dark:bg-gray-800",
"hover:dark:text-blue-400",
"hover:dark:text-blue-700",
"hover:opacity-90",
"hover:text-blue-light",
"hover:text-blue",
"hover:text-white",
"hover:underline",
"icon-lg",
@ -364,13 +379,14 @@
"max-w-56",
"max-w-[1920px]",
"max-w-[840px]",
"max-w-fit",
"max-w-full",
"max-w-none",
"max-w-xl",
"mb-1",
"mb-2",
"mb-3",
"mb-4",
"mb-6",
"mb-8",
"md-dropdown",
"md:block",
@ -404,9 +420,10 @@
"mt-[2px]",
"mx-auto",
"my-0",
"my-1",
"my-4",
"my-6",
"navbar-font",
"navbar-group-font-title",
"no-underline",
"no-wrap",
"not-prose",
@ -416,7 +433,7 @@
"origin-bottom-right",
"origin-top-right",
"ot-sdk-show-settings",
"outline-none",
"outline-hidden",
"overflow-clip",
"overflow-hidden",
"overflow-x-auto",
@ -447,6 +464,7 @@
"pt-10",
"pt-2",
"pt-4",
"pt-5",
"px-1",
"px-2",
"px-4",
@ -460,20 +478,22 @@
"right-0",
"right-3",
"right-8",
"ring-2",
"ring-[1.5px]",
"ring-blue-light-400",
"ring-gray-light-200",
"ring-3-2",
"ring-3-[1.5px]",
"ring-3-blue-light-400",
"ring-3-gray-light-200",
"rotate-45",
"rounded",
"rounded-[6px]",
"rounded-b-lg",
"rounded-full",
"rounded-sm",
"rounded-sm-b-lg",
"scale-50",
"scale-75",
"scroll-mt-2",
"scroll-mt-20",
"scroll-mt-36",
"section-card",
"section-card-text",
"section-card-title",
"select-none",
"self-center",
"self-start",
@ -490,38 +510,34 @@
"space-y-2",
"space-y-4",
"sticky",
"sub-button",
"summary-bar",
"svg",
"svg-container",
"syntax-light",
"systemd-networkd",
"text-2xl",
"text-amber-light",
"text-base",
"text-black",
"text-blue",
"text-blue-light",
"text-divider-light",
"text-gray-light",
"text-gray-light-200",
"text-gray-light-300",
"text-gray-light-500",
"text-gray-light-600",
"text-gray-light-800",
"text-green-light",
"text-gray",
"text-gray-100",
"text-gray-200",
"text-gray-400",
"text-gray-600",
"text-gray-800",
"text-left",
"text-lg",
"text-magenta-light",
"text-red-light",
"text-sm",
"text-violet-light",
"text-white",
"text-xl",
"text-xs",
"to-30%",
"to-50%",
"to-75%",
"to-blue-light",
"to-magenta-light-400",
"to-transparent",
"to-white",
"to-blue-200",
"to-blue-500",
"toc",
"top-0",
"top-16",
@ -533,12 +549,10 @@
"transition-transform",
"truncate",
"underline-offset-2",
"uppercase",
"w-2",
"w-56",
"w-8",
"w-[1200px]",
"w-[32px]",
"w-fit",
"w-full",
"w-screen",

View File

@ -1,41 +1,42 @@
{{- $icons := dict
"caution" "dangerous"
"important" "report"
"note" "info"
"tip" "lightbulb"
"warning" "warning"
"caution" "warning.svg"
"important" "important.svg"
"note" "info.svg"
"tip" "lightbulb.svg"
"warning" "warning.svg"
}}
{{- $borders := dict
"caution" "border-red-light dark:border-red-dark"
"important" "border-violet-light dark:border-violet-dark"
"note" "border-blue-light dark:border-blue-dark"
"tip" "border-green-light dark:border-green-dark"
"warning" "border-amber-light dark:border-amber-dark"
}}
{{- $textColors := dict
"caution" "text-red-light dark:text-red-dark"
"important" "text-violet-light dark:text-violet-dark"
"note" "text-blue-light dark:text-blue-dark"
"tip" "text-green-light dark:text-green-dark"
"warning" "text-amber-light dark:text-amber-dark"
{{- $admonitionClasses := dict
"caution" "admonition admonition-danger"
"important" "admonition admonition-note"
"note" "admonition admonition-note"
"tip" "admonition admonition-tip"
"warning" "admonition admonition-warning"
}}
{{- $type := cond (index $icons .AlertType) .AlertType "note" }}
{{- $iconFile := index $icons $type }}
{{- $partial := printf "admonitions/icons/%s" $iconFile }}
{{ if eq .Type "alert" }}
<blockquote
{{ with .Attributes.id }}id="{{ . }}"{{ end }}
class="px-4 border-l-4 {{ index $borders .AlertType }}">
<p class="flex gap-2 items-center {{ index $textColors .AlertType }}">
<span class="icon-svg pb-1">{{ $i := index $icons .AlertType }}
{{ partialCached "icon.html" $i $i }}
class="{{ index $admonitionClasses .AlertType }} admonition not-prose">
<div class="admonition-header">
<span class="admonition-icon">
{{- partialCached $partial . }}
</span>
<strong>{{ i18n .AlertType }}</strong>
</p>
{{ .Text | safeHTML }}
<span class="admonition-title">
{{ printf "%s%s" (upper (substr $.AlertType 0 1)) (substr $.AlertType 1) }}
</span>
</div>
<div class="admonition-content">
{{ .Text | safeHTML }}
</div>
</blockquote>
{{ else }}
<blockquote
{{ with .Attributes.id }}id="{{ . }}"{{ end }}
class="px-4 border-l-4 text-gray-light dark:text-gray-dark">
{{ .Text | safeHTML }}
class="admonition not-prose">
{{ .Text | safeHTML }}
</blockquote>
{{ end }}

View File

@ -1,38 +1,65 @@
<div data-pagefind-ignore class="scroll-mt-20" x-data x-ref="root">
<div data-pagefind-ignore class="scroll-mt-2" x-data x-ref="root">
{{ with .Attributes.title }}
<div class="text-sm -mb-3 text-gray-light dark:text-gray-dark">{{ . }}</div>
<div class="mb-3 text-sm text-gray-100 dark:bg-gray-900 dark:text-gray-900">
{{ . }}
</div>
{{ end }}
<div class="group relative">
<button x-data="{ code: '{{encoding.Base64Encode .Inner}}', copying: false }"
class="absolute right-3 top-3 z-10 text-gray-light-300 dark:text-gray-dark-600" title="copy" @click="window.navigator.clipboard.writeText(atob(code).replaceAll(/^[\$>]\s+/gm, ''));
<!-- copy button -->
<button
x-data="{ code: '{{ encoding.Base64Encode .Inner }}', copying: false }"
class="absolute top-3 right-3 z-10 text-gray-200 dark:text-gray-500"
title="copy"
@click="window.navigator.clipboard.writeText(atob(code).replaceAll(/^[\$>]\s+/gm, ''));
copying = true;
setTimeout(() => copying = false, 2000);">
<span :class="{ 'group-hover:block' : !copying }" class="icon-svg hidden">{{ partialCached "icon" "content_copy" "content_copy" }}</span>
<span :class="{ 'group-hover:block' : copying }" class="icon-svg hidden">{{ partialCached "icon" "check_circle" "check_circle" }}</span>
setTimeout(() => copying = false, 2000);"
>
<span :class="{ 'group-hover:block' : !copying }" class="icon-svg hidden"
>{{ partialCached "icon" "content_copy" "content_copy" }}</span
>
<span :class="{ 'group-hover:block' : copying }" class="icon-svg hidden"
>{{ partialCached "icon" "check_circle" "check_circle" }}</span
>
</button>
{{ $lang := .Type | default "text" }} {{ $result := transform.Highlight .Inner
$lang .Options }}
<div class="syntax-light dark:syntax-dark">
{{ $lang := .Type | default "text" }}
{{ $result := transform.Highlight .Inner
$lang .Options
}}
<div class="syntax-light dark:syntax-dark not-prose">
{{ with .Attributes.collapse }}
<div x-data="{ collapse: true }" class="relative overflow-clip"
x-init="$watch('collapse', value => $refs.root.scrollIntoView({ behavior: 'smooth'}))">
<div x-show="collapse"
class="to-transparent absolute z-10 flex h-32 w-full flex-col-reverse items-center overflow-clip bg-gradient-to-t from-background-light to-75% bg-cover pb-4 dark:from-background-dark">
<button @click="collapse = false"
class="flex items-center rounded-full bg-blue-light px-2 text-sm text-white dark:bg-blue-dark-400">
<span>Show more</span>
<span class="icon-svg">{{ partialCached "icon" "arrow_drop_down" "arrow_drop_down" }}</span>
</button>
<div
x-data="{ collapse: true }"
class="relative overflow-clip"
x-init="$watch('collapse', value => $refs.root.scrollIntoView({ behavior: 'smooth'}))"
>
<div
x-show="collapse"
class="absolute z-10 flex h-32 w-full flex-col-reverse items-center overflow-clip pb-4"
>
<button
@click="collapse = false"
class="bg-blue flex items-center rounded-full px-2 text-sm text-white dark:bg-blue-400"
>
<span>Show more</span>
<span class="icon-svg"
>{{ partialCached "icon" "arrow_drop_down" "arrow_drop_down" }}</span
>
</button>
</div>
<div :class="{ 'h-32': collapse }">
{{ $result }}
<button
@click="collapse = true"
x-show="!collapse"
class="rounded-sm-b-lg bg-blue mx-auto mt-4 flex items-center px-2 text-sm text-white dark:bg-blue-800"
>
<span>Hide</span>
<span class="icon-svg"
>{{ partialCached "icon" "arrow_drop_up" "arrow_drop_up" }}</span
>
</button>
</div>
</div>
<div :class="{ 'h-32': collapse }">
{{ $result }}
<button @click="collapse = true" x-show="!collapse"
class="mx-auto -mt-4 flex items-center rounded-b-lg bg-blue-light px-2 text-sm text-white dark:bg-blue-dark-400">
<span>Hide</span>
<span class="icon-svg">{{ partialCached "icon" "arrow_drop_up" "arrow_drop_up" }}</span>
</button>
</div>
</div>
{{ else }}
{{ $result }}
{{ end }}

View File

@ -14,6 +14,7 @@
{{ $height := $params.Get "h" }}
{{ $border := $params.Has "border" }}
<figure
x-data="{ zoom: false }"
@click="zoom = ! zoom"
@ -23,28 +24,28 @@
loading="lazy"
src="{{ $src }}"
alt="{{ .Text }}"
{{ with $width }} width="{{ . }}" {{ end }}
{{ with $height }} height="{{ . }}" {{ end }}
class="rounded mx-auto{{ with $border }} border border-divider-light dark:border-divider-dark{{end}}"
{{ with $width }}width="{{ . }}"{{ end }}
{{ with $height }}height="{{ . }}"{{ end }}
class="mx-auto{{ with $border }}
border border-divider-light dark:border-divider-dark
{{ end }} rounded-sm"
/>
{{ with .Title }}
<figcaption class="text-gray-light dark:text-gray-dark">{{ . }}</figcaption>
<figcaption class="text-gray-200 dark:text-gray-500">{{ . }}</figcaption>
{{ end }}
<template x-teleport="body">
<div
x-show="zoom"
@click="zoom = false"
x-transition.opacity.duration.250ms
class="fixed z-20 inset-0 flex items-center justify-center bg-black/70 p-6"
class="fixed inset-0 z-20 flex items-center justify-center bg-black/70 p-6"
>
<button
class="text-white fixed z-30 top-6 right-8 icon-svg"
>
<button class="icon-svg fixed top-6 right-8 z-30 text-white">
{{ partialCached "icon" "close" "close" }}
</button>
<img
loading="lazy"
class="rounded max-w-full max-h-full"
class="max-h-full max-w-full rounded-sm"
src="{{ $src }}"
alt="{{ .Text }}"
/>

View File

@ -4,12 +4,14 @@
{{- if $v }}
{{- printf " %s=%q" $k $v | safeHTMLAttr }}
{{- end }}
{{- end }}>
<thead class="bg-gray-light-100 dark:bg-gray-dark-200">
{{- end }}
>
<thead class="bg-gray-100 dark:bg-gray-800">
{{- range .THead }}
<tr>
{{- range . }}
<th class="p-2"
<th
class="p-2"
{{- with .Alignment }}
{{- printf " style=%q" (printf "text-align: %s" .) | safeHTMLAttr }}
{{- end -}}
@ -24,7 +26,8 @@
{{- range .TBody }}
<tr>
{{- range . }}
<td class="p-2"
<td
class="p-2"
{{- with .Alignment }}
{{- printf " style=%q" (printf "text-align: %s" .) | safeHTMLAttr }}
{{- end -}}

View File

@ -1,16 +1,19 @@
<!doctype html>
<html lang="en">
<head>
{{ partial "head.html" . }}
</head>
<head>
{{ partial "head.html" . }}
</head>
<body
class="flex flex-col items-center bg-gradient-to-r from-background-light from-20% to-white to-30% text-base dark:from-gray-dark-100 dark:to-background-dark dark:text-white">
{{ partial "header.html" . }}
<main class="relative flex w-full max-w-[1920px]">
<!-- Sidebar -->
<div style="scroll-behavior: smooth;" x-data x-init="$nextTick(() => {
<body
class="dark:bg-navbar-bg-dark bg-navbar-bg flex flex-col items-center text-base text-black dark:text-white"
>
{{ partial "header.html" . }}
<main class="relative flex w-full max-w-[1920px]">
<!-- Sidebar -->
<div
style="scroll-behavior: smooth;"
x-data
x-init="$nextTick(() => {
const container = $el; // The div with overflow
const item = document.getElementById('sidebar-current-page')
if (item) {
@ -26,39 +29,51 @@
}
}
})"
class="md:h-[calc(100vh-64px)] fixed md:sticky top-0 md:top-16 z-40 hidden h-screen flex-none overflow-y-auto overflow-x-hidden bg-background-light dark:bg-gray-dark-100 w-full md:z-auto md:block md:w-[300px]"
:class="{ 'hidden': ! $store.showSidebar }">
<!-- Gray backdrop on small screens -->
<div class="fixed bg-black/50 md:hidden z-30" x-show="$store.showSidebar" @click="openSidebar = false"
x-transition.opacity></div>
<div class="z-50 w-full bg-background-light p-4 dark:bg-gray-dark-100 md:block md:w-[300px]">
<!-- Collapse button for small screens -->
<button class="my-4 md:hidden" @click="$store.showSidebar = false">
<span class="icon-svg">{{ partialCached "icon" "arrow_left_alt" "arrow_left_alt" }}</span>
Back
</button>
<!-- Actual Sidebar Content -->
{{ block "left" . }}
{{ partial "sidebar/mainnav.html" . }}
{{ partial "sidebar/sections.html" . }}
class="bg-background-toc dark:bg-background-toc fixed top-0 z-40 hidden h-screen w-full flex-none overflow-x-hidden overflow-y-auto md:sticky md:top-16 md:z-auto md:block md:h-[calc(100vh-64px)] md:w-[300px]"
:class="{ 'hidden': ! $store.showSidebar }"
>
<!-- Gray backdrop on small screens -->
<div
class="fixed bg-black/50 md:hidden"
x-show="$store.showSidebar"
@click="openSidebar = false"
x-transition.opacity
></div>
<div
class="bg-background-toc dark:bg-background-toc z-50 w-full p-4 md:block md:w-[300px]"
>
<!-- Collapse button for small screens -->
<button class="my-4 md:hidden" @click="$store.showSidebar = false">
<span class="icon-svg"
>{{ partialCached "icon" "arrow_left_alt" "arrow_left_alt" }}</span
>
Back
</button>
<!-- Actual Sidebar Content -->
{{ block "left" . }}
{{ partial "sidebar/mainnav.html" . }}
{{ partial "sidebar/sections.html" . }}
{{ end }}
</div>
</div>
<!-- Main content -->
<div
{{ if ne .Params.sitemap false }}data-pagefind-body{{- end }}
class="dark:bg-background-dark w-full min-w-0 bg-white p-8"
>
{{ block "main" . }}
{{ end }}
</div>
</div>
</main>
<!-- Main content -->
<div {{ if ne .Params.sitemap false }}data-pagefind-body{{- end }}
class="w-full min-w-0 bg-white p-8 dark:bg-background-dark">
{{ block "main" . }}
{{ end }}
</div>
</main>
<footer class="w-full z-10 relative">{{ partialCached "footer.html" . }}</footer>
{{/* Load the YouTube player if the page embeds a YouTube video */}}
{{ with .Store.Get "youtube" }}
{{ partial "youtube-script.html" . }}
{{ end }}
</body>
<footer class="relative z-10 w-full">
{{ partialCached "footer.html" . }}
</footer>
{{/* Load the YouTube player if the page embeds a YouTube video */}}
{{ with .Store.Get "youtube" }}
{{ partial "youtube-script.html" . }}
{{ end }}
</body>
</html>

View File

@ -10,7 +10,7 @@
<div class="flex w-full">
<article class="prose min-w-0 flex-[2_2_0%] max-w-4xl dark:prose-invert">
{{ partial "breadcrumbs.html" . }}
<h1 class="scroll-mt-36">{{ .Title }}</h1>
<h1>{{ .Title }}</h1>
<div class="overflow-x-auto">
<table>
<tbody>
@ -100,7 +100,7 @@ can be removed entirely in a future release.
{{ $.Store.Add "headings" $heading }}
<div class="overflow-x-auto">
<table>
<thead class="bg-gray-light-100 dark:bg-gray-dark-200">
<thead class="bg-gray-100 dark:bg-gray-800">
<tr>
<th class="p-2">Option</th>
<th class="p-2">Default</th>

View File

@ -3,25 +3,34 @@
{{ end }}
{{ define "main" }}
<article class="prose max-w-none dark:prose-invert">
<article class="prose dark:prose-invert max-w-none">
<h1 class="py-4">{{ .Title }}</h1>
{{ .Content }}
<div class="not-prose">
<div class="flex flex-col lg:flex-row justify-between gap-8">
<input type="search" id="search-page-input"
class="min-w-0 ring-[1.5px] ring-gray-light-200 dark:ring-gray-dark-400 w-full max-w-xl rounded px-4 py-2 outline-none bg-white dark:bg-background-dark focus:ring-blue-light dark:focus:ring-blue-dark"
placeholder="Search…" tabindex="0" />
<div class="flex min-w-fit flex-col flex-grow items-center">
<div class="flex flex-col justify-between gap-8 lg:flex-row">
<input
type="search"
id="search-page-input"
class="ring-3-gray-light-200 dark:ring-3-gray-dark-400 dark:bg-background-dark focus:ring-3-blue-light dark:focus:ring-3-blue-dark ring-3-[1.5px] w-full max-w-xl min-w-0 rounded-sm bg-white px-4 py-2 outline-hidden"
placeholder="Search…"
tabindex="0"
/>
<div class="flex min-w-fit flex-grow flex-col items-center">
<p>Not finding what you're looking for?</p>
<button
class="px-2 py-1 font-semibold rounded open-kapa-widget flex w-fit gap-2 items-center hover:bg-gray-light-200 dark:hover:bg-gray-dark-200">
class="open-kapa-widget flex w-fit items-center gap-2 rounded-sm px-2 py-1 font-semibold hover:bg-gray-200 dark:hover:bg-gray-800"
>
<span>Try Ask AI</span>
<img height="24px" width="24px" src="{{ (resources.Get "images/ai-stars.svg").Permalink }}"
alt="AI sparkles!" />
<img
height="24px"
width="24px"
src="{{ (resources.Get "images/ai-stars.svg").Permalink }}"
alt="AI sparkles!"
/>
</button>
</div>
</div>
<hr class="border-divider-light dark:border-divider-dark">
<hr class="border-divider-light dark:border-divider-dark" />
<div id="search-page-results">
<!-- results -->
</div>
@ -124,14 +133,14 @@
}
// Generate the search results HTML
let resultsHTML = `<div class="text-gray-light dark:text-gray-dark p-2">${resultsLength} results</div>`;
let resultsHTML = `<div class="text-gray-200 dark:text-gray-500 p-2">${resultsLength} results</div>`;
// Map results to HTML
resultsHTML += results
.map((item) => {
return `<div class="p-4">
<div class="flex flex-col">
<span class="text-gray-light dark:texty-gray-dark text-sm">${item.meta.breadcrumbs}</span>
<span class="text-gray-200 dark:texty-gray-dark text-sm">${item.meta.breadcrumbs}</span>
<a class="link" href="${item.url}" data-query="${query}" data-index="${item.index}">${item.meta.title}</a>
<p class="text-black dark:text-white overflow-hidden">…${item.excerpt}…</p>
</div>
@ -140,7 +149,7 @@
.join("");
// If the results length is greater than 10, display links to show more results
if (resultsLength > 10) {
resultsHTML += `<hr class="border-divider-light dark:border-divider-dark">`
resultsHTML += `<hr class="border-divider-light dark:border-divider-dark">`;
resultsHTML += `<ul class="flex flex-wrap gap-1 pt-4 pb-8 justify-center text-sm">`;
for (let i = 1; i <= resultsLength / 10; i++) {
if (i == currentPage) {
@ -148,8 +157,8 @@
<a href="/search/?q=${query}&page=${i}" class="block h-6 w-6 rounded-sm bg-blue-light dark:bg-blue-dark">${i}</a>
</li>`;
} else {
resultsHTML += `<li class="text-center text-gray-light dark:text-gray-dark">
<a href="/search/?q=${query}&page=${i}" class="block h-6 w-6 rounded-sm bg-gray-light-200 dark:bg-gray-dark-200">${i}</a>
resultsHTML += `<li class="text-center text-gray-200 dark:text-gray-500">
<a href="/search/?q=${query}&page=${i}" class="block h-6 w-6 rounded-sm bg-gray-200 dark:bg-gray-800">${i}</a>
</li>`;
}
}

View File

@ -1,7 +1,7 @@
{{ define "main" }}
<article class="prose min-w-0 flex-[2_2_0%] max-w-4xl dark:prose-invert">
<article class="prose dark:prose-invert max-w-4xl min-w-0 flex-[2_2_0%]">
{{ partial "breadcrumbs.html" . }}
<h1 data-pagefind-weight="10" class="scroll-mt-36">{{ .Title }}</h1>
<h1 data-pagefind-weight="10">{{ .Title }}</h1>
<div class="block lg:hidden">
{{ partialCached "pagemeta.html" . . }}
<hr />

View File

@ -1,8 +1,11 @@
{{ define "left" }}
{{- partial "sidebar/mainnav.html" . }}
<div class="p-4 flex flex-col gap-2 text-sm">
<p>Filter guides by tag or programming language.<p>
<div class="space-y-4" x-data="{
{{- partial "sidebar/mainnav.html" . }}
<div class="navbar-font flex flex-col gap-2 p-4 text-sm">
<p>Filter guides by tag or programming language.</p>
<p></p>
<div
class="space-y-4"
x-data="{
filters: { tags: [], languages: [] },
toggleFilter(grp, tag) {
this.filters[grp].includes(tag)
@ -20,7 +23,7 @@
this.$dispatch('guide-filter', { filters: this.filters });
},
init() {
const url = new URL(window.location.href);
const tags = url.searchParams.get('tags')
@ -32,42 +35,59 @@
this.filters['languages'] = langs.split('~');
}
}
}" @guide-filter.window="filters = $event.detail.filters;">
<div class="pl-2"><strong>Tags</strong></div>
<fieldset class="flex flex-col gap-2">
{{- range $name, $taxonomy := where site.Taxonomies.tags ".Page.Type" "guides" }}
{{- $id := anchorize (fmt.Printf "tag-%s" $name) }}
<div class="pl-2 flex gap-2">
<input value="{{ $name }}" type="checkbox" id="{{ $id }}" @change="toggleFilter('tags', '{{ $name }}')"
:checked="filters['tags'].includes('{{ $name }}')">
<label class="select-none" for="{{ $id }}">{{ .Page.LinkTitle }}</label>
</div>
{{ end }}
</fieldset>
<div class="pl-2"><strong>Languages</strong></div>
<fieldset class="pl-2 flex flex-wrap gap-2">
{{- range $name, $taxonomy := where site.Taxonomies.languages ".Page.Type" "guides" }}
{{- $id := anchorize (fmt.Printf "lang-%s" $name) }}
<button
class="px-2 py-1 rounded-full flex gap-1 bg-white dark:bg-gray-dark-300 border border-divider-light dark:border-divider-dark"
:class="{ 'ring-2 ring-blue-light-400 dark:ring-blue-dark-400': filters['languages'].includes('{{ $name }}') }"
@click="toggleFilter('languages', '{{ $name }}')">
<img height="18" width="18" title="{{ .Page.LinkTitle }}" src="{{ .Page.Params.icon }}">
<span>{{ .Page.LinkTitle }}</span>
</button>
{{ end }}
</fieldset>
}"
@guide-filter.window="filters = $event.detail.filters;"
>
<div class="pl-2"><strong>Tags</strong></div>
<fieldset class="flex flex-col gap-2">
{{- range $name, $taxonomy := where site.Taxonomies.tags ".Page.Type" "guides" }}
{{- $id := anchorize (fmt.Printf "tag-%s" $name) }}
<div class="flex gap-2 pl-2">
<input
value="{{ $name }}"
type="checkbox"
id="{{ $id }}"
@change="toggleFilter('tags', '{{ $name }}')"
:checked="filters['tags'].includes('{{ $name }}')"
/>
<label class="select-none" for="{{ $id }}"
>{{ .Page.LinkTitle }}</label
>
</div>
{{ end }}
</fieldset>
<div class="pl-2"><strong>Languages</strong></div>
<fieldset class="flex flex-wrap gap-2 pl-2">
{{- range $name, $taxonomy := where site.Taxonomies.languages ".Page.Type" "guides" }}
{{- $id := anchorize (fmt.Printf "lang-%s" $name) }}
<button
class="border-divider-light dark:border-divider-dark flex gap-1 rounded-full border bg-white px-2 py-1 dark:bg-gray-800"
:class="{ 'ring-3-2 ring-3-blue-light-400 dark:ring-3-blue-dark-400': filters['languages'].includes('{{ $name }}') }"
@click="toggleFilter('languages', '{{ $name }}')"
>
<img
height="18"
width="18"
title="{{ .Page.LinkTitle }}"
src="{{ .Page.Params.icon }}"
/>
<span>{{ .Page.LinkTitle }}</span>
</button>
{{ end }}
</fieldset>
</div>
</div>
</div>
{{ end }}
{{ define "main" }}
<div class="flex gap-8 w-full">
<article class="prose min-w-0 max-w-none dark:prose-invert">
{{- partial "breadcrumbs.html" . }}
<h1 data-pagefind-weight="10" class="scroll-mt-36">{{ .Title }}</h1>
{{ .Content }}
<div class="not-prose min-h-screen" x-data="{
<div class="flex w-full gap-8">
<article class="prose dark:prose-invert max-w-none min-w-0">
{{- partial "breadcrumbs.html" . }}
<h1 data-pagefind-weight="10" class="scroll-mt-36">{{ .Title }}</h1>
{{ .Content }}
<div
class="not-prose min-h-screen"
x-data="{
filters: { tags: [], languages: [] },
hidden: [],
total: {{ len .Pages }},
@ -123,99 +143,127 @@
}
this.updateVisible();
}
}" x-cloak
@guide-filter.window="filters = $event.detail.filters; updateVisible(); $nextTick(() => { window.scrollTo({ top: 0 }) })">
<div x-show="noFilters()">
<h2>Featured guides</h2>
<div class="not-prose py-4 grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-8">
{{- $featured := where .Pages "Params.featured" true }}
{{- with $featured }}
{{- range . }}
<div class="flex flex-col h-full">
<a class="hover:underline" href="{{ .Permalink }}">
{{- $img := resources.Get (.Params.image | default "/images/thumbnail.webp") }}
{{- $img = $img.Process "resize 600x" }}
<img class="h-48 w-full object-cover rounded shadow" src="{{ $img.Permalink }}">
<p class="text-xl leading-snug my-4">{{ .Title }}</p>
</a>
<p class="flex-grow text-sm">{{ .Summary }}</p>
<div class="mt-4">
{{ template "guide-metadata" . }}
}"
x-cloak
@guide-filter.window="filters = $event.detail.filters; updateVisible(); $nextTick(() => { window.scrollTo({ top: 0 }) })"
>
<div x-show="noFilters()">
<h2>Featured guides</h2>
<div
class="not-prose grid grid-cols-1 gap-8 py-4 lg:grid-cols-2 xl:grid-cols-3"
>
{{- $featured := where .Pages "Params.featured" true }}
{{- with $featured }}
{{- range . }}
<div class="flex h-full flex-col">
<a class="hover:underline" href="{{ .Permalink }}">
{{- $img := resources.Get (.Params.image | default "/images/thumbnail.webp") }}
{{- $img = $img.Process "resize 600x" }}
<img
class="h-48 w-full rounded-sm object-cover shadow"
src="{{ $img.Permalink }}"
/>
<p class="my-4 text-xl leading-snug">{{ .Title }}</p>
</a>
<p class="flex-grow text-sm">{{ .Summary }}</p>
<div class="mt-4">
{{ template "guide-metadata" . }}
</div>
</div>
{{- end }}
{{- end }}
</div>
<hr class="text-divider-light dark:text-divider-dark" />
</div>
<h2 x-show="noFilters()" id="all-guides" class="scroll-mt-36">
All guides
</h2>
<div x-show="!noFilters()" class="flex flex-col gap-2 pb-8">
<div class="flex items-center gap-2">
<span class="icon-svg icon-sm mb-1"
>{{ partialCached "icon" "filter_alt" "filter_alt" }}</span
>
<p>
Filtered results: showing
<span x-text="total - hidden.length"></span> out of
<span x-text="total"></span> guides.
</p>
</div>
<div class="flex items-center gap-2 pl-4">
{{- range $name, $taxonomy := site.Taxonomies.tags }}
<div x-show="filters.tags.includes('{{ $name }}')">
{{ template "termchip" $taxonomy.Page.LinkTitle }}
</div>
{{- end }}
{{- range $name, $taxonomy := site.Taxonomies.languages }}
<div
x-show="filters.languages.includes('{{ $name }}')"
class="border-divider-light dark:border-divider-dark inline-flex items-center gap-1 rounded-full border bg-gray-100 px-2 text-sm text-gray-200 select-none dark:bg-gray-800 dark:text-gray-300"
>
<img
class="py-1"
height="18"
width="18"
title="{{ .Page.LinkTitle }}"
src="{{ .Page.Params.icon }}"
/>
<span>{{ .Page.LinkTitle }}</span>
</div>
{{- end }}
</div>
</div>
<div x-ref="guide-container">
{{- range .Pages }}
<div
id="guide-{{ math.Counter }}"
data-languages="{{ jsonify (.Params.languages | default slice) }}"
data-tags="{{ jsonify (.Params.tags | default slice) }}"
x-show="isVisible($el);"
class="border-divider-light dark:border-divider-dark flex flex-col justify-between border-b p-4 hover:bg-gray-100 hover:dark:bg-gray-800"
>
<div class="flex flex-col justify-between xl:flex-row">
<a
href="{{ .Permalink }}"
class="mb-2 truncate text-lg hover:underline xl:mb-0"
>{{ .Title }}</a
>
{{ template "guide-metadata" . }}
</div>
</div>
{{- end }}
</div>
<hr class="text-divider-light dark:text-divider-dark">
</div>
<h2 x-show="noFilters()" id="all-guides" class="scroll-mt-36">All guides</h2>
<div x-show="!noFilters()" class="pb-8 flex flex-col gap-2">
<div class="flex gap-2 items-center">
<span class="mb-1 icon-svg icon-sm">{{ partialCached "icon" "filter_alt" "filter_alt" }}</span>
<p>Filtered results: showing <span x-text="total - hidden.length"></span> out of <span x-text="total"></span> guides.</p>
</div>
<div class="pl-4 flex gap-2 items-center">
{{- range $name, $taxonomy := site.Taxonomies.tags }}
<div x-show="filters.tags.includes('{{$name}}')">{{ template "termchip" $taxonomy.Page.LinkTitle }}</div>
{{- end }}
{{- range $name, $taxonomy := site.Taxonomies.languages }}
<div x-show="filters.languages.includes('{{$name}}')"
class="text-sm inline-flex gap-1 items-center rounded-full border
border-divider-light dark:border-divider-dark bg-gray-light-100
px-2 text-gray-light-800 dark:bg-gray-dark-200
dark:text-gray-dark-800 select-none">
<img class="py-1" height="18" width="18" title="{{ .Page.LinkTitle }}" src="{{ .Page.Params.icon }}">
<span>{{ .Page.LinkTitle }}</span>
</div>
{{- end }}
</div>
</div>
<div x-ref="guide-container">
{{- range .Pages }}
<div
id="guide-{{ math.Counter }}"
data-languages='{{ jsonify (.Params.languages | default slice) }}'
data-tags='{{ jsonify (.Params.tags | default slice) }}'
x-show="isVisible($el);"
class="flex flex-col justify-between p-4 border-b border-divider-light
hover:bg-gray-light-100 hover:dark:bg-gray-dark-200
dark:border-divider-dark">
<div class="flex flex-col xl:flex-row justify-between">
<a href="{{ .Permalink }}" class="text-lg hover:underline mb-2 xl:mb-0 truncate">{{ .Title }}</a>
{{ template "guide-metadata" . }}
</div>
</div>
{{- end }}
</div>
</div>
</article>
</div>
</article>
</div>
{{ end }}
{{- define "guide-metadata" }}
<div class="text-sm flex gap-8 items-center justify-between text-gray-light dark:text-gray-dark">
<div class="flex flex-wrap md:flex-nowrap gap-2">
{{- $langs := .GetTerms "languages" }}
{{ partial "languages" $langs }}
{{- $tags := .GetTerms "tags" }}
{{- range $tags }}
{{ template "termchip" .Page.LinkTitle }}
<div
class="flex items-center justify-between gap-8 text-sm text-gray-200 dark:text-gray-300"
>
<div class="flex flex-wrap gap-2 md:flex-nowrap">
{{- $langs := .GetTerms "languages" }}
{{ partial "languages" $langs }}
{{- $tags := .GetTerms "tags" }}
{{- range $tags }}
{{ template "termchip" .Page.LinkTitle }}
{{- end }}
</div>
{{- with .Params.time }}
<div class="flex flex-shrink gap-2 whitespace-nowrap">
<span class="icon-svg"
>{{ partialCached "icon" "schedule" "schedule" }}</span
>
<span>{{ . }}</span>
</div>
{{- end }}
</div>
{{- with .Params.time }}
<div class="flex whitespace-nowrap flex-shrink gap-2">
<span class="icon-svg">{{ partialCached "icon" "schedule" "schedule" }}</span>
<span>{{ . }}</span>
</div>
{{- end }}
</div>
{{- end }}
{{- define "termchip" }}
<span class="whitespace-nowrap inline-flex text-sm min-w-0 items-center rounded-full
border border-divider-light dark:border-divider-dark
bg-gray-light-100 px-2 text-gray-light-800 dark:bg-gray-dark-200
dark:text-gray-dark-800 select-none">
<span
class="border-divider-light dark:border-divider-dark inline-flex min-w-0 items-center rounded-full border bg-gray-100 px-2 text-sm whitespace-nowrap text-gray-200 select-none dark:bg-gray-800 dark:text-gray-300"
>
<span class="icon-svg icon-sm pb-0.5">
{{ partialCached "icon" "tag" "tag" }}
</span>

View File

@ -6,13 +6,17 @@
{{ define "main" }}
{{ partial "content-default.html" . }}
<div class="prose dark:prose-invert max-w-4xl">
<div class="md-dropdown ml-auto hidden lg:block">
{{ partial "md-dropdown.html" . }}
</div>
{{ if (.Store.Get "multipage") }}
{{- with .PrevInSection }}
<div class="col-start-2 not-prose my-4">
<a href="{{ .Permalink }}"
class="cursor-pointer py-2 px-4 rounded bg-blue-light-500
dark:bg-blue-dark-400 hover:bg-blue-light-400
dark:hover:bg-blue-dark-500 text-white">{{ .Title }} »</a>
<div class="not-prose col-start-2 my-4">
<a
href="{{ .Permalink }}"
class="cursor-pointer rounded-sm bg-blue-500 px-4 py-2 text-white hover:bg-blue-400 dark:bg-blue-800 dark:hover:bg-blue-700"
>{{ .Title }} »</a
>
</div>
{{- end }}
{{- end }}

View File

@ -1,262 +1,322 @@
<!doctype html>
<html lang="en">
<head>
{{ partial "head.html" . }}
</head>
<head>
{{ partial "head.html" . }}
</head>
<body class="flex h-max flex-col bg-background-light text-base dark:bg-background-dark dark:text-white">
<div class="absolute -z-10 w-full">
<svg class="dark:hidden" viewBox="0 0 1616 797" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1066.69 797L0 136.789V0H1616V488.038L1066.69 797Z" fill="#EFEFF2" />
</svg>
<svg class="hidden dark:block" viewBox="0 0 1616 797" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1066.69 797L0 136.789V0H1616V488.038L1066.69 797Z" fill="#080B0E" fill-opacity="0.3" />
</svg>
</div>
{{ partial "header.html" . }}
<main class="flex min-h-screen w-full flex-col items-stretch self-center">
<div class="flex xl:w-[1200px] flex-col items-stretch gap-20 self-center py-20 w-full px-4">
<div class="bg-pattern-blue relative overflow-hidden rounded drop-shadow">
<div class="flex h-full flex-col items-start justify-between gap-4 p-8">
<div class="flex items-center gap-6">
<span class="icon-svg text-violet-light dark:text-violet-dark">
{{ partial "icon" "play_circle" }}</span>
<h1 class="text-2xl">Get Docker</h1>
</div>
<p>
Learn how to install Docker for Mac, Windows, or Linux and explore
our developer tools.
</p>
<a href="/get-started/get-docker/"
class="mt-20 flex cursor-pointer items-center gap-2 rounded bg-blue-light p-2 px-4 text-white transition duration-300 hover:bg-blue-light-400 dark:bg-blue-dark-400 dark:hover:bg-blue-dark">
<span class="icon-svg">{{ partial "icon" "download"}}</span>
Get Docker
</a>
</div>
<div class="absolute bottom-0 right-0 origin-bottom-right scale-50 lg:scale-100">
<img class="dark:hidden" alt="Low-fi desktop app" src="/assets/images/app-wf-light-1.svg" />
<img class="hidden dark:block" alt="Low-fi desktop app" src="/assets/images/app-wf-dark-1.svg" />
</div>
</div>
<div>
<div class="grid grid-cols-1 gap-4 lg:grid-cols-4">
<div>
<a class="h-full" href="/get-started/">
<div
class="flex h-full flex-col gap-2 rounded border border-gray-light-100 bg-white p-4 drop-shadow-sm hover:border-gray-light-200 hover:drop-shadow-lg dark:border-gray-dark-400 dark:bg-gray-dark-200 hover:dark:border-gray-dark">
<div class="flex items-center gap-4">
<span class="icon-svg text-violet-light dark:text-violet-dark">
{{ partial "icon" "rocket" }}
</span>
<div>
<div class="text-xl leading-snug text-gray-light-800 dark:text-white">
Get started
</div>
</div>
</div>
<div class="leading-snug text-gray-light-500 dark:text-gray-dark-700">
Learn Docker basics and the benefits of containerization.
</div>
</div>
</a>
</div>
<div>
<a class="h-full" href="/guides/">
<div
class="flex h-full flex-col gap-2 rounded border border-gray-light-100 bg-white p-4 drop-shadow-sm hover:border-gray-light-200 hover:drop-shadow-lg dark:border-gray-dark-400 dark:bg-gray-dark-200 hover:dark:border-gray-dark">
<div class="flex items-center gap-4">
<span class="icon-svg text-violet-light dark:text-violet-dark">
{{ partial "icon" "developer_guide" }}
</span>
<div>
<div class="text-xl leading-snug text-gray-light-800 dark:text-white">
Guides
</div>
</div>
</div>
<div class="leading-snug text-gray-light-500 dark:text-gray-dark-700">
Learn how Docker can optimize your development workflows.
</div>
</div>
</a>
</div>
<div>
<a class="h-full" href="/manuals/">
<div
class="flex h-full flex-col gap-2 rounded border border-gray-light-100 bg-white p-4 drop-shadow-sm hover:border-gray-light-200 hover:drop-shadow-lg dark:border-gray-dark-400 dark:bg-gray-dark-200 hover:dark:border-gray-dark">
<div class="flex items-center gap-4">
<span class="icon-svg text-violet-light dark:text-violet-dark">
{{ partial "icon" "description" }}
</span>
<div>
<div class="text-xl leading-snug text-gray-light-800 dark:text-white">
Manuals
</div>
</div>
</div>
<div class="leading-snug text-gray-light-500 dark:text-gray-dark-700">
Learn how to install, set up, configure, and use Docker
products.
</div>
</div>
</a>
</div>
<div>
<a class="h-full" href="/reference/">
<div
class="flex h-full flex-col gap-2 rounded border border-gray-light-100 bg-white p-4 drop-shadow-sm hover:border-gray-light-200 hover:drop-shadow-lg dark:border-gray-dark-400 dark:bg-gray-dark-200 hover:dark:border-gray-dark">
<div class="flex items-center gap-4">
<span class="icon-svg text-violet-light dark:text-violet-dark">
{{ partial "icon" "terminal" }}
</span>
<div>
<div class="text-xl leading-snug text-gray-light-800 dark:text-white">
Reference
</div>
</div>
</div>
<div class="leading-snug text-gray-light-500 dark:text-gray-dark-700">
Browse the CLI and API documentation.
</div>
</div>
</a>
</div>
</div>
</div>
<div class="z-10 grid grid-cols-1 gap-20 lg:grid-cols-2">
<div class="bg-pattern-verde relative rounded p-6 drop-shadow">
<div class="flex h-full flex-col items-start justify-between gap-12">
<div class="flex flex-col gap-4">
<h2 class="font-medium">Gen AI catalog {{ partial
"components/badge.html" (dict "color" "blue" "content" "New")
}}</h2>
<p class="text-xl">
Integrate AI solutions into your apps with minimal effort
</p>
<body
class="flex h-max flex-col bg-gray-50 text-base dark:bg-gray-950 dark:text-white"
>
<div class="absolute -z-10 w-full">
<svg
class="dark:hidden"
viewBox="0 0 1616 797"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1066.69 797L0 136.789V0H1616V488.038L1066.69 797Z"
fill="#EFEFF2"
/>
</svg>
<svg
class="hidden dark:block"
viewBox="0 0 1616 797"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1066.69 797L0 136.789V0H1616V488.038L1066.69 797Z"
fill="#080B0E"
fill-opacity="0.3"
/>
</svg>
</div>
{{ partial "header.html" . }}
<main class="flex min-h-screen w-full flex-col items-stretch self-center">
<div
class="flex w-full flex-col items-stretch gap-20 self-center px-4 py-20 xl:w-[1200px]"
>
<div
class="bg-pattern-blue relative overflow-hidden rounded-sm drop-shadow"
>
<div
class="flex h-full flex-col items-start justify-between gap-4 p-8"
>
<div class="flex items-center gap-2">
<span class="icon-svg text-blue dark:text-blue">
{{ partial "icon" "play_circle" }}</span
>
<h1 class="text-2xl">Get Docker</h1>
</div>
<div class="flex flex-col xl:flex-row gap-4 items-start">
<a href="https://hub.docker.com/catalogs/gen-ai"
class="flex cursor-pointer items-center gap-2 rounded bg-blue-light p-2 px-4 text-white transition duration-300 hover:bg-blue-light-400 dark:bg-blue-dark-400 dark:hover:bg-blue-dark">
Explore on Docker Hub
<p>
Learn how to install Docker for Mac, Windows, or Linux and explore
our developer tools.
</p>
<a
href="/get-started/get-docker/"
class="bg-blue mt-20 flex cursor-pointer items-center gap-2 rounded-sm p-2 px-4 text-white transition duration-300 hover:bg-blue-500 dark:bg-blue-500 dark:hover:bg-blue-400"
>
<span class="icon-svg">{{ partial "icon" "download" }}</span>
Get Docker
</a>
</div>
<div
class="absolute right-0 bottom-0 origin-bottom-right scale-50 lg:scale-100"
>
<img
class="dark:hidden"
alt="Low-fi desktop app"
src="/assets/images/app-wf-light-1.svg"
/>
<img
class="hidden dark:block"
alt="Low-fi desktop app"
src="/assets/images/app-wf-dark-1.svg"
/>
</div>
</div>
<div>
<div class="grid grid-cols-1 gap-4 lg:grid-cols-4">
<div>
<a class="h-full" href="/get-started/">
<div class="section-card">
<div class="flex items-center gap-4">
<span class="icon-svg text-blue dark:text-blue">
{{ partial "icon" "rocket" }}
</span>
<div>
<div class="section-card-title">Get started</div>
</div>
</div>
<div class="section-card-text">
Learn Docker basics and the benefits of containerization.
</div>
</div>
</a>
<a href="/docker-hub/image-library/catalogs/"
class="flex-grow-0 flex cursor-pointer items-center gap-2 rounded bg-blue-light p-2 px-4 text-white transition duration-300 hover:bg-blue-light-400 dark:bg-blue-dark-400 dark:hover:bg-blue-dark">
Read the docs
</div>
<div>
<a class="h-full" href="/guides/">
<div class="section-card">
<div class="flex items-center gap-4">
<span class="icon-svg text-blue dark:text-blue">
{{ partial "icon" "developer_guide" }}
</span>
<div>
<div class="section-card-title">Guides</div>
</div>
</div>
<div class="section-card-text">
Learn how Docker can optimize your development workflows.
</div>
</div>
</a>
</div>
<div>
<a class="h-full" href="/manuals/">
<div class="section-card">
<div class="flex items-center gap-4">
<span class="icon-svg text-blue dark:text-blue">
{{ partial "icon" "description" }}
</span>
<div>
<div class="section-card-title">Manuals</div>
</div>
</div>
<div class="section-card-text">
Learn how to install, set up, configure, and use Docker
products.
</div>
</div>
</a>
</div>
<div>
<a class="h-full" href="/reference/">
<div class="section-card">
<div class="flex items-center gap-4">
<span class="icon-svg text-blue dark:text-blue">
{{ partial "icon" "terminal" }}
</span>
<div>
<div class="section-card-title">Reference</div>
</div>
</div>
<div class="section-card-text">
Browse the CLI and API documentation.
</div>
</div>
</a>
</div>
</div>
<div class="absolute bottom-0 right-0 origin-bottom-right scale-75 md:scale-100">
<img class="dark:hidden" alt="Low-fi desktop app" src="/assets/images/app-wf-light-2.svg" />
<img class="hidden dark:block" alt="Low-fi desktop app" src="/assets/images/app-wf-dark-2.svg" />
</div>
</div>
<div class="rounded-[6px] bg-gradient-to-br from-blue-light-400 to-magenta-light-400 dark:from-blue-dark-400 dark:to-magenta-dark-400 p-[2px] drop-shadow">
<div class="bg-pattern-purple rounded p-6">
<div class="flex flex-col gap-12">
<div class="z-10 grid grid-cols-1 gap-20 lg:grid-cols-2">
<div class="bg-pattern-verde relative rounded-sm p-6 drop-shadow">
<div
class="flex h-full flex-col items-start justify-between gap-12"
>
<div class="flex flex-col gap-4">
<h2 class="font-medium">
Docker Model Runner
{{ partial "components/badge.html" (dict "color" "blue" "content" "Beta") }}
Gen AI catalog
{{ partial
"components/badge.html" (dict "color" "blue" "content" "New")
}}
</h2>
<p class="text-xl">
Run, test, and serve AI models locally in seconds — no setup, no hassle.
</p>
<p>
Whether youre experimenting with the latest LLMs or deploying to production,
Docker Model Runner brings the performance and control you need, without the friction.
Integrate AI solutions into your apps with minimal effort
</p>
</div>
<div class="flex flex-col xl:flex-row gap-4 items-start">
<a href="/desktop/features/model-runner/"
class="max-w-fit cursor-pointer rounded bg-blue-light px-4 py-2 text-white transition duration-300 hover:bg-blue-light-400 dark:bg-blue-dark-400 dark:hover:bg-blue-dark">Read the docs</a>
<div class="flex flex-col items-start gap-4 xl:flex-row">
<a
href="https://hub.docker.com/catalogs/gen-ai"
class="bg-blue dark:bg-blue rounded-sm p-2 px-4 text-white transition duration-300 hover:bg-blue-500 dark:hover:bg-blue-500"
>
Explore on Docker Hub
</a>
<a
href="/docker-hub/image-library/catalogs/"
class="bg-blue dark:bg-blue rounded-sm p-2 px-4 text-white transition duration-300 hover:bg-blue-500 dark:hover:bg-blue-500"
>
Read the docs
</a>
</div>
</div>
</div>
</div>
</div>
<div>
<h2 class="mb-4 text-xl">Browse by section</h2>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
{{ range .Params.grid }}
<div>
<div
class="flex h-full flex-col gap-2 rounded border border-gray-light-100 bg-white p-4 drop-shadow-sm dark:border-gray-dark-400 dark:bg-gray-dark-200">
<div class="flex items-center gap-4">
<span class="icon-svg text-gray-light dark:text-gray-dark">{{ partial "icon" .icon }}</span>
<div>
<div class="text-xl">{{ .title }}</div>
class="absolute right-0 bottom-0 origin-bottom-right scale-75 md:scale-100"
>
<img
class="dark:hidden"
alt="Low-fi desktop app"
src="/assets/images/app-wf-light-2.svg"
/>
<img
class="hidden dark:block"
alt="Low-fi desktop app"
src="/assets/images/app-wf-dark-2.svg"
/>
</div>
</div>
<div
class="rounded-sm bg-gradient-to-br from-blue-400 to-blue-200 p-[2px] drop-shadow dark:from-blue-300 dark:to-blue-400"
>
<div class="bg-pattern-purple rounded-sm p-6">
<div class="flex flex-col gap-12">
<div class="flex flex-col gap-4">
<h2 class="font-medium">
Docker Model Runner
{{ partial "components/badge.html" (dict "color" "blue" "content" "Beta") }}
</h2>
<p class="text-xl">
Run, test, and serve AI models locally in seconds — no
setup, no hassle.
</p>
<p>
Whether youre experimenting with the latest LLMs or
deploying to production, Docker Model Runner brings the
performance and control you need, without the friction.
</p>
</div>
<div class="flex flex-col items-start gap-4 xl:flex-row">
<a
href="/desktop/features/model-runner/"
class="bg-blue dark:bg-blue rounded-sm p-2 px-4 text-white transition duration-300 hover:bg-blue-500 dark:hover:bg-blue-500"
>Read the docs</a
>
</div>
</div>
<div class="flex h-full flex-col justify-between gap-4">
<p>{{ .description | markdownify }}</p>
<nav class="flex flex-col gap-2">
{{ range .links }}
<div>
<span class="icon-svg text-gray-light dark:text-gray-dark">{{ partial "icon" "arrow_right" }}</span>
<a class="link" href="{{ .url }}">{{ .text }}</a>
</div>
{{ end }}
</nav>
</div>
</div>
</div>
{{ end }}
</div>
</div>
<div class="flex flex-col gap-4">
<h2 class="mb-4 text-xl">Browse by tag</h2>
<div class="flex flex-wrap gap-4">
{{ $tags := slice }}
{{- range site.Taxonomies.tags }}
{{ $tags = $tags | append .Page }}
{{ end }}
{{ partial "tags.html" $tags }}
</div>
</div>
</div>
<div
class="relative flex md:h-[334px] items-center justify-center overflow-hidden bg-gray-light-100 dark:bg-gray-dark-200 h-full py-8">
<div class="w-[1200px] px-4">
<div class="flex md:max-w-[66%] flex-col gap-8 max-w-full">
<h2 class="text-2xl">Community resources</h2>
<p>
Find fellow Docker enthusiasts, engage in insightful discussions,
share knowledge, and collaborate on projects. Our communities
offer a rich online experience for developers to create valuable
connections that challenge and inspire!
</p>
<div class="flex gap-4 flex-col md:flex-row">
<a href="https://forums.docker.com/"
class="cursor-pointer rounded bg-white px-4 py-2 text-blue-light hover:bg-gray-light-100 dark:bg-gray-dark-400 dark:text-white dark:hover:bg-gray-dark-500">
Visit Docker Forum
</a>
<a href="https://dockr.ly/comm-slack"
class="cursor-pointer rounded bg-white px-4 py-2 text-blue-light hover:bg-gray-light-100 dark:bg-gray-dark-400 dark:text-white dark:hover:bg-gray-dark-500">
Join Docker Slack
</a>
<a href="https://www.docker.com/community/captains/"
class="cursor-pointer rounded bg-white px-4 py-2 text-blue-light hover:bg-gray-light-100 dark:bg-gray-dark-400 dark:text-white dark:hover:bg-gray-dark-500">
Find your Docker Captain
</a>
<div>
<h2 class="mb-4 text-xl">Browse by section</h2>
<div
class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"
>
{{ range .Params.grid }}
<div>
<div class="section-card">
<div class="flex items-center gap-4">
<span class="icon-svg text-gray dark:text-gray"
>{{ partial "icon" .icon }}</span
>
<div>
<div class="section-card-title">{{ .title }}</div>
</div>
</div>
<div class="flex h-full flex-col justify-between gap-4">
<p>{{ .description | markdownify }}</p>
<nav class="flex flex-col gap-2">
{{ range .links }}
<div>
<span class="icon-svg text-gray dark:text-gray"
>{{ partial "icon" "arrow_right" }}</span
>
<a class="link" href="{{ .url }}">{{ .text }}</a>
</div>
{{ end }}
</nav>
</div>
</div>
</div>
{{ end }}
</div>
</div>
<div class="flex flex-col gap-4">
<h2 class="mb-4 text-xl">Browse by tag</h2>
<div class="flex flex-wrap gap-4">
{{ $tags := slice }}
{{- range site.Taxonomies.tags }}
{{ $tags = $tags | append .Page }}
{{ end }}
{{ partial "tags.html" $tags }}
</div>
</div>
</div>
<div class="absolute right-0 top-0 hidden md:block">
{{- (resources.Get "images/home-abstract-faint.svg").Content | safe.HTML -}}
</div>
</div>
</main>
<footer>{{ partialCached "footer.html" . }}</footer>
</body>
<div
class="relative flex h-full items-center justify-center overflow-hidden bg-gray-100 py-8 md:h-[334px] dark:bg-gray-900"
>
<div class="w-[1200px] px-4">
<div class="flex max-w-full flex-col gap-8 md:max-w-[66%]">
<h2 class="text-2xl">Community resources</h2>
<p>
Find fellow Docker enthusiasts, engage in insightful discussions,
share knowledge, and collaborate on projects. Our communities
offer a rich online experience for developers to create valuable
connections that challenge and inspire!
</p>
<div class="flex flex-col gap-4 md:flex-row">
<a
href="https://forums.docker.com/"
class="cursor-pointer rounded-sm bg-white px-4 py-2 hover:bg-gray-50 dark:bg-gray-400 dark:text-white dark:hover:bg-gray-500"
>
Visit Docker Forum
</a>
<a
href="https://dockr.ly/comm-slack"
class="cursor-pointer rounded-sm bg-white px-4 py-2 hover:bg-gray-50 dark:bg-gray-400 dark:text-white dark:hover:bg-gray-500"
>
Join Docker Slack
</a>
<a
href="https://www.docker.com/community/captains/"
class="cursor-pointer rounded-sm bg-white px-4 py-2 hover:bg-gray-50 dark:bg-gray-400 dark:text-white dark:hover:bg-gray-500"
>
Find your Docker Captain
</a>
</div>
</div>
</div>
<div class="absolute top-0 right-0 hidden md:block">
{{- (resources.Get "images/home-abstract-faint.svg").Content | safe.HTML -}}
</div>
</div>
</main>
<footer>{{ partialCached "footer.html" . }}</footer>
</body>
</html>

View File

@ -0,0 +1,8 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0_23_93" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="2" y="1" width="20" height="22">
<path d="M12 8.00008V12.0001M12 16.0001H12.01M3 7.94153V16.0586C3 16.4013 3 16.5726 3.05048 16.7254C3.09515 16.8606 3.16816 16.9847 3.26463 17.0893C3.37369 17.2077 3.52345 17.2909 3.82297 17.4573L11.223 21.5684C11.5066 21.726 11.6484 21.8047 11.7985 21.8356C11.9315 21.863 12.0685 21.863 12.2015 21.8356C12.3516 21.8047 12.4934 21.726 12.777 21.5684L20.177 17.4573C20.4766 17.2909 20.6263 17.2077 20.7354 17.0893C20.8318 16.9847 20.9049 16.8606 20.9495 16.7254C21 16.5726 21 16.4013 21 16.0586V7.94153C21 7.59889 21 7.42756 20.9495 7.27477C20.9049 7.13959 20.8318 7.01551 20.7354 6.91082C20.6263 6.79248 20.4766 6.70928 20.177 6.54288L12.777 2.43177C12.4934 2.27421 12.3516 2.19543 12.2015 2.16454C12.0685 2.13721 11.9315 2.13721 11.7985 2.16454C11.6484 2.19543 11.5066 2.27421 11.223 2.43177L3.82297 6.54288C3.52345 6.70928 3.37369 6.79248 3.26463 6.91082C3.16816 7.01551 3.09515 7.13959 3.05048 7.27477C3 7.42756 3 7.59889 3 7.94153Z" stroke="#6C7E9D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</mask>
<g mask="url(#mask0_23_93)">
<rect width="24" height="24" fill="black" fill-opacity="0.8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,8 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0_23_89" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="2" y="2" width="20" height="20">
<path d="M12 8V12M12 16H12.01M7.8 21H16.2C17.8802 21 18.7202 21 19.362 20.673C19.9265 20.3854 20.3854 19.9265 20.673 19.362C21 18.7202 21 17.8802 21 16.2V7.8C21 6.11984 21 5.27976 20.673 4.63803C20.3854 4.07354 19.9265 3.6146 19.362 3.32698C18.7202 3 17.8802 3 16.2 3H7.8C6.11984 3 5.27976 3 4.63803 3.32698C4.07354 3.6146 3.6146 4.07354 3.32698 4.63803C3 5.27976 3 6.11984 3 7.8V16.2C3 17.8802 3 18.7202 3.32698 19.362C3.6146 19.9265 4.07354 20.3854 4.63803 20.673C5.27976 21 6.11984 21 7.8 21Z" stroke="#6C7E9D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</mask>
<g mask="url(#mask0_23_89)">
<rect width="24" height="24" fill="currentColor" fill-opacity="0.8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 905 B

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 16V12M12 8H12.01M22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 335 B

View File

@ -0,0 +1,8 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0_5432_1749" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="4" y="1" width="17" height="22">
<path d="M9.93896 22H14.939M10.439 10H14.439M12.439 10L12.439 16M15.439 15.3264C17.8039 14.2029 19.439 11.7924 19.439 9C19.439 5.13401 16.305 2 12.439 2C8.57297 2 5.43896 5.13401 5.43896 9C5.43896 11.7924 7.07402 14.2029 9.43896 15.3264V16C9.43896 16.9319 9.43896 17.3978 9.59121 17.7654C9.79419 18.2554 10.1835 18.6448 10.6736 18.8478C11.0411 19 11.5071 19 12.439 19C13.3708 19 13.8368 19 14.2043 18.8478C14.6944 18.6448 15.0837 18.2554 15.2867 17.7654C15.439 17.3978 15.439 16.9319 15.439 16V15.3264Z" stroke="#6C7E9D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</mask>
<g mask="url(#mask0_5432_1749)">
<rect width="24" height="24" fill="currentColor" fill-opacity="0.8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 920 B

View File

@ -0,0 +1,8 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0_5432_2018" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="2" width="24" height="21">
<path d="M11.9998 9.99999V14M11.9998 18H12.0098M10.6151 4.89171L2.39019 19.0983C1.93398 19.8863 1.70588 20.2803 1.73959 20.6037C1.769 20.8857 1.91677 21.142 2.14613 21.3088C2.40908 21.5 2.86435 21.5 3.77487 21.5H20.2246C21.1352 21.5 21.5904 21.5 21.8534 21.3088C22.0827 21.142 22.2305 20.8857 22.2599 20.6037C22.2936 20.2803 22.0655 19.8863 21.6093 19.0983L13.3844 4.89171C12.9299 4.10654 12.7026 3.71396 12.4061 3.58211C12.1474 3.4671 11.8521 3.4671 11.5935 3.58211C11.2969 3.71396 11.0696 4.10655 10.6151 4.89171Z" stroke="#6C7E9D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</mask>
<g mask="url(#mask0_5432_2018)">
<rect width="24" height="24" fill="currentColor" fill-opacity="0.8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 933 B

View File

@ -1,12 +1,19 @@
<nav id="breadcrumbs"
<nav
id="breadcrumbs"
{{- $breadcrumbTitles := slice }}
data-pagefind-ignore class="gap-4 flex items-center text-gray-light dark:text-gray-dark min-w-0">
data-pagefind-ignore
class="mb-4 flex min-w-0 items-center gap-2 text-gray-400 dark:text-gray-300"
>
{{ range .Ancestors.Reverse }}
{{ $breadcrumbTitles = $breadcrumbTitles | append .LinkTitle }}
<a href="{{ .Permalink }}" class="link truncate">{{ markdownify .LinkTitle }}</a>
<a href="{{ .Permalink }}" class="link truncate"
>{{ markdownify .LinkTitle }}</a
>
<span>/</span>
{{- end }}
<span
data-pagefind-meta="breadcrumbs:{{ collections.Delimit $breadcrumbTitles " / " }}"
class="truncate">{{ markdownify .LinkTitle }}</span>
class="truncate"
>{{ markdownify .LinkTitle }}</span
>
</nav>

View File

@ -1,15 +1,24 @@
<div
id="{{ urls.Anchorize .title }}"
x-data="{ open: {{ .open | default false }} }" class="border border-gray-light-200 dark:border-gray-dark-200 bg-white dark:bg-gray-dark-100 py-2 my-6 rounded">
<button class="not-prose w-full py-2 px-4 flex justify-between" x-on:click="open = ! open">
<div class="{{ with .large }} text-xl {{ end }} flex items-center gap-2">
x-data="{ open: {{ .open | default false }} }"
class="my-6 rounded-sm border border-gray-200 bg-white py-2 dark:border-gray-700 dark:bg-gray-900"
>
<button
class="not-prose flex w-full justify-between px-4 py-2"
x-on:click="open = ! open"
>
<div class="{{ with .large }}text-xl{{ end }} flex items-center gap-2">
{{- with .icon }}
<span class="icon-svg -mt-1">{{ partialCached "icon" . . }}</span>
{{- end }}
{{ .title }}
</div>
<span :class="{ 'hidden' : !open }" class="icon-svg">{{ partialCached "icon" "arrow_drop_up" "arrow_drop_up" }}</span>
<span :class="{ 'hidden' : open }" class="icon-svg">{{ partialCached "icon" "arrow_drop_down" "arrow_drop_down" }}</span>
<span :class="{ 'hidden' : !open }" class="icon-svg"
>{{ partialCached "icon" "arrow_drop_up" "arrow_drop_up" }}</span
>
<span :class="{ 'hidden' : open }" class="icon-svg"
>{{ partialCached "icon" "arrow_drop_down" "arrow_drop_down" }}</span
>
</button>
<div x-show="open" x-collapse class="px-4">
{{ markdownify .body }}

View File

@ -1,17 +1,18 @@
{{- $colors := (dict
"amber" "bg-amber-light dark:bg-amber-dark"
"blue" "bg-blue-light dark:bg-blue-dark"
"green" "bg-green-light dark:bg-green-dark"
"red" "bg-red-light dark:bg-red-dark"
"violet" "bg-violet-light dark:bg-violet-dark"
"amber" "bg-amber-500 dark:bg-amber-400"
"blue" "bg-blue-500 dark:bg-blue-400"
"green" "bg-green-500 dark:bg-green-700"
"red" "bg-red-500 dark:bg-red-400"
"violet" "bg-violet-500 dark:bg-violet-400"
)
-}}
{{- if not (isset $colors .color) -}}
{{- errorf "[badge] wrong color name: '%s' - supported values: amber, blue, green, red, violet" .color -}}h
{{- errorf "[badge] wrong color name: '%s' - supported values: amber, blue, green, red, violet" .color -}}h
{{- end -}}
<span
class="not-prose px-1 rounded-sm {{ index $colors .color }} text-white text-xs"
class="not-prose {{ index $colors .color }} rounded-sm px-1 text-xs text-white"
>{{ .content }}</span
>

View File

@ -1,51 +1,31 @@
{{ if (and .image .icon) }}
{{ errorf "card: don't use both image and icon: %s" . }}
{{ end }}
<div class="not-prose overflow-x-hidden drop-shadow bg-white rounded
border border-gray-light-100 dark:bg-gray-dark-200 dark:border-gray-dark-400
{{ if .link }}hover:border-gray-light-200 hover:dark:border-gray-dark{{ end }}">
<div class="card">
{{ if .link }}
<a href="{{ .link }}">
<a href="{{ .link }}" class="card-link">
{{ end }}
{{ if .image }}
{{/* use the "tall image" layout */}}
<div class="flex gap-2 items-stretch">
<div class="basis-1/3">
<img class="h-full w-full object-cover" src="{{ .image }}" alt="">
</div>
<div class="basis-2/3 flex flex-col gap-2 p-4">
<div class="text-xl text-gray-light-800 leading-snug dark:text-white flex gap-2">
{{ markdownify .title }}
</div>
<div class="text-gray-light-500 leading-snug dark:text-gray-dark-700">
{{ .description | markdownify }}
</div>
</div>
</div>
{{ else }}
{{/* use the default layout */}}
<div class="flex flex-col gap-2 p-4">
<div class="flex gap-4 items-center">
{{ with .icon }}
{{ if strings.ContainsAny . "/." }}
{{/* image file */}}
<img class="w-[32px] invertible" src="{{ . }}" alt="">
{{ else }}
{{/* icon ligature */}}
<span class="icon-svg">{{ partial "icon" . }}</span>
{{ end }}
<div class="card-header">
{{ with .image }}
<img class="card-image" src="{{ . }}" alt="">
{{ end }}
{{ with .icon }}
<div class="card-icon">
{{ if (in . ".svg") }}
<span class="card-img svg">
{{ partial "utils/svg" . }}
</span>
{{ else if (in . "/") }}
<img class="card-img" src="{{ . }}" alt="">
{{ else }}
<span class="card-img svg">
{{ partial "icon" . }}
</span>
{{ end }}
<div>
<div class="text-xl text-gray-light-800 leading-snug dark:text-white flex items-center gap-2">
{{ markdownify .title }}
</div>
</div>
</div>
<div class="text-gray-light-600 leading-snug dark:text-gray-dark-700">
{{ .description | markdownify }}
</div>
{{ end }}
<h3 class="card-title">{{ markdownify .title }}</h3>
</div>
<div class="card-content">
<p class="card-description">{{ .description | markdownify }}</p>
</div>
{{ end }}
{{ if .link }}
</a>
{{ end }}

View File

@ -1,14 +1,16 @@
<div class="not-prose">
<div class="flex flex-col sm:flex-row gap-4 p-6 m-4 bg-gray-light-200 dark:bg-gray-dark-300">
<div class="flex-grow flex flex-col sm:items-center">
<div
class="m-4 flex flex-col gap-4 bg-gray-200 p-6 sm:flex-row dark:bg-gray-300"
>
<div class="flex flex-grow flex-col sm:items-center">
<span><strong>Skill level</strong></span>
<span>{{ .Params.skill }}</span>
</div>
<div class="flex-grow flex flex-col sm:items-center">
<div class="flex flex-grow flex-col sm:items-center">
<span><strong>Time to complete</strong></span>
<span>{{ .Params.time }}</span>
</div>
<div class="flex-grow flex flex-col sm:items-center">
<div class="flex flex-grow flex-col sm:items-center">
<span><strong>Prerequisites</strong></span>
<span>{{ .Params.prereq }}</span>
</div>

View File

@ -1,7 +1,7 @@
<a
href="https://hub.docker.com/support/contact"
class="flex items-center rounded bg-blue-light dark:bg-blue-dark text-white
py-2 px-4 z-50"
aria-label="Contact support">
class="hover:bg-blue bg-blue z-50 flex items-center rounded-sm px-4 py-2 text-white dark:bg-blue-400 hover:dark:bg-blue-500"
aria-label="Contact support"
>
<span>Contact support</span>
</a>
</a>

View File

@ -1,20 +1,19 @@
<div class="flex w-full gap-8">
<article class="prose min-w-0 max-w-4xl flex-[2_2_0%] dark:prose-invert">
<article class="prose dark:prose-invert max-w-4xl min-w-0 flex-[2_2_0%]">
{{ partial "breadcrumbs.html" . }}
<h1 data-pagefind-weight="10" class="flex scroll-mt-36 items-center">
<span>{{ .Title }}</span>
</h1>
<div class="flex items-start justify-between">
<h1 data-pagefind-weight="10">{{ .Title }}</h1>
<div class="md-dropdown ml-auto hidden lg:block">
{{ partial "md-dropdown.html" . }}
</div>
</div>
<div class="block lg:hidden">
{{ partialCached "pagemeta.html" . . }}
<hr />
</div>
{{ .Content }}
</article>
<div class="hidden lg:block ml-auto md-dropdown">
{{ partial "md-dropdown.html" . }}
</div>
<div class="-mr-8 -mt-8 hidden min-w-52 flex-1 lg:block">
<div class="-mt-8 -mr-8 hidden min-w-52 flex-1 lg:block">
{{ partial "aside.html" . }}
</div>
</div>

View File

@ -1,51 +1,72 @@
<div class="flex justify-center py-8 px-4 bg-gray-light-100 dark:bg-gray-dark-200 relative z-10">
<div
class="relative z-10 flex justify-center bg-gray-100 px-4 py-8 dark:bg-gray-900"
>
{{ partialCached "components/support-button.html" . }}
</div>
<div class="flex justify-center pt-10 pb-20 px-4 bg-gray-light-100 dark:bg-gray-dark-200">
<div class="flex justify-center bg-gray-100 px-4 pt-10 pb-20 dark:bg-gray-900">
<div class="flex w-full max-w-[840px] flex-col gap-10">
<div class="flex flex-col md:flex-row gap-4 items-center justify-evenly">
<a class="underline-offset-2 hover:underline" href="https://www.docker.com/">Product offerings</a>
<a class="underline-offset-2 hover:underline" href="https://www.docker.com/pricing/">Pricing</a>
<a class="underline-offset-2 hover:underline" href="https://www.docker.com/company/">About us</a>
<div class="flex flex-col items-center justify-evenly gap-4 md:flex-row">
<a
class="underline-offset-2 hover:underline"
href="https://www.docker.com/"
>Product offerings</a
>
<a
class="underline-offset-2 hover:underline"
href="https://www.docker.com/pricing/"
>Pricing</a
>
<a
class="underline-offset-2 hover:underline"
href="https://www.docker.com/company/"
>About us</a
>
{{- with .GetPage "/contribute" }}
<a class="underline-offset-2 hover:underline" href="{{ .Permalink }}">{{ .LinkTitle }}</a>
<a class="underline-offset-2 hover:underline" href="{{ .Permalink }}"
>{{ .LinkTitle }}</a
>
{{- end }}
<a href="{{ "llms.txt" | relURL }}">Read llms.txt</a>
</div>
<hr class="text-divider-light dark:text-divider-dark" />
<div class="grid lg:grid-cols-3 place-items-center gap-8 grid-cols-1">
<div class="grid grid-cols-1 place-items-center gap-8 lg:grid-cols-3">
<p class="text-sm">
Copyright © 2013-{{ time.Now.Year}} Docker Inc. All rights reserved.
Copyright © 2013-{{ time.Now.Year }} Docker Inc. All rights reserved.
</p>
<div class="flex gap-4">
<a
class="h-8 w-8 rounded-full fill-blue-light dark:fill-blue-dark"
class="fill-blue h-8 w-8 rounded-full dark:fill-blue-300"
title="X (Twitter)"
href="http://twitter.com/docker/">
href="http://twitter.com/docker/"
>
{{ (resources.Get "images/TwitterCircle.svg").Content | safe.HTML }}
</a>
<a
class="h-8 w-8 rounded-full fill-blue-light dark:fill-blue-dark"
class="fill-blue h-8 w-8 rounded-full dark:fill-blue-300"
title="LinkedIn"
href="https://www.linkedin.com/company/docker">
href="https://www.linkedin.com/company/docker"
>
{{ (resources.Get "images/LinkedinCircle.svg").Content | safe.HTML }}
</a>
<a
class="h-8 w-8 rounded-full fill-blue-light dark:fill-blue-dark"
class="fill-blue h-8 w-8 rounded-full dark:fill-blue-300"
title="Instagram"
href="https://www.instagram.com/dockerinc/">
href="https://www.instagram.com/dockerinc/"
>
{{ (resources.Get "images/InstagramCircle.svg").Content | safe.HTML }}
</a>
<a
class="h-8 w-8 rounded-full fill-blue-light dark:fill-blue-dark"
class="fill-blue h-8 w-8 rounded-full dark:fill-blue-300"
title="YouTube"
href="http://www.youtube.com/user/dockerrun">
href="http://www.youtube.com/user/dockerrun"
>
{{ (resources.Get "images/YoutubeCircle.svg").Content | safe.HTML }}
</a>
<a
class="h-8 w-8 rounded-full fill-blue-light dark:fill-blue-dark"
class="fill-blue h-8 w-8 rounded-full dark:fill-blue-300"
title="Facebook"
href="https://www.facebook.com/docker.run">
href="https://www.facebook.com/docker.run"
>
{{ (resources.Get "images/FacebookCircle.svg").Content | safe.HTML }}
</a>
</div>
@ -54,20 +75,23 @@
class="underline-offset-2 hover:underline"
title="Docker Terms of Service"
href="https://www.docker.com/legal/docker-terms-service"
>Terms of Service</a>
>Terms of Service</a
>
<a
class="underline-offset-2 hover:underline"
title="Docker Systems Status Page"
href="https://www.dockerstatus.com/"
>Status</a>
>Status</a
>
<a
class="underline-offset-2 hover:underline"
title="Docker Legal Terms"
href="https://www.docker.com/legal"
>Legal</a>
>Legal</a
>
</div>
</div>
<div class="flex justify-between items-center">
<div class="flex items-center justify-between">
<button type="button" id="ot-sdk-btn" class="ot-sdk-show-settings">
Cookies Settings
</button>
@ -76,9 +100,7 @@
<button
aria-label="Theme switch"
id="theme-switch"
class="rounded bg-blue-light px-4 py-1 text-white transition
hover:bg-blue-light-400 dark:bg-blue-dark-400
dark:hover:bg-blue-dark"
class="bg-blue rounded-sm px-4 py-1 text-white transition hover:bg-blue-400 dark:bg-blue-400 dark:hover:bg-blue-500"
x-data="{ theme: localStorage.getItem('theme-preference') }"
x-init="$watch('theme', value => {
localStorage.setItem('theme-preference', value);

View File

@ -4,20 +4,24 @@
- "Request changes": Links to a pre-filled issue form.
*/ -}}
{{ if hugo.IsProduction }}
{{ with .File }}
{{ if not (in .Filename "/_vendor/") }}
<p class="flex items-center gap-2">
<span class="icon-svg">{{ partialCached "icon" "edit" "edit" }}</span>
{{ with .File }}
{{ if not (in .Filename "/_vendor/") }}
<p class="flex items-center gap-1">
<span class="icon-svg icon-sm">
{{ partial "utils/svg.html" "theme/icons/edit.svg" }}
</span>
<a class="link" rel="noopener"
href="{{ site.Params.repo }}/edit/main/content/{{ .Path }}">{{- T "editPage" -}}
<span class="icon-svg icon-sm">
{{ partialCached "icon" "open_in_new" "open_in_new" }}
</span></a>
</p>
{{ end }}
{{ end }}
<p class="flex items-center gap-2">
<span class="icon-svg">{{ partialCached "icon" "check" "check" }}</span>
{{ end }}
{{ end }}
<p class="flex items-center gap-1">
<span class="icon-svg icon-sm">
{{ partial "utils/svg.html" "theme/icons/issue.svg" }}
</span>
<a class="link" rel="noopener"
href="{{ site.Params.repo }}/issues/new?template=doc_issue.yml&location={{ .Permalink }}&labels=status%2Ftriage">{{- T "requestChanges" -}}
<span class="icon-svg icon-sm">

View File

@ -1,7 +1,7 @@
{{/*- Multi-page guide: render a progress bar -*/}}
<div class="flex flex-col my-4 items-start text-sm">
{{/* - Multi-page guide: render a progress bar - */}}
<div class="my-4 flex flex-col items-start text-sm">
{{ $totalPages := len .CurrentSection.Pages }}
{{/*- initialize the page store
{{/* - initialize the page store
$stepper_seen controls the color of the item in the stepper
@ -13,42 +13,42 @@
default to true if kind = section
(make all entries gray)
-*/}}
-
*/}}
{{ page.Store.Set "stepper_seen" .IsSection }}
{{/*- Loop over the pages in this guide -*/}}
{{/* - Loop over the pages in this guide - */}}
{{ range $i, $e := .CurrentSection.Pages }}
{{ $isLast := eq (add $i 1) $totalPages }}
<div class="flex">
<div class="flex flex-col items-center">
{{/*- Render the page's index digit (1,2,3,4 etc) -*/}}
{{/* - Render the page's index digit (1,2,3,4 etc) - */}}
<a
href="{{ .Permalink }}"
class="{{ if (page.Store.Get "stepper_seen") }}
bg-gray-light-400 dark:bg-gray-dark-400
bg-gray-400 dark:bg-gray-500
{{ else if (eq . page) }}
{{ .Store.Set "stepper_seen" true }} bg-blue-light-400
dark:bg-blue-dark-400
{{ .Store.Set "stepper_seen" true }} bg-blue-400 dark:bg-blue-800
{{ else }}
bg-green-light-400 dark:bg-green-dark-400
bg-green-400 dark:bg-green-dark-400
{{ end }} flex h-8 w-8 items-center justify-center rounded-full text-white no-underline"
>
{{ add $i 1 }}
</a>
{{/*- Render the vertical border -*/}}
{{/* - Render the vertical border - */}}
{{ if not $isLast }}
<div
class="{{ if (page.Store.Get "stepper_seen") }}
border-gray-light-400 dark:border-gray-dark-400
border-gray-400 dark:border-gray-400
{{ else if (eq . page) }}
border-blue-light-400 dark:border-blue-dark-400
border-blue-400 dark:border-blue-400
{{ else }}
border-green-light-400 dark:border-green-dark-400
border-green-400 dark:border-green-400
{{ end }} h-6 border-l-2"
></div>
{{ end }}
</div>
{{/*- Render the page's title -*/}}
<div class="ml-2 flex self-start h-8 items-center">
{{/* - Render the page's title - */}}
<div class="ml-2 flex h-8 items-center self-start">
<a href="{{ .Permalink }}">
{{ .LinkTitle }}
</a>

View File

@ -1,6 +1,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
{{ partial "meta.html" . }}
{{ partial "utils/css.html" "-" }}
{{- if hugo.IsProduction -}}
<script
src="https://cdn.cookielaw.org/scripttemplates/otSDKStub.js"
@ -8,13 +9,14 @@
charset="UTF-8"
data-domain-script="{{ site.Params.analytics.onetrust }}"
></script>
<script type="text/javascript">function OptanonWrapper() {}</script>
<script type="text/javascript">
function OptanonWrapper() {}
</script>
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','{{ site.Params.analytics.google }}');</script>
<script>
})(window,document,'script','dataLayer','{{ site.Params.analytics.google }}');</script> <script>
(function(h,o,t,j,a,r){
h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
h._hjSettings={hjid:{{ site.Params.analytics.hotjar.prod | safeJS }},hjsv:6};
@ -50,30 +52,37 @@
</script>
{{ end }}
{{/* kapa.ai widget */}}
<script async src="https://widget.kapa.ai/kapa-widget.bundle.js"
data-button-hide="true"
data-font-family="Roboto Flex,sans-serif"
data-modal-disclaimer-bg-color="#e5f2fc"
data-modal-disclaimer-text-color="#086dd7"
data-modal-disclaimer="This is a custom LLM for answering questions about Docker. Answers are based on the contents of the documentation. Rate the answers to let us know what you think!"
data-kapa-branding-text="powered by [kapa.ai](https://www.kapa.ai) and Docker"
data-modal-header-bg-color="#1d63ed"
data-modal-image-height="25px"
data-modal-image-width="181px"
data-modal-title=""
data-modal-override-open-class="open-kapa-widget"
data-modal-ask-ai-input-placeholder="Ask me a question about Docker…"
data-modal-title-color="#fff"
data-project-color="#1d63ed"
data-project-logo="/assets/images/logo-icon-white.svg"
data-project-name="Docker"
data-user-analytics-fingerprint-enabled="true"
data-bot-protection-mechanism="hcaptcha"
data-website-id="{{ site.Params.kapa.id }}"
<script
async
src="https://widget.kapa.ai/kapa-widget.bundle.js"
data-button-hide="true"
data-font-family="Roboto Flex,sans-serif"
data-modal-disclaimer-bg-color="#e5f2fc"
data-modal-disclaimer-text-color="#086dd7"
data-modal-disclaimer="This is a custom LLM for answering questions about Docker. Answers are based on the contents of the documentation. Rate the answers to let us know what you think!"
data-kapa-branding-text="powered by [kapa.ai](https://www.kapa.ai) and Docker"
data-modal-header-bg-color="#1d63ed"
data-modal-image-height="25px"
data-modal-image-width="181px"
data-modal-title=""
data-modal-override-open-class="open-kapa-widget"
data-modal-ask-ai-input-placeholder="Ask me a question about Docker…"
data-modal-title-color="#fff"
data-project-color="#1d63ed"
data-project-logo="/assets/images/logo-icon-white.svg"
data-project-name="Docker"
data-user-analytics-fingerprint-enabled="true"
data-bot-protection-mechanism="hcaptcha"
data-website-id="{{ site.Params.kapa.id }}"
></script>
{{/* preload Roboto Flex as it's a critical font: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/preload */}}
<link href="/assets/fonts/RobotoFlex.woff2" rel="preload" as="font" type="font/woff2" crossorigin />
{{ partialCached "utils/css.html" "-" }}
<link
href="/assets/fonts/RobotoFlex.woff2"
rel="preload"
as="font"
type="font/woff2"
crossorigin
/>
{{ $theme := resources.Get "js/theme.js" | js.Build (dict "minify" true) }}
<script>{{ $theme.Content | safeJS }}</script>
{{ $js := resources.Match "js/src/**.js"

View File

@ -1,11 +1,19 @@
<header class="w-full sticky top-0 z-20 h-16 px-6 text-white bg-gradient-to-r from-blue-light-600 to-blue-light dark:from-blue-dark-200 to-50% dark:to-blue-dark-100">
<div class="max-w-[1920px] mx-auto flex lg:gap-8 gap-2 h-full items-center justify-between">
<div class="flex h-full items-center lg:gap-8 gap-2">
<header
class="sticky top-0 z-20 h-16 w-full bg-gradient-to-r from-blue-600 to-blue-500 to-50% px-6 text-white dark:from-blue-600 dark:to-blue-500"
>
<div
class="mx-auto flex h-full max-w-[1920px] items-center justify-between gap-2 lg:gap-8"
>
<div class="flex h-full items-center gap-2 lg:gap-8">
{{- if not .IsHome }}
<button x-data @click="$store.showSidebar = true"
class="icon-svg block px-4 md:hidden h-full" aria-label="Menu">
{{ partialCached "icon" "menu" "menu" }}
</button>
<button
x-data
@click="$store.showSidebar = true"
class="icon-svg block h-full px-4 md:hidden"
aria-label="Menu"
>
{{ partialCached "icon" "menu" "menu" }}
</button>
{{- end }}
<div>
{{/* main logo */}}
@ -21,24 +29,32 @@
<nav class="mt-1 hidden md:block">
<ul class="flex text-sm md:text-base lg:gap-4">
{{ range site.Menus.main }}
<li
{{- if or (eq page.Permalink .Page.Permalink) (page.IsDescendant .Page) }}
class="border-b-4"
{{- else }}
class="border-b-4 border-transparent hover:border-white/20"
{{- end }}>
<a class="block px-2 py-1 whitespace-nowrap" href="{{ .URL }}">{{ .Name }}</a>
</li>
<li
{{- if or (eq page.Permalink .Page.Permalink) (page.IsDescendant .Page) }}
class="border-b-4"
{{- else }}
class="border-b-4 border-transparent hover:border-white/20"
{{- end }}
>
<a class="block px-2 py-1 whitespace-nowrap" href="{{ .URL }}"
>{{ .Name }}</a
>
</li>
{{ end }}
</ul>
</nav>
</div>
<div class="flex min-w-0 items-center gap-4 flex-grow justify-end">
<div class="flex min-w-0 flex-grow items-center justify-end gap-4">
{{ partialCached "search-bar.html" "-" }}
<button @click="open = false"
class="dark:text-white py-1 px-2 rounded open-kapa-widget flex gap-1 items-center hover:bg-white/20 transition">
<button
@click="open = false"
class="open-kapa-widget flex items-center gap-1 rounded-sm px-2 py-1 transition hover:bg-white/20 dark:text-white"
>
<span>Ask&nbsp;AI</span>
<img src="{{ (resources.Get "images/ai-stars.svg").Permalink }}" alt="AI Stars" />
<img
src="{{ (resources.Get "images/ai-stars.svg").Permalink }}"
alt="AI Stars"
/>
</button>
</div>
</div>

View File

@ -10,12 +10,16 @@
{{- if not .Page.Params.icon }}
{{- errorf "[languages] language is missing an icon: '%s' in %s" (urlize (strings.ToLower .Title)) page.File.Filename }}
{{- end }}
<span class="text-sm inline-flex gap-1 items-center rounded-full border
border-divider-light dark:border-divider-dark bg-gray-light-100
px-2 text-gray-light-800 dark:bg-gray-dark-200
dark:text-gray-dark-800 select-none">
<img class="py-1" height="18" width="18" title="{{ .Page.LinkTitle }}" src="{{ .Page.Params.icon }}">
<span
class="border-divider-light dark:border-divider-dark inline-flex items-center gap-1 rounded-full border bg-gray-100 px-2 text-sm text-gray-200 select-none dark:bg-gray-800 dark:text-gray-400"
>
<img
class="py-1"
height="18"
width="18"
title="{{ .Page.LinkTitle }}"
src="{{ .Page.Params.icon }}"
/>
<span>{{ .Page.LinkTitle }}</span>
</span>
{{- end -}}

View File

@ -1,6 +1,7 @@
<details id="markdownDropdown" class="group relative z-10 inline-block" data-heap-id="markdown-dropdown">
<summary
class="inline-flex cursor-pointer items-center gap-2 rounded border border-gray-light-200 bg-gray-light-200 px-4 py-2 text-base font-semibold text-black transition-colors hover:bg-gray-light-300 dark:border-gray-dark-200 dark:bg-gray-dark-300 dark:text-white dark:hover:bg-gray-dark-400"
class="inline-flex cursor-pointer items-center gap-0 rounded-sm border border-gray-600 bg-white px-2 py-2
text-base font-semibold text-gray-600 transition-colors hover:bg-gray-50 dark:border-gray-50 dark:bg-gray-950 dark:text-gray-100 dark:hover:bg-gray-900"
data-heap-id="markdown-dropdown-toggle"
>
<span>Page options</span>
@ -13,13 +14,13 @@
<!-- Dropdown menu -->
<div
class="absolute right-0 z-50 mt-2 w-56 origin-top-right rounded border border-gray-light-200 bg-gray-light-200 p-2 text-sm text-black shadow-md [display:none] group-open:[display:block] dark:border-gray-dark-200 dark:bg-gray-dark-300 dark:text-white"
class="absolute right-0 z-50 mt-2 w-56 origin-top-right rounded-sm border border-gray-300 bg-white p-2 text-sm text-black shadow-md [display:none] group-open:[display:block] dark:border-gray-100 dark:text-gray-100 dark:bg-gray-950"
data-heap-id="markdown-dropdown-menu"
>
<button
onclick="copyMarkdown()"
data-heap-id="copy-markdown-button"
class="flex w-full items-start gap-2 rounded px-2 py-2 text-left transition-colors hover:bg-gray-light-300 dark:hover:bg-gray-dark-400"
class="sub-button"
>
<span class="icon-svg mt-[2px] text-base leading-none">
{{ partial "icon" "content_copy" }}
@ -35,7 +36,7 @@
<button
onclick="viewPlainText()"
data-heap-id="view-markdown-button"
class="flex w-full items-start gap-2 rounded px-2 py-2 text-left transition-colors hover:bg-gray-light-300 dark:hover:bg-gray-dark-400"
class="sub-button"
>
<span class="icon-svg mt-[2px] text-base leading-none">
{{ partial "icon" "description" }}
@ -48,7 +49,7 @@
<button
onclick="openInDocsAI()"
data-heap-id="search-docs-ai-button"
class="flex w-full items-start gap-2 rounded px-2 py-2 text-left transition-colors hover:bg-gray-light-300 dark:hover:bg-gray-dark-400"
class="sub-button"
>
<span class="icon-svg mt-[2px] text-base leading-none">
{{ partial "icon" "search" }}
@ -116,4 +117,4 @@
dropdown.removeAttribute("open");
}
});
</script>
</script>

View File

@ -4,18 +4,21 @@
- Limits heading levels to a min and max range (`$min` and `$max`).
- Wraps the ToC in a `data-pagefind-ignore` container to exclude it from search indexing.
- Includes a recursive template (`walkHeadingFragments`) to handle nested headings.
*/ -}}
*/
-}}
{{- $toc := false }}
{{- with .Fragments }}
{{- $toc = and (ne page.Params.notoc true) .Headings }}
{{- end }}
{{- with $toc }}
<div data-pagefind-ignore class="not-prose">
<div class="text-lg pb-0 lg:pb-2">{{ T "tableOfContents" }}</div>
<nav class="toc">
{{ $root := (index page.Fragments.Headings 0).Headings }}
{{- template "walkHeadingFragments" $root }}
</nav>
<div class="pb-0 text-lg lg:pb-2">
{{ T "tableOfContents" }}
</div>
<nav class="toc">
{{ $root := (index page.Fragments.Headings 0).Headings }}
{{- template "walkHeadingFragments" $root }}
</nav>
</div>
{{- end }}
@ -26,7 +29,9 @@
{{- range . }}
{{- if and (ge .Level $min) (le .Level $max) }}
<li>
<a class="link lg:no-underline" href="#{{ .ID }}">{{ markdownify .Title }}</a>
<a class="link lg:no-underline" href="#{{ .ID }}"
>{{ markdownify .Title }}</a
>
</li>
{{- end }}
{{- with .Headings }}

View File

@ -1,70 +1,79 @@
{{- if gt .Paginator.TotalPages 1 }}
{{ $selectable := "cursor-pointer" }}
{{ $active := "hover:text-black dark:hover:text-white underline underline-offset-8" }}
{{ $disabled := "cursor-not-allowed text-gray-light dark:text-gray-dark" }}
<ul class="flex gap-6 items-center">
{{- with .Paginator }}
{{- $currentPageNumber := .PageNumber }}
{{ $disabled := "cursor-not-allowed text-gray-200 dark:text-gray-500" }}
<ul class="flex items-center gap-6">
{{- with .Paginator }}
{{- $currentPageNumber := .PageNumber }}
{{- with .First }}
{{- if ne $currentPageNumber .PageNumber }}
<li>
<a class="{{ $selectable }}" href="{{ .URL }}" aria-label="First">
<span class="icon-svg">
{{- partialCached "icon" "chevron_backward" "chevron_backward" -}}
</span>
</a>
</li>
{{- else }}
<li>
<a class="{{ $disabled }}" aria-disabled="true" aria-label="First">
<span class="icon-svg">
{{- partialCached "icon" "chevron_backward" "chevron_backward" -}}
</span>
</a>
</li>
{{- with .First }}
{{- if ne $currentPageNumber .PageNumber }}
<li>
<a class="{{ $selectable }}" href="{{ .URL }}" aria-label="First">
<span class="icon-svg">
{{- partialCached "icon" "chevron_backward" "chevron_backward" -}}
</span>
</a>
</li>
{{- else }}
<li>
<a class="{{ $disabled }}" aria-disabled="true" aria-label="First">
<span class="icon-svg">
{{- partialCached "icon" "chevron_backward" "chevron_backward" -}}
</span>
</a>
</li>
{{- end }}
{{- end }}
{{- $slots := 5 }}
{{- $start := math.Max 1 (sub .PageNumber (math.Floor (div $slots 2))) }}
{{- $end := math.Min .TotalPages (sub (add $start $slots) 1) }}
{{- if lt (add (sub $end $start) 1) $slots }}
{{- $start = math.Max 1 (add (sub $end $slots) 1) }}
{{- end }}
{{- range $k := seq $start $end }}
{{- if eq $.Paginator.PageNumber $k }}
<li>
<a
class="{{ $active }}"
aria-current="page"
aria-label="Page {{ $k }}"
>{{ $k }}</a
>
</li>
{{- else }}
<li>
<a
class="{{ $selectable }}"
href="{{ (index $.Paginator.Pagers (sub $k 1)).URL }}"
aria-label="Page {{ $k }}"
>{{ $k }}</a
>
</li>
{{- end }}
{{- end }}
{{- with .Last }}
{{- if ne $currentPageNumber .PageNumber }}
<li>
<a class="{{ $selectable }}" href="{{ .URL }}" aria-label="Last">
<span class="icon-svg">
{{- partialCached "icon" "chevron_forward" "chevron_forward" -}}
</span>
</a>
</li>
{{- else }}
<li>
<a class="{{ $disabled }}" aria-disabled="true" aria-label="Last">
<span class="icon-svg">
{{- partialCached "icon" "chevron_forward" "chevron_forward" -}}
</span>
</a>
</li>
{{- end }}
{{- end }}
{{- end }}
{{- $slots := 5 }}
{{- $start := math.Max 1 (sub .PageNumber (math.Floor (div $slots 2))) }}
{{- $end := math.Min .TotalPages (sub (add $start $slots) 1) }}
{{- if lt (add (sub $end $start) 1) $slots }}
{{- $start = math.Max 1 (add (sub $end $slots) 1) }}
{{- end }}
{{- range $k := seq $start $end }}
{{- if eq $.Paginator.PageNumber $k }}
<li>
<a class="{{ $active }}" aria-current="page" aria-label="Page {{ $k }}">{{ $k }}</a>
</li>
{{- else }}
<li>
<a class="{{ $selectable }}" href="{{ (index $.Paginator.Pagers (sub $k 1)).URL }}" aria-label="Page {{ $k }}">{{ $k }}</a>
</li>
{{- end }}
{{- end }}
{{- with .Last }}
{{- if ne $currentPageNumber .PageNumber }}
<li>
<a class="{{ $selectable }}" href="{{ .URL }}" aria-label="Last">
<span class="icon-svg">
{{- partialCached "icon" "chevron_forward" "chevron_forward" -}}
</span>
</a>
</li>
{{- else }}
<li>
<a class="{{ $disabled }}" aria-disabled="true" aria-label="Last">
<span class="icon-svg">
{{- partialCached "icon" "chevron_forward" "chevron_forward" -}}
</span>
</a>
</li>
{{- end }}
{{- end }}
{{- end }}
</ul>
{{- end }}

View File

@ -3,13 +3,23 @@
<span class="icon-svg">{{ partialCached "icon" "search" "search" }}</span>
</a>
<!-- search button -->
<div x-ref="searchBarRef" x-data="{ open: false }" @click.outside="open = false;"
@keyup.escape.window="open = false" id="search-bar"
class="hidden min-w-0 sm:flex relative bg-white/10 rounded items-center p-2 sm:w-full xl:w-[400px]">
<div
x-ref="searchBarRef"
x-data="{ open: false }"
@click.outside="open = false;"
@keyup.escape.window="open = false"
id="search-bar"
class="relative hidden min-w-0 items-center rounded-sm bg-white/10 p-2 sm:flex sm:w-full xl:w-[400px]"
>
{{ (resources.Get "images/search-ai.svg").Content | safeHTML }}
<input x-ref="searchBarInput" type="search" id="search-bar-input" @focus="open = true;"
<input
x-ref="searchBarInput"
type="search"
id="search-bar-input"
@focus="open = true;"
@keyup.enter.prevent="window.location.href = '/search/?q=' + $event.target.value;"
@keyup.escape.prevent="open = false;" @keydown.window="(e) => {
@keyup.escape.prevent="open = false;"
@keydown.window="(e) => {
switch(e.key) {
case 'k':
if (e.metaKey || e.ctrlKey) {
@ -18,24 +28,41 @@
}
break;
}
}" class="flex-grow px-2 bg-transparent min-w-0 text-white placeholder:text-white outline-none" placeholder="Search"
tabindex="0" />
<div x-cloak :class="open && 'hidden'" class="hidden lg:flex border px-1 text-sm border-white rounded items-center">
}"
class="min-w-0 flex-grow bg-transparent px-2 text-white outline-hidden placeholder:text-white"
placeholder="Search"
tabindex="0"
/>
<div
x-cloak
:class="open && 'hidden'"
class="hidden items-center rounded-sm border border-white px-1 text-sm lg:flex"
>
<div class="-mt-0.5">
<span x-show="navigator.platform == 'MacIntel'" class="icon-svg icon-sm">{{ partialCached "icon" "keyboard_command_key" "keyboard_command_key" }}</span>
<span x-show="navigator.platform != 'MacIntel'" class="icon-svg icon-sm">{{ partialCached "icon" "keyboard_control_key" "keyboard_control_key" }}</span>
<span x-show="navigator.platform == 'MacIntel'" class="icon-svg icon-sm"
>{{ partialCached "icon" "keyboard_command_key" "keyboard_command_key" }}</span
>
<span x-show="navigator.platform != 'MacIntel'" class="icon-svg icon-sm"
>{{ partialCached "icon" "keyboard_control_key" "keyboard_control_key" }}</span
>
</div>
<span>K</span>
</div>
<div x-cloak :class="open || 'hidden'">
<button @click="$refs.searchBarInput.value = ''; open = false" class="text-white hover:text-white">
<button
@click="$refs.searchBarInput.value = ''; open = false"
class="text-white hover:text-white"
>
<span class="icon-svg">{{ partialCached "icon" "close" "close" }}</span>
</button>
</div>
<div x-show="open" x-cloak
class="absolute px-6 py-4 right-0 w-screen max-w-xl top-full bg-background-light dark:bg-background-dark rounded shadow-lg z-50">
<div
x-show="open"
x-cloak
class="bg-background-light dark:bg-background-dark absolute top-full right-0 z-50 w-screen max-w-xl rounded-sm px-6 py-4 shadow-lg"
>
<div id="search-bar-results">
{{- $emptyState := `<div class="p-2 text-gray-light dark:text-gray-dark">Start typing to search… or try <button @click="open=false" class="open-kapa-widget link">Ask AI</button></div>` }}
{{- $emptyState := `<div class="p-2 text-gray-200 dark:text-gray-500">Start typing to search… or try <button @click="open=false" class="open-kapa-widget link">Ask AI</button></div>` }}
{{- $emptyState | safe.HTML }}
<!-- results -->
</div>
@ -77,7 +104,7 @@
searchBarResults.classList.add("hidden");
}
let resultsHTML = `<div class="p-2 text-gray-light dark:text-gray-dark">${resultsLength} results</div>`;
let resultsHTML = `<div class="p-2 text-gray-200 dark:text-gray-500">${resultsLength} results</div>`;
resultsHTML += results
.map((item) => {
return `<div class="p-2">

View File

@ -5,7 +5,8 @@
- Includes a stepper navigation (`guides-stepper.html`) for multipage guides.
- Optionally lists resource links from `Params.resource_links`.
- Provides a link back to the main `/guides/` index.
*/ -}}
*/
-}}
<div class="flex flex-col gap-4 px-4 pt-2">
{{- $root := . }}
{{- .Store.Set "multipage" false }}
@ -18,35 +19,35 @@
</div>
<div>{{ $root.Summary }}</div>
<div class="space-y-4">
<div class="flex flex-wrap gap-2">
{{- with ($root.GetTerms "languages") }}
<div class="flex flex-wrap gap-2">
{{- with ($root.GetTerms "languages") }}
{{ partial "languages.html" . }}
{{- end }}
{{- with ($root.GetTerms "tags") }}
{{- end }}
{{- with ($root.GetTerms "tags") }}
{{ partial "tags.html" . }}
{{- end }}
</div>
{{- with ($root.Params.time) }}
<div class="flex gap-2 text-gray-light dark:text-gray-dark">
<span class="icon-svg"
>{{ partialCached "icon" "schedule" "schedule" }}</span
>
<span>{{ . }}</span>
{{- end }}
</div>
{{- end -}}
{{- with ($root.Params.time) }}
<div class="flex gap-2 text-gray-200 dark:text-gray-500">
<span class="icon-svg"
>{{ partialCached "icon" "schedule" "schedule" }}</span
>
<span>{{ . }}</span>
</div>
{{- end -}}
</div>
{{- if (.Store.Get "multipage") }}
{{- partial "guides-stepper.html" . }}
{{- end }}
{{- with $root.Params.resource_links }}
<div class="space-y-2">
<p>Resources:</p>
<ul class="ml-4 space-y-2">
{{- range . }}
<li><a href="{{ .url }}" class="link">{{ .title }}</a></li>
{{- end }}
</ul>
</div>
<div class="space-y-2">
<p>Resources:</p>
<ul class="ml-4 space-y-2">
{{- range . }}
<li><a href="{{ .url }}" class="link">{{ .title }}</a></li>
{{- end }}
</ul>
</div>
{{- end }}
<a href="/guides/" class="mt-2 link">« Back to all guides</a>
<a href="/guides/" class="link mt-2">« Back to all guides</a>
</div>

View File

@ -3,9 +3,10 @@
- Renders the main navigation for site sections, linking to the current or ancestor section/page.
- Uses the `site.Menus.main` configuration to determine primary navigation structure.
- Toggles visibility of nested menu items for the main sections.
*/ -}}
*/
-}}
<!-- Main navigation for the sidebar -->
<div class="py-2 px-4" x-data="{ expanded: false }">
<div class="px-4 py-2" x-data="{ expanded: false }">
<div class="flex w-full items-center justify-between">
<!-- Current section: use menu, fall back to current section or page -->
{{- $curr := .FirstSection }}
@ -17,15 +18,21 @@
{{- $curr = .Page }}
{{- end }}
{{- end }}
<a class="hover:text-blue-light dark:hover:text-blue-dark" href="{{ $curr.Permalink }}">
<a
class="hover:text-blue dark:hover:text-blue"
href="{{ $curr.Permalink }}"
>
{{- with $curr.Params.icon }}
<span class="pr-2 icon-sm icon-svg">
<span class="icon-sm icon-svg pr-2">
{{- partialCached "icon.html" . . -}}
</span>
{{- end }}
{{- $curr.LinkTitle -}}
</a>
<button @click="expanded = !expanded" class="rounded hover:bg-gray-light-300 hover:dark:bg-gray-dark-300">
<button
@click="expanded = !expanded"
class="rounded-sm hover:bg-gray-300 hover:dark:bg-gray-300"
>
<span x-show="! expanded" class="icon-svg">
{{ partialCached "icon" "arrow_drop_down" "arrow_drop_down" }}
</span>
@ -34,21 +41,21 @@
</span>
</button>
</div>
<ul x-cloak x-show="expanded" class="pt-4 space-y-4">
<ul x-cloak x-show="expanded" class="space-y-4 pt-4">
{{ range site.Menus.main }}
{{ if ne page.FirstSection .Page }}
<li>
<a class="hover:text-blue-light dark:hover:text-blue-dark" href="{{ .URL }}">
{{- with .Page.Params.icon }}
<span class="pr-2 icon-sm icon-svg">
{{- partialCached "icon.html" . . -}}
</span>
{{- end }}
{{- .Name }}
</a>
</li>
<li>
<a class="hover:text-blue dark:hover:text-blue" href="{{ .URL }}">
{{- with .Page.Params.icon }}
<span class="icon-sm icon-svg pr-2">
{{- partialCached "icon.html" . . -}}
</span>
{{- end }}
{{- .Name }}
</a>
</li>
{{ end }}
{{ end }}
</ul>
</div>
<hr class="m-2 text-gray-light-200 dark:text-gray-dark-300" />
<hr class="m-2 text-gray-200 dark:text-gray-500" />

View File

@ -5,11 +5,13 @@
- Dynamically applies current page highlighting and expanded states.
- Handles external links via `Params.sidebar.goto` in `renderSingle`.
- Requires `Params.sitemap` and `Params.sidebar` for filtering and behavior.
*/ -}}
*/
-}}
<!-- section tree -->
<nav class="md:text-sm flex flex-col">
<div
class="block py-4 md:hidden text-gray-light dark:text-gray-dark">This section</div>
<nav class="navbar-font flex flex-col">
<div class="block py-4 text-gray-200 md:hidden dark:text-gray-200">
This section
</div>
<ul>
{{ template "renderChildren" .FirstSection }}
</ul>
@ -29,8 +31,10 @@
{{- end }}
{{- end }}
{{- range .Params.sidebar.groups }}
<li class="px-2 py-2 pb-2 text-gray-light dark:text-gray-dark uppercase
text-xs font-semibold">{{ . }}</li>
<!-- Main titles -->
<li class="navbar-group-font-title mt-2 px-2 py-2 pt-5 pb-2">
{{ . }}
</li>
{{- range where $pages "Params.sidebar.group" . }}
{{- if .IsSection }}
{{- template "renderList" . }}
@ -45,34 +49,56 @@
{{ define "renderList" }}
{{ $isCurrent := eq page . }}
{{ $expanded := or $isCurrent (page.IsDescendant .) }}
<li x-data="{ expanded: {{$expanded}} }">
<div class="rounded px-4 w-full flex items-center justify-between{{ if $isCurrent }} bg-gray-light-200 dark:bg-gray-dark-200{{ end }}">
<div class="w-full py-2 truncate">
<li x-data="{ expanded: {{ $expanded }} }">
<div
class="justify-between{{ if $isCurrent }}
bg-gray-100 dark:bg-gray-900
{{ end }} flex w-full items-center rounded-sm px-4"
>
<div class="w-full truncate py-1">
{{- if .Permalink }}
{{/* If the link is not empty, use it */}}
<a {{ if $isCurrent }}aria-current="page" id="sidebar-current-page" {{ end }}
class="block select-none hover:text-blue-light hover:dark:text-blue-dark"
href="{{ .Permalink }}">
<a
{{ if $isCurrent }}
aria-current="page" id="sidebar-current-page"
{{ end }}
class="hover:text-blue block select-none hover:dark:text-blue-400"
href="{{ .Permalink }}"
>
{{ template "renderTitle" . }}
</a>
{{- else }}
{{/* Otherwise, just expand the section */}}
<button @click="expanded = !expanded"
class="w-full text-left select-none hover:text-blue-light hover:dark:text-blue-dark">
<button
@click="expanded = !expanded"
class="hover:text-blue w-full text-left select-none hover:dark:text-blue-400"
>
{{ template "renderTitle" . }}
</button>
{{- end }}
</div>
<button @click="expanded = !expanded" class="hover:bg-gray-light-300 hover:dark:bg-gray-dark-300 rounded">
<span :class="{ 'hidden' : expanded }" class="icon-svg {{ if $expanded }}hidden{{ end }}">
<button
@click="expanded = !expanded"
class="rounded-sm hover:bg-gray-300 hover:dark:bg-gray-300"
>
<span
:class="{ 'hidden' : expanded }"
class="icon-svg {{ if $expanded }}hidden{{ end }}"
>
{{ partialCached "icon" "arrow_drop_down" "arrow_drop_down" }}
</span>
<span :class="{ 'hidden' : !expanded }" class="icon-svg {{ if not $expanded }}hidden{{ end }}">
<span
:class="{ 'hidden' : !expanded }"
class="icon-svg {{ if not $expanded }}hidden{{ end }}"
>
{{ partialCached "icon" "arrow_drop_up" "arrow_drop_up" }}
</span>
</button>
</div>
<ul :class="{ 'hidden' : !expanded }" class="{{if not $expanded}}hidden {{end}}ml-3">
<ul
:class="{ 'hidden' : !expanded }"
class="{{ if not $expanded }}hidden{{ end }} ml-3"
>
{{ template "renderChildren" . }}
</ul>
</li>
@ -80,19 +106,30 @@
{{ define "renderSingle" }}
{{- if .Params.sidebar.goto }}
<li class="px-4 hover:text-blue-light hover:dark:text-blue-dark">
<a class="py-2 w-full truncate block"
href="{{ .Params.sidebar.goto }}"
title="{{ .LinkTitle }}">
<li class="hover:text-blue px-4 hover:dark:text-blue-400">
<a
class="block w-full truncate py-2"
href="{{ .Params.sidebar.goto }}"
title="{{ .LinkTitle }}"
>
{{ template "renderTitle" . }}
</a>
</li>
{{- else }}
{{ $isCurrent := eq page . }}
<li class="rounded px-4 hover:text-blue-light hover:dark:text-blue-dark
{{ if $isCurrent }} bg-gray-light-200 dark:bg-gray-dark-200{{ end }}">
<a {{ if $isCurrent }}aria-current="page" id="sidebar-current-page" {{ end }} class="py-2 w-full truncate block"
href="{{ .Permalink }}" title="{{ .LinkTitle }}">
<li
class="hover:text-blue {{ if $isCurrent }}
bg-gray-100 dark:bg-gray-900
{{ end }} rounded-sm px-4 hover:dark:text-blue-400"
>
<a
{{ if $isCurrent }}
aria-current="page" id="sidebar-current-page"
{{ end }}
class="block w-full truncate py-2"
href="{{ .Permalink }}"
title="{{ .LinkTitle }}"
>
{{ template "renderTitle" . }}
</a>
</li>
@ -102,6 +139,8 @@
{{ define "renderTitle" }}
{{ .LinkTitle }}
{{- with .Params.sidebar.badge }}
<span>{{- partial "components/badge.html" (dict "color" .color "content" .text) }}</span>
<span
>{{- partial "components/badge.html" (dict "color" .color "content" .text) }}</span
>
{{- end }}
{{ end }}
{{ end }}

View File

@ -2,14 +2,20 @@
Renders a flat list of tags for the "tags" taxonomy.
- Unlike `sections.html`, this template is based on taxonomy terms, not section pages.
- Highlights the current tag page and links to all tag pages.
*/ -}}
*/
-}}
<ul class="md:text-sm">
{{- range site.Taxonomies.tags }}
<li class="pl-4 hover:text-blue-light hover:dark:text-blue-dark
{{ if eq .Page page }} bg-gray-light-200 dark:bg-gray-dark-200{{ end }}">
<a class="py-2 w-full truncate block"
href="{{ .Page.Permalink }}"
title="{{ .Page.LinkTitle }}">
<li
class="hover:text-blue {{ if eq .Page page }}
bg-gray-400 dark:bg-gray-800
{{ end }} pl-4 hover:dark:text-blue-700"
>
<a
class="block w-full truncate py-2"
href="{{ .Page.Permalink }}"
title="{{ .Page.LinkTitle }}"
>
{{ .Page.LinkTitle }}
</a>
</li>

View File

@ -7,14 +7,13 @@
{{- if eq .File nil }}
{{- errorf "[tags] Undefined tag: '%s' in %s" (urlize (strings.ToLower .Title)) page.File.Filename }}
{{- end }}
<a class="text-sm inline-flex items-center rounded-full border
border-divider-light dark:border-divider-dark bg-gray-light-100 px-2
text-gray-light-800 dark:bg-gray-dark-200 dark:text-gray-dark-800
select-none"
href="{{ .Permalink }}">
<a
class="border-divider-light dark:border-divider-dark bg-gray-00 inline-flex items-center rounded-full border px-2 text-sm text-gray-800 select-none hover:bg-gray-100 dark:bg-gray-800 dark:text-gray-200 hover:dark:bg-gray-700"
href="{{ .Permalink }}"
>
<span class="icon-svg icon-sm pb-0.5">
{{ partialCached "icon" "tag" "tag" }}
</span>
<span>{{ .LinkTitle }}</span>
</a>
</a>
{{- end -}}

View File

@ -1,15 +1,24 @@
{{- /*
Renders a tooltip component using Floating UI for positioning.
See script at `assets/js/src/tooltip.js` for functionality.
*/ -}}
*/
-}}
<div data-tooltip-wrapper>
<div data-tooltip-button class="icon-svg flex items-center text-blue-light dark:text-blue-dark">
<div
data-tooltip-button
class="icon-svg text-blue-light flex items-center dark:text-blue-700"
>
{{ partialCached "icon" "help" "help" }}
</div>
<div data-tooltip-body
class="absolute left-0 top-0 hidden max-w-56 rounded bg-gray-light-700 p-2 text-white dark:bg-gray-dark-300"
role="tooltip">
<div
data-tooltip-body
class="absolute top-0 left-0 hidden max-w-56 rounded-sm bg-gray-700 p-2 text-white dark:bg-gray-300"
role="tooltip"
>
{{ . }}
<div data-tooltip-arrow class="absolute h-2 w-2 rotate-45 bg-gray-light-700 dark:bg-gray-dark-300"></div>
<div
data-tooltip-arrow
class="absolute h-2 w-2 rotate-45 bg-gray-700 dark:bg-gray-300"
></div>
</div>
</div>

View File

@ -1,15 +1,22 @@
{{- /*
Processes and links the main CSS file (`assets/css/styles.css`).
- Applies PostCSS, minification, fingerprinting, and post-processing in production.
- Adds inline CSS to hide injected images in production builds.
*/ -}}
{{ $styles := resources.Get "css/styles.css" }}
{{ $styles = $styles | css.PostCSS }}
{{ if hugo.IsProduction }}
{{ $styles = $styles | minify | fingerprint | resources.PostProcess }}
<style>
/* hide img injected by prod scripts */
body > img { display: none }
</style>
{{ with (templates.Defer (dict "key" "global")) }}
{{ with resources.Get "css/style.css" }}
{{ $opts := dict
"minify" hugo.IsProduction
"inlineImports" true
}}
{{ with . | css.TailwindCSS $opts }}
{{ if hugo.IsProduction }}
{{ with . | fingerprint }}
<link
rel="stylesheet"
href="{{ .RelPermalink }}"
integrity="{{ .Data.Integrity }}"
crossorigin="anonymous"
/>
{{ end }}
{{ else }}
<link rel="stylesheet" href="{{ .RelPermalink }}" />
{{ end }}
{{ end }}
{{ end }}
{{ end }}
<link href="{{ $styles.Permalink }}" rel="stylesheet" />

View File

@ -0,0 +1,10 @@
{{- $path := printf "%s" . }}
{{- with resources.Get $path }}
{{ .Content | safeHTML }}
{{- else }}
{{- if in $path "toolbox.svg" }}
{{/* Temporary empty branch */}}
{{- else }}
{{- errorf "The 'svg' partial was unable to find %s" $path }}
{{- end }}
{{- end }}

View File

@ -5,9 +5,9 @@
{{ define "main" }}
{{ partial "breadcrumbs.html" . }}
<article class="prose max-w-none dark:prose-invert">
<article class="prose dark:prose-invert max-w-none">
{{ with .Title }}
<h1 class="scroll-mt-36">{{ . }}</h1>
<h1>{{ . }}</h1>
{{ end }}
<table>
<thead>

View File

@ -8,7 +8,9 @@
{{ $url = ref .Page $url }}
{{- end -}}
<div class="not-prose my-4">
<a href="{{ $url }}"
class="cursor-pointer py-2 px-4 rounded bg-blue-light-500 dark:bg-blue-dark-400 hover:bg-blue-light-400 dark:hover:bg-blue-dark-500 text-white">{{
$text }}</a>
<a
href="{{ $url }}"
class="cursor-pointer rounded-sm bg-blue-500 px-4 py-2 text-white hover:bg-blue-400 dark:bg-blue-800 dark:hover:bg-blue-700"
>{{ $text }}</a
>
</div>

View File

@ -1,9 +1,8 @@
{{ partial "components/card.html"
(dict
"description" (.Get "description")
"link" (.Get "link")
"title" (.Get "title")
"icon" (.Get "icon")
"image" (.Get "image")
"description" (.Get "description")
"link" (.Get "link")
"title" (.Get "title")
"icon" (.Get "icon")
)
}}

View File

@ -1,10 +1,11 @@
<div class="p-4 bg-amber-light-200 dark:bg-amber-dark-200" role="alert">
<div class="bg-amber-light-200 dark:bg-amber-dark-200 p-4" role="alert">
<div class="text-lg">{{ .Get "header" }}</div>
{{ .Get "body" | .Page.RenderString (dict "display" "block") }}
<div class="not-prose">
<a href="{{ .Get "url" }}"
class="cursor-pointer py-2 px-4 rounded bg-blue-light-500 dark:bg-blue-dark-400 hover:bg-blue-light-400 dark:hover:bg-blue-dark-500 text-white"
>{{ .Get "cta" }}</a>
<a
href="{{ .Get "url" }}"
class="cursor-pointer rounded-sm bg-blue-500 px-4 py-2 text-white hover:bg-blue-400 dark:bg-blue-800 dark:hover:bg-blue-700"
>{{ .Get "cta" }}</a
>
</div>
</div>

View File

@ -4,43 +4,50 @@
{{- $mac := .Get "mac" -}}
{{- $linux := .Get "linux" -}}
{{- $build_path := .Get "build_path" -}}
<blockquote {{ if eq $build_path "/" }} class="tip" {{ end }}>
<p>Download Docker Desktop</p>
<p>
<blockquote {{ if eq $build_path "/" }} class="tip" {{ end }} class="not-prose download-links">
<p>Download Docker Desktop:</p>
<div class="download-links-subcontainer">
{{- if or $all $win }}
<a rel="noopener"
href="https://desktop.docker.com/win/main/amd64{{ $build_path }}Docker%20Desktop%20Installer.exe">Windows</a>
(<a rel="noopener"
href="https://desktop.docker.com/win/main/amd64{{ $build_path }}checksums.txt">checksum</a>) |
<div>
<a rel="noopener"
href="https://desktop.docker.com/win/main/amd64{{ $build_path }}Docker%20Desktop%20Installer.exe">Windows</a>
(<a rel="noopener"
href="https://desktop.docker.com/win/main/amd64{{ $build_path }}checksums.txt">checksum</a>)
</div>
{{ end }}
{{- if or $beta_win_arm }}
<a rel="noopener"
href="https://desktop.docker.com/win/main/arm64{{ $build_path }}Docker%20Desktop%20Installer.exe">Windows ARM Beta</a>
(<a rel="noopener"
href="https://desktop.docker.com/win/main/arm64{{ $build_path }}checksums.txt">checksum</a>) |
<div>
<a rel="noopener"
href="https://desktop.docker.com/win/main/arm64{{ $build_path }}Docker%20Desktop%20Installer.exe">Windows ARM Beta</a>
(<a rel="noopener"
href="https://desktop.docker.com/win/main/arm64{{ $build_path }}checksums.txt">checksum</a>)
</div>
{{ end }}
{{- if or $all $mac }}
<a rel="noopener" href="https://desktop.docker.com/mac/main/arm64{{ $build_path }}Docker.dmg">Mac
with Apple chip</a>
(<a rel="noopener"
href="https://desktop.docker.com/mac/main/arm64{{ $build_path }}checksums.txt">checksum</a>) |
<a rel="noopener" href="https://desktop.docker.com/mac/main/amd64{{ $build_path }}Docker.dmg">Mac
with Intel chip</a>
(<a rel="noopener"
href="https://desktop.docker.com/mac/main/amd64{{ $build_path }}checksums.txt">checksum</a>)
<div>
<a rel="noopener" href="https://desktop.docker.com/mac/main/arm64{{ $build_path }}Docker.dmg">Mac with Apple chip</a>
(<a rel="noopener"
href="https://desktop.docker.com/mac/main/arm64{{ $build_path }}checksums.txt">checksum</a>)
</div>
<div>
<a rel="noopener" href="https://desktop.docker.com/mac/main/amd64{{ $build_path }}Docker.dmg">Mac with Intel chip</a>
(<a rel="noopener"
href="https://desktop.docker.com/mac/main/amd64{{ $build_path }}checksums.txt">checksum</a>)
</div>
{{ end -}}
{{- if or $all $linux }}
|
<a rel="noopener"
href="https://desktop.docker.com/linux/main/amd64{{ $build_path }}docker-desktop-amd64.deb">Debian</a>
-
<a rel="noopener"
href="https://desktop.docker.com/linux/main/amd64{{ $build_path }}docker-desktop-x86_64.rpm">RPM</a>
-
<a rel="noopener"
href="https://desktop.docker.com/linux/main/amd64{{ $build_path }}docker-desktop-x86_64.pkg.tar.zst">Arch</a>
(<a rel="noopener"
href="https://desktop.docker.com/linux/main/amd64{{ $build_path }}checksums.txt">checksum</a>)
<div>
<a rel="noopener"
href="https://desktop.docker.com/linux/main/amd64{{ $build_path }}docker-desktop-amd64.deb">Debian</a>
-
<a rel="noopener"
href="https://desktop.docker.com/linux/main/amd64{{ $build_path }}docker-desktop-x86_64.rpm">RPM</a>
-
<a rel="noopener"
href="https://desktop.docker.com/linux/main/amd64{{ $build_path }}docker-desktop-x86_64.pkg.tar.zst">Arch</a>
(<a rel="noopener"
href="https://desktop.docker.com/linux/main/amd64{{ $build_path }}checksums.txt">checksum</a>)
</div>
{{- end -}}
</p>
</div>
</blockquote>

View File

@ -1,5 +1,7 @@
{{ $cols := .Get "cols" | default 3 }}
<div class="not-prose grid grid-cols-1 md:grid-cols-{{ math.Max 2 (sub $cols 1) }} lg:grid-cols-{{ $cols }} gap-4">
<div
class="not-prose md:grid-cols-{{ math.Max 2 (sub $cols 1) }} lg:grid-cols-{{ $cols }} grid grid-cols-1 gap-4 mb-6"
>
{{ $items := index .Page.Params (.Get "items" | default "grid") }}
{{ range $items }}
{{ $opts := dict "title" .title "link" .link "description" .description "icon" .icon "image" .image }}

View File

@ -1,3 +1 @@
<em class="italic text-gray-light-500 dark:text-gray-dark-500"
>{{ .Get "date" }}</em
>
<em class="text-gray-200 italic dark:text-gray-500">{{ .Get "date" }}</em>

View File

@ -23,7 +23,7 @@
<div
class="not-prose my-1 flex flex-col border-l-4 border-gray-light-200 bg-gray-light-200 bg-opacity-75 px-4 py-1 dark:bg-gray-dark-300 dark:bg-opacity-75"
class="not-prose summary-bar"
>
{{ with $feature.subscription }}
<div class="flex flex-wrap gap-1">
@ -79,4 +79,4 @@
</div>
{{ end }}
</div>
{{ end }}
{{ end }}

View File

@ -4,26 +4,27 @@
{{ $groupID := fmt.Printf "tabgroup-%s" (urlize $group) }}
{{ $persist := .Get "persist" }}
<div
{{ with $group }}
{{ if $persist }}
x-data="{ selected: $persist('{{$first}}').as('{{$groupID}}') }"
x-data="{ selected: $persist('{{ $first }}').as('{{ $groupID }}') }"
{{ else }}
x-data="{ selected: '{{$first}}' }"
x-data="{ selected: '{{ $first }}' }"
{{ end }}
@tab-select.window="$event.detail.group === '{{ . }}'
? selected = $event.detail.name
: null"
@tab-select.window="$event.detail.group === '{{ . }}' ? selected =
$event.detail.name : null"
{{ else }}
x-data="{ selected: '{{ $first }}' }"
{{ end }}
aria-role="tabpanel">
aria-role="tabpanel"
>
<div aria-role="tablist" class="space-x-2">
{{ range (.Store.Get "tabs") }}
<button
class="p-1"
:class="selected === '{{ .name | urlize }}' &&
'border-blue-light-500 border-b-4 dark:border-b-blue-dark-600'"
'border-blue border-b-4 dark:border-b-blue-600'"
{{ if $group }}
@click="$dispatch('tab-select', { group: '{{ $group }}', name:
'{{ .name | urlize }}'})"

View File

@ -4,20 +4,22 @@
{{ end }}
{{ define "main" }}
<article class="prose max-w-none dark:prose-invert">
<article class="prose dark:prose-invert max-w-none">
{{ partial "breadcrumbs.html" . }}
<h1 class="scroll-mt-36 flex items-center">
<span class="icon-svg icon-lg pb-2">{{ partialCached "icon" "tag" "tag" }}</span>
<h1 class="flex items-center">
<span class="icon-svg icon-lg pb-2"
>{{ partialCached "icon" "tag" "tag" }}</span
>
<span>{{ .Title }}</span>
</h1>
{{ .Content }}
<ul>
{{ range site.Taxonomies.tags }}
<li>
<a href="{{ .Page.Permalink }}">{{ .Page.Title }}</a>
({{ (len .Pages) }} {{ cond (gt (len .Pages) 1) "pages" "page" }})
</li>
{{ end }}
{{ range site.Taxonomies.tags }}
<li>
<a href="{{ .Page.Permalink }}">{{ .Page.Title }}</a>
({{ (len .Pages) }} {{ cond (gt (len .Pages) 1) "pages" "page" }})
</li>
{{ end }}
</ul>
</article>
{{ end }}

View File

@ -6,7 +6,7 @@
{{ define "main" }}
<article class="prose max-w-none dark:prose-invert">
{{ partial "breadcrumbs.html" . }}
<h1 class="scroll-mt-36 flex items-center">
<h1 class="flex items-center">
<span class="icon-svg icon-lg pb-2">{{ partialCached "icon" "tag" "tag" }}</span>
</span>{{ .Title }}</span>
</h1>

2634
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -19,19 +19,16 @@
"@alpinejs/persist": "^3.14.3",
"@floating-ui/dom": "^1.6.12",
"@material-symbols/svg-400": "^0.23.0",
"@tailwindcss/cli": "^4.1.6",
"@tailwindcss/nesting": "^0.0.0-insiders.565cd3e",
"@tailwindcss/typography": "^0.5.15",
"alpinejs": "^3.14.3",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.49",
"postcss-cli": "^11.0.0",
"postcss-import": "^16.1.0",
"tailwindcss": "^3.4.15"
"tailwindcss": "^4.1.6"
},
"devDependencies": {
"markdownlint": "^0.35.0",
"prettier": "^3.3.3",
"prettier-plugin-go-template": "^0.0.15",
"prettier-plugin-tailwindcss": "^0.6.8"
"prettier-plugin-tailwindcss": "^0.6.11"
}
}

View File

@ -1,8 +0,0 @@
module.exports = {
plugins: {
"postcss-import": {},
"tailwindcss/nesting": {},
tailwindcss: {},
...(process.env.NODE_ENV === "production" ? { autoprefixer: {} } : {}),
},
};

Some files were not shown because too many files have changed in this diff Show More