docs: update overview page

This commit is contained in:
Amy Sorto
2025-01-17 21:54:18 +00:00
committed by Jessica Janiuk
parent 27fa993fb8
commit 111a7644ef
38 changed files with 1068 additions and 623 deletions
@@ -171,11 +171,18 @@ export class DocViewer {
return;
}
const firstHeading = element.querySelector<HTMLHeadingElement>('h2,h3[id]');
let firstHeading = element.querySelector<HTMLElement>('h2,h3[id]');
if (!firstHeading) {
return;
}
// If the first header is in a card container element, place TOC element
// before the container.
const parentEl = firstHeading.parentElement;
if (parentEl && parentEl.classList.contains('docs-card-container-header')) {
firstHeading = parentEl.parentElement;
}
// Since the content of the main area is dynamically created and there is
// no host element for a ToC component, we create it manually.
let tocHostElement: HTMLElement | null = element.querySelector(TOC_HOST_ELEMENT_NAME);
@@ -7,14 +7,23 @@
*/
import {Tokens, Token, RendererThis, TokenizerThis} from 'marked';
import {loadWorkspaceRelativeFile} from '../../helpers.mjs';
import {formatHeading} from '../../transformations/heading.mjs';
interface DocsCardContainerToken extends Tokens.Generic {
type: 'docs-card-container';
cards: string;
headerTitle?: string;
headerImgSrc?: string;
tokens: Token[];
}
const cardContainerRule = /^<docs-card-container>(.*?)<\/docs-card-container>/s;
// Capture group 1: all attributes on the opening tag
// Capture group 2: all content between the open and close tags
const cardContainerRule =
/^[^<]*<docs-card-container(?:\s([^>]*))?>((?:.(?!\/docs-card-container))*)<\/docs-card-container>/s;
const headerTitleRule = /headerTitle="([^"]*)"/;
const headerImgSrcRule = /headerImgSrc="([^"]*)"/;
export const docsCardContainerExtension = {
name: 'docs-card-container',
@@ -26,11 +35,18 @@ export const docsCardContainerExtension = {
const match = cardContainerRule.exec(src);
if (match) {
const body = match[1];
const attr = match[1] ? match[1].trim() : '';
const headerTitle = headerTitleRule.exec(attr);
const headerImgSrc = headerImgSrcRule.exec(attr);
const body = match[2].trim();
const token: DocsCardContainerToken = {
type: 'docs-card-container',
raw: match[0],
cards: body ?? '',
headerTitle: headerTitle ? headerTitle[1] : undefined,
headerImgSrc: headerImgSrc ? headerImgSrc[1] : undefined,
tokens: [],
};
this.lexer.blockTokens(token.cards, token.tokens);
@@ -39,10 +55,35 @@ export const docsCardContainerExtension = {
return undefined;
},
renderer(this: RendererThis, token: DocsCardContainerToken) {
return `
<div class="docs-card-grid">
${this.parser.parse(token.tokens)}
</div>
`;
return token.headerTitle
? getContainerWithHeader(this, token)
: getStandardContainer(this, token);
},
};
function getStandardContainer(renderer: RendererThis, token: DocsCardContainerToken) {
return `
<div class="docs-card-grid">
${renderer.parser.parse(token.tokens)}
</div>
`;
}
function getContainerWithHeader(renderer: RendererThis, token: DocsCardContainerToken) {
// We can assume that all illustrations are svg files
// We need to read svg content, instead of renering svg with `img`,
// cause we would like to use CSS variables to support dark and light mode.
let illustration = token.headerImgSrc ? loadWorkspaceRelativeFile(token.headerImgSrc!) : '';
return `
<div class="docs-card-container-wrapper">
<div class="docs-card-container-header">
${formatHeading({text: token.headerTitle!, depth: 2})}
<span class="header-img">${illustration}</span>
</div>
<div class="docs-card-container-content docs-card-grid">
${renderer.parser.parse(token.tokens)}
</div>
</div>
`;
}
@@ -17,17 +17,19 @@ interface DocsCardToken extends Tokens.Generic {
link?: string;
href?: string;
imgSrc?: string;
iconImgSrc?: string; // Need image since icons are custom
tokens: Token[];
}
// Capture group 1: all attributes on the opening tag
// Capture group 2: all content between the open and close tags
const cardRule = /^[^<]*<docs-card\s([^>]*)>((?:.(?!\/docs-card))*)<\/docs-card>/s;
const cardRule = /^[^<]*<docs-card(?:\s([^>]*))?>((?:.(?!\/docs-card))*)<\/docs-card>/s;
const titleRule = /title="([^"]*)"/;
const linkRule = /link="([^"]*)"/;
const hrefRule = /href="([^"]*)"/;
const imgSrcRule = /imgSrc="([^"]*)"/;
const iconImgSrcRule = /iconImgSrc="([^"]*)"/;
export const docsCardExtension = {
name: 'docs-card',
@@ -39,11 +41,12 @@ export const docsCardExtension = {
const match = cardRule.exec(src);
if (match) {
const attr = match[1].trim();
const attr = match[1] ? match[1].trim() : '';
const title = titleRule.exec(attr);
const link = linkRule.exec(attr);
const href = hrefRule.exec(attr);
const imgSrc = imgSrcRule.exec(attr);
const iconImgSrc = iconImgSrcRule.exec(attr);
const body = match[2].trim();
@@ -55,6 +58,7 @@ export const docsCardExtension = {
href: href ? href[1] : undefined,
link: link ? link[1] : undefined,
imgSrc: imgSrc ? imgSrc[1] : undefined,
iconImgSrc: iconImgSrc ? iconImgSrc[1] : undefined,
tokens: [],
};
this.lexer.blockTokens(token.body, token.tokens);
@@ -68,7 +72,23 @@ export const docsCardExtension = {
};
function getStandardCard(renderer: RendererThis, token: DocsCardToken) {
if (token.href) {
if (token.iconImgSrc && token.href) {
// We can assume that all icons are svg files since they are custom.
// We need to read svg content, instead of renering svg with `img`,
// cause we would like to use CSS variables to support dark and light mode.
const icon = loadWorkspaceRelativeFile(token.iconImgSrc);
return `
<a href="${token.href}" ${anchorTarget(token.href)} class="docs-card">
<div>
${icon}
<h3>${token.title}</h3>
${renderer.parser.parse(token.tokens)}
</div>
<span>${token.link ? token.link : 'Learn more'}</span>
</a>
`;
} else if (token.href) {
return `
<a href="${token.href}" ${anchorTarget(token.href)} class="docs-card">
<div>
@@ -0,0 +1,146 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {Tokens, Token, RendererThis, TokenizerThis} from 'marked';
import {loadWorkspaceRelativeFile} from '../../helpers.mjs';
interface DocsNavCardToken extends Tokens.Generic {
type: 'docs-nav-card';
title: string;
items: string;
tokens: Token[];
iconImgSrc?: string; // Need image since icons are custom
}
// Capture group 1: all attributes on the opening tag
// Capture group 2: all content between the open and close tags
const navCardRule = /^[^<]*<docs-nav-card\s([^>]*)>((?:.(?!\/docs-nav-card))*)<\/docs-nav-card>/s;
const titleRule = /title="([^"]*)"/;
const hrefRule = /href="([^"]*)"/;
const iconImgSrcRule = /iconImgSrc="([^"]*)"/;
export const docsNavCardExtension = {
name: 'docs-nav-card',
level: 'block' as const,
start(src: string) {
return src.match(/^\s*<docs-nav-card\s*/m)?.index;
},
tokenizer(this: TokenizerThis, src: string): DocsNavCardToken | undefined {
const match = navCardRule.exec(src);
if (match) {
const attr = match[1].trim();
const title = titleRule.exec(attr);
const iconImgSrc = iconImgSrcRule.exec(attr);
const items = match[2].trim();
const token: DocsNavCardToken = {
type: 'docs-nav-card',
raw: match[0],
title: title ? title[1] : '',
items: items ?? '',
iconImgSrc: iconImgSrc ? iconImgSrc[1] : undefined,
tokens: [],
};
this.lexer.blockTokens(token.items, token.tokens);
return token;
}
return undefined;
},
renderer(this: RendererThis, token: DocsNavCardToken) {
// We can assume that all icons are svg files since they are custom.
// We need to read svg content, instead of renering svg with `img`,
// cause we would like to use CSS variables to support dark and light mode.
let icon = '';
if (token.iconImgSrc) {
icon = loadWorkspaceRelativeFile(token.iconImgSrc);
}
return `
<div class="docs-nav-card">
<div class="docs-nav-card-title">
${icon}
<h6>${token.title}</h6>
</div>
<div class="docs-nav-card-content">
<div class="docs-nav-card-links">
${this.parser.parse(token.tokens)}
</div>
</div>
</div>
`;
},
};
interface DocsNavLinkToken extends Tokens.Generic {
type: 'docs-nav-link';
title: string;
body: string;
href: string;
iconImgSrc?: string; // Need image since icons are custom
bodyTokens: Token[];
}
// Capture group 1: all attributes on the opening tag
// Capture group 2: all content between the open and close tags
const navLinkRule = /^[^<]*<docs-nav-link\s([^>]*)>((?:.(?!\/docs-nav-link))*)<\/docs-nav-link>/s;
export const docsNavLinkExtension = {
name: 'docs-nav-link',
level: 'block' as const,
start(src: string) {
src.match(/^\s*<docs-nav-link/m)?.index;
},
tokenizer(this: TokenizerThis, src: string): DocsNavLinkToken | undefined {
const match = navLinkRule.exec(src);
if (match) {
const attr = match[1].trim();
const title = titleRule.exec(attr);
const iconImgSrc = iconImgSrcRule.exec(attr);
const href = hrefRule.exec(attr);
const body = match[2].trim();
const token: DocsNavLinkToken = {
type: 'docs-nav-link',
raw: match[0],
title: title ? title[1] : '',
href: href ? href[1] : '',
body: body ?? '',
iconImgSrc: iconImgSrc ? iconImgSrc[1] : undefined,
bodyTokens: [],
};
this.lexer.blockTokens(token.body, token.bodyTokens);
return token;
}
return undefined;
},
renderer(this: RendererThis, token: DocsNavLinkToken) {
// We can assume that all icons are svg files since they are custom.
// We need to read svg content, instead of renering svg with `img`,
// cause we would like to use CSS variables to support dark and light mode.
let icon = '';
if (token.iconImgSrc) {
icon = loadWorkspaceRelativeFile(token.iconImgSrc);
}
return `
<a href="${token.href}" class="docs-card docs-nav-link">
<div class="docs-card-text-content">
<div class="docs-nav-link-title">
${icon}
<h3>${token.title}</h3>
</div>
${this.parser.parse(token.bodyTokens)}
</div>
</a>
`;
},
};
@@ -15,6 +15,7 @@ interface DocsDecorativeHeaderToken extends Tokens.Generic {
type: 'docs-decorative-header';
title: string;
imgSrc: string;
gradientBackground?: boolean;
body: string;
}
@@ -25,6 +26,7 @@ const decorativeHeaderRule =
const imgSrcRule = /imgSrc="([^"]*)"/;
const titleRule = /title="([^"]*)"/;
const gradientBackgroundRule = /gradientBackground="([^"]*)"/;
export const docsDecorativeHeaderExtension = {
name: 'docs-decorative-header',
@@ -41,12 +43,14 @@ export const docsDecorativeHeaderExtension = {
const imgSrc = imgSrcRule.exec(attr);
const title = titleRule.exec(attr);
const gradientBackground = gradientBackgroundRule.exec(attr);
const token: DocsDecorativeHeaderToken = {
type: 'docs-decorative-header',
raw: match[0],
title: title ? title[1] : '',
imgSrc: imgSrc ? imgSrc[1] : '',
gradientBackground: gradientBackground ? gradientBackground[1] === 'true' : false,
body: body ?? '',
};
return token;
@@ -54,26 +58,52 @@ export const docsDecorativeHeaderExtension = {
return undefined;
},
renderer(this: RendererThis, token: DocsDecorativeHeaderToken) {
// We can assume that all illustrations are svg files
// We need to read svg content, instead of renering svg with `img`,
// cause we would like to use CSS variables to support dark and light mode.
const illustration = token.imgSrc ? loadWorkspaceRelativeFile(token.imgSrc) : '';
return `
<div class="docs-decorative-header-container">
<div class="docs-decorative-header">
<div class="docs-header-content">
<docs-breadcrumb></docs-breadcrumb>
${getPageTitle(token.title, (this.parser.renderer as AdevDocsRenderer).context.markdownFilePath)}
<p>${token.body}</p>
</div>
<!-- illustration -->
${illustration}
</div>
</div>
`;
return token.gradientBackground
? getGradientDecorativeHeader(this, token)
: getStandardDecorativeHeader(this, token);
},
};
function getStandardDecorativeHeader(renderer: RendererThis, token: DocsDecorativeHeaderToken) {
// We can assume that all illustrations are svg files
// We need to read svg content, instead of renering svg with `img`,
// cause we would like to use CSS variables to support dark and light mode.
const illustration = token.imgSrc ? loadWorkspaceRelativeFile(token.imgSrc) : '';
return `
<div class="docs-decorative-header-container">
<div class="docs-decorative-header">
<div class="docs-header-content">
<docs-breadcrumb></docs-breadcrumb>
${getPageTitle(token.title)}
<p>${token.body}</p>
</div>
<!-- illustration -->
${illustration}
</div>
</div>
`;
}
function getGradientDecorativeHeader(renderer: RendererThis, token: DocsDecorativeHeaderToken) {
// We can assume that all illustrations are svg files
// We need to read svg content, instead of renering svg with `img`,
// cause we would like to use CSS variables to support dark and light mode.
const illustration = token.imgSrc ? loadWorkspaceRelativeFile(token.imgSrc) : '';
return `
<div class="docs-decorative-header-container">
<div class="docs-decorative-gradient-header">
<div class="docs-header-content">
${getPageTitle(token.title)}
<p>${token.body}</p>
</div>
<!-- illustration -->
${illustration}
</div>
</div>
`;
}
@@ -15,6 +15,7 @@ import {docsPillRowExtension} from './extensions/docs-pill/docs-pill-row.mjs';
import {docsVideoExtension} from './extensions/docs-video.mjs';
import {docsWorkflowExtension} from './extensions/docs-workflow/docs-workflow.mjs';
import {docsStepExtension} from './extensions/docs-workflow/docs-step.mjs';
import {docsNavCardExtension, docsNavLinkExtension} from './extensions/docs-card/docs-nav-card.mjs';
import {docsCardExtension} from './extensions/docs-card/docs-card.mjs';
import {docsCardContainerExtension} from './extensions/docs-card/docs-card-container.mjs';
import {docsDecorativeHeaderExtension} from './extensions/docs-decorative-header.mjs';
@@ -39,6 +40,8 @@ const extensions = [
docsCodeBlockExtension,
docsCodeExtension,
docsCodeMultifileExtension,
docsNavCardExtension,
docsNavLinkExtension,
docsTabExtension,
docsTabGroupExtension,
];
@@ -1,4 +1,4 @@
<docs-card-container>
<docs-card ></docs-card>
<docs-card ></docs-card>
<docs-card></docs-card>
<docs-card></docs-card>
</docs-card-container>
+59 -4
View File
@@ -11,10 +11,12 @@
--bright-blue: oklch(51.01% 0.274 263.83); // #0546ff
--indigo-blue: oklch(51.64% 0.229 281.65); // #5c44e4
--electric-violet: oklch(53.18% 0.28 296.97); // #8514f5
--electric-violet-header: oklch(53.18% 0.28 296.97); // #8514f5
--french-violet: oklch(47.66% 0.246 305.88); // #8001c6
--vivid-pink: oklch(69.02% 0.277 332.77); // #f637e3
--always-pink: oklch(69.02% 0.277 332.77); // #f637e3
--hot-pink: oklch(59.91% 0.239 8.14); // #e90464
--hot-pink-header: oklch(59.91% 0.239 8.14); // #e90464
--hot-red: oklch(61.42% 0.238 15.34); // #f11653
--orange-red: oklch(63.32% 0.24 31.68); // #fa2c04
--super-green: oklch(79.12% 0.257 155.13); // #00c572 // Used for success, merge additions, etc.
@@ -119,6 +121,24 @@
var(--vivid-pink) 100%
);
--pink-to-white-horizontal-gradient: linear-gradient(
90deg,
var(--vivid-pink) 0%,
var(--gray-200) 60%
);
--light-pink-to-light-purple-horizontal-gradient: linear-gradient(
90deg,
var(--light-pink) 0%,
var(--light-purple) 100%
);
--light-vivid-pink-to-light-electric-violet-horizontal-gradient: linear-gradient(
90deg,
color-mix(in srgb, var(--vivid-pink), white 90%),
color-mix(in srgb, var(--electric-violet), white 90%)
);
--purple-to-light-purple-vertical-gradient: linear-gradient(
0deg,
var(--french-violet) 0%,
@@ -156,6 +176,17 @@
var(--light-orange) 100%
);
--white-to-light-blue-diagonal-gradient: linear-gradient(
132.83deg,
hsl(from color-mix(in srgb, var(--bright-blue), white 60%) h s l / 0) 45.38%,
hsl(from color-mix(in srgb, var(--bright-blue), white 60%) h s l / 0.3) 159.03%);
--white-to-light-pink-diagonal-gradient: linear-gradient(
135deg,
white 30%,
var(--light-pink) 100%
);
// Radial Gradients
--page-bg-radial-gradient: radial-gradient(circle, white 0%, white 100%);
--soft-pink-radial-gradient: radial-gradient(
@@ -164,6 +195,12 @@
white 80%
);
--hot-pink-to-electric-violet-radial-gradient: radial-gradient(
circle at 60% bottom,
var(--hot-pink-header) 20%,
var(--electric-violet-header) 100%
);
// ABSTRACTIONS light - dark
// --full-contrast: black - white
// --primary-constrast: gray-900 - gray-100
@@ -193,6 +230,8 @@
// for the "unfilled" portion of the word that hasn't
// been highlighted by the gradient
--gray-unfilled: var(--gray-400);
--webgl-page-background: var(var(--page-background))
--webgl-gray-unfilled: var(--gray-400);
}
@mixin dark-mode-definitions() {
@@ -211,13 +250,20 @@
--bright-blue: color-mix(in srgb, oklch(51.01% 0.274 263.83), var(--full-contrast) 60%);
--indigo-blue: color-mix(in srgb, oklch(51.64% 0.229 281.65), var(--full-contrast) 70%);
--electric-violet: color-mix(in srgb, oklch(53.18% 0.28 296.97), var(--full-contrast) 70%);
--electric-violet-header: color-mix(in srgb, oklch(53.18% 0.28 296.97), var(--full-contrast) 15%);
--french-violet: color-mix(in srgb, oklch(47.66% 0.246 305.88), var(--full-contrast) 70%);
--vivid-pink: color-mix(in srgb, oklch(69.02% 0.277 332.77), var(--full-contrast) 70%);
// --always-pink we keep the same in light mode
--hot-pink: color-mix(in srgb, oklch(59.91% 0.239 8.14), var(--full-contrast) 70%);
--hot-pink-header: color-mix(in srgb, oklch(59.91% 0.239 8.14), var(--full-contrast) 15%);
--hot-red: color-mix(in srgb, oklch(61.42% 0.238 15.34), var(--full-contrast) 70%);
--orange-red: color-mix(in srgb, oklch(63.32% 0.24 31.68), var(--full-contrast) 60%);
--super-green: color-mix(in srgb, oklch(79.12% 0.257 155.13), var(--full-contrast) 70%);
--light-vivid-pink-to-light-electric-violet-horizontal-gradient:
linear-gradient(hsl(from var(--gray-1000) h s l / 0.9), hsl(from var(--gray-1000) h s l / 0.9)),
linear-gradient(hsl(from var(--full-contrast) h s l / 0.2), hsl(from var(--full-contrast) h s l / 0.2)),
var(--pink-to-purple-horizontal-gradient);
--white-to-light-pink-diagonal-gradient: color-mix(in srgb, var(--french-violet), var(--full-contrast) 60%);
--deprecated-dark: oklch(30% 0.02 304.04); // Base color
--deprecated-docs-bg: var(--deprecated-dark); // Alias specifically for deprecated docs
@@ -255,14 +301,23 @@
);
--page-bg-radial-gradient: radial-gradient(circle, black 0%, black 100%);
--soft-pink-radial-gradient: radial-gradient(
circle at center bottom,
var(--light-pink) 0%,
color-mix(in srgb, black, transparent 15%) 80%
--soft-pink-radial-gradient:
linear-gradient(119.77deg,
hsl(from color-mix(in srgb, var(--french-violet), white 60%) h s l / 0) 24.32%,
hsl(from color-mix(in srgb, var(--french-violet), white 60%) h s l / 0.3) 116.25%);
// Use light values hot pink and electric violet since this gradient used for
// the decorative header which looks the same in both modes
--hot-pink-to-electric-violet-radial-gradient: radial-gradient(
circle at 60% bottom,
var(--hot-pink-header) 20%,
var(--electric-violet-header) 100%
);
// Home page - dark mode
--gray-unfilled: var(--gray-700);
--webgl-page-background: var(--gray-1000);
--webgl-gray-unfilled: var(--gray-700);
.docs-toggle {
input {
+176
View File
@@ -1,6 +1,102 @@
// Card Grid
@mixin docs-card() {
.docs-card-container-wrapper {
border: 1px solid var(--senary-contrast);
border-radius: 0.25rem;
margin: 1rem 0;
.docs-card-container-header {
align-items: flex-end;
border-bottom: 1px solid var(--senary-contrast);
display: flex;
justify-content: space-between;
h2 {
padding: 2.5rem 1rem 2.5rem 2.5rem;
min-width: 350px;
}
.theme-fill-bg {
fill: var(--page-background);
stroke: var(--primary-contrast);
}
.theme-fill-accent-bg {
fill: var(--septenary-contrast);
stroke: var(--primary-contrast);
}
.theme-stroke-primary {
stroke: var(--primary-contrast);
}
.theme-fill-primary {
fill: var(--primary-contrast);
}
.theme-fill-secondary {
fill: var(--octonary-contrast);
}
.theme-stroke-accent {
stroke: var(--vivid-pink);
}
.theme-fill-accent {
fill: var(--vivid-pink);
stroke: var(--primary-contrast);
}
.theme-stroke-secondary {
stroke: var(--senary-contrast);
}
.theme-fill-secondary {
fill: var(--senary-contrast);
}
.header-img {
margin-top: 5px;
overflow: hidden;
margin-bottom: -5px;
}
svg {
fill-opacity: 1;
@container header (max-width: 550px) {
display: none;
}
rect {
fill: transparent;
}
}
}
.docs-card-container-content {
margin: 1rem;
padding: 1.5rem;
.docs-card {
margin: 0;
svg {
margin-block-end: 0.75rem;
}
}
}
}
.docs-card-container-wrapper:nth-child(odd) {
background-image: var(--white-to-light-blue-diagonal-gradient);
.docs-card-container-header {
background-image: var(--white-to-light-blue-diagonal-gradient);
}
}
.docs-card-container-wrapper:nth-child(even) {
background-image: var(--white-to-light-pink-diagonal-gradient);
.docs-card-container-header {
background-image: var(--white-to-light-pink-diagonal-gradient);
}
}
.docs-card-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
@@ -12,6 +108,10 @@
}
}
:not(.docs-card-container) .docs-card {
margin: 1rem 0;
}
.docs-card {
display: flex;
flex-direction: column;
@@ -101,4 +201,80 @@
margin-block-start: 0;
font-size: 1rem;
}
.docs-nav-card {
position: relative;
background: var(--light-vivid-pink-to-light-electric-violet-horizontal-gradient);
container: header / inline-size;
background-clip: padding-box;
border: solid 1px transparent;
border-radius: 0.25rem;
margin: 1rem 0;
&:before {
content: '';
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
z-index: -1;
margin: -1px;
border-radius: inherit;
background: var(--pink-to-white-horizontal-gradient);
}
.docs-nav-card-title {
background: var(--pink-to-highlight-to-purple-to-blue-horizontal-gradient);
padding: 1.5rem 1.5rem .5rem;
-webkit-background-clip: text;
background-clip: text;
color: transparent;
display: flex;
align-items: baseline;
gap: 8px;
h6 {
margin: 0;
}
}
.docs-nav-card-content {
display: flex;
margin-block: 0;
position: relative;
overflow: hidden;
padding: 0 1.5rem 1.5rem;
}
.docs-nav-card-links {
width: 100%;
}
.docs-nav-card-svg {
width: 350px;
@container header (max-width: 550px) {
display: none;
}
}
a.docs-nav-link {
text-decoration: none;
.docs-nav-link-title {
display: flex;
gap: 8px;
h3 {
margin-block-end: .5rem;
}
svg path {
fill: var(--gray-400);
}
}
p {
margin-block: 0;
}
}
}
}
@@ -15,60 +15,14 @@
flex-direction: column-reverse;
}
.docs-header-content {
box-sizing: border-box;
padding: 1.5rem;
padding-inline-end: 0;
flex-grow: 1;
@container header (max-width: 550px) {
width: 100%;
padding-block-end: 1.5rem;
}
h1,
p,
span {
color: var(--primary-contrast);
transition: color 0.3s ease;
}
a {
position: absolute;
top: 1.5rem;
right: 1.5rem;
z-index: 20;
i {
color: var(--quaternary-contrast);
}
&:hover {
i {
color: var(--primary-contrast);
}
}
}
docs-breadcrumb {
padding-block-end: 1rem;
}
.docs-breadcrumb {
font-size: 0.875rem;
span {
color: var(--primary-contrast) !important;
}
}
}
svg {
margin: 0;
margin-block: auto;
padding-inline: 1rem 3.5rem;
padding-block: 2rem;
min-width: 150px;
max-width: 250px;
margin: 0;
max-height: 125px;
max-width: 250px;
min-width: 150px;
padding-block: 2rem;
padding-inline: 1rem 3.5rem;
z-index: 0;
&.docs-what-is-angular-svg {
@@ -86,13 +40,108 @@
}
@container header (max-width: 550px) {
padding: 2rem;
max-height: 125px;
max-width: 80%;
min-width: auto;
padding-block-end: 0;
padding-inline-start: 1.5rem;
padding: 2rem;
width: fit-content;
min-width: auto;
max-width: 80%;
max-height: 125px;
}
}
}
.docs-viewer:has(.docs-decorative-gradient-header) {
padding: 0 var(--layout-padding) var(--layout-padding);
}
.docs-decorative-gradient-header {
background: var(--hot-pink-to-electric-violet-radial-gradient);
border-radius: 0 0 0.625rem 0.625rem;
display: flex;
max-width: var(--page-width);
overflow: hidden;
position: relative;
transition: background 0.3s ease;
@container header (max-width: 550px) {
flex-direction: column-reverse;
}
.docs-header-content {
padding: 5rem 12rem 5rem 2.5rem;
@container header (max-width: 550px) {
padding: 5rem 2.5rem;
}
h1,
p {
color: white;
}
.docs-breadcrumb span {
color: white !important;
}
}
svg {
bottom: -50px;
position: absolute;
right: -75px;
z-index: 0;
path {
stroke: var(--vivid-pink);
}
@container header (max-width: 550px) {
display: none;
}
}
}
.docs-header-content {
box-sizing: border-box;
flex-grow: 1;
padding-inline-end: 0;
padding: 1.5rem;
@container header (max-width: 550px) {
padding-block-end: 1.5rem;
width: 100%;
}
h1,
p,
span {
color: var(--primary-contrast);
transition: color 0.3s ease;
}
a {
position: absolute;
right: 1.5rem;
top: 1.5rem;
z-index: 20;
i {
color: var(--quaternary-contrast);
}
&:hover {
i {
color: var(--primary-contrast);
}
}
}
docs-breadcrumb {
padding-block-end: 1rem;
}
.docs-breadcrumb {
font-size: 0.875rem;
span {
color: var(--primary-contrast) !important;
}
}
}