mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
docs: update overview page
This commit is contained in:
committed by
Jessica Janiuk
parent
27fa993fb8
commit
111a7644ef
@@ -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);
|
||||
|
||||
+48
-7
@@ -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,
|
||||
];
|
||||
|
||||
+2
-2
@@ -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>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user