Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cd97ff7a13 | |||
| 075b6542b8 | |||
| afc27c8ff6 | |||
| 089db8762a | |||
| cba9c88d9b | |||
| 52088dd13a | |||
| cf42933bea | |||
| 8ad00a791e | |||
| dfa878ec14 | |||
| 5f8458469e | |||
| 55fe0419e9 | |||
| 86fbeac4ef | |||
| a40d06ed23 | |||
| 758cc7b7c8 | |||
| b6cb5ccaca | |||
| 1dad304994 | |||
| eb239f3a91 | |||
| c1c1a64daa | |||
| ca38b53eb4 | |||
| 30abc3fcc6 | |||
| f872ebdad7 | |||
| 0e37963f67 | |||
| a475a43ac0 | |||
| dc2e9d7087 | |||
| 71039e8ffd | |||
| 126710a3ed | |||
| acb1b8e55c | |||
| 9b8a9b31f0 |
@@ -47,7 +47,7 @@ jobs:
|
||||
main-branch-name: 'master'
|
||||
|
||||
- name: Start CI Run
|
||||
run: npx nx-cloud@next start-ci-run --auto-apply-fixes="*format:check*,*sync:check*,*conformance:check*,*format-native*,*lint-native*,*lint*,*astro-docs:validate-links*" --distribute-on="./.nx/workflows/dynamic-changesets.yaml" --stop-agents-after="e2e"
|
||||
run: npx nx-cloud@next start-ci-run --distribute-on="./.nx/workflows/dynamic-changesets.yaml" --stop-agents-after="e2e"
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
|
||||
Generated
+90
-75
@@ -86,6 +86,15 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi-escape-sequences"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6afb74bb006f83a46d689f70e46ce3a9830db762134b3b585986fa9eab21f75d"
|
||||
dependencies = [
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.6"
|
||||
@@ -295,7 +304,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"regex-automata 0.4.6",
|
||||
"regex-automata 0.4.13",
|
||||
"serde",
|
||||
]
|
||||
|
||||
@@ -790,6 +799,12 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b"
|
||||
|
||||
[[package]]
|
||||
name = "east-asian-width"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef8c47de0fcde8bd09c98fc22e4ea10ed14b9c05bf02c309e1e743aee7d0d9f6"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.10.0"
|
||||
@@ -1382,8 +1397,8 @@ dependencies = [
|
||||
"aho-corasick",
|
||||
"bstr",
|
||||
"log",
|
||||
"regex-automata 0.4.6",
|
||||
"regex-syntax 0.8.2",
|
||||
"regex-automata 0.4.13",
|
||||
"regex-syntax 0.8.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1587,7 +1602,7 @@ dependencies = [
|
||||
"js-sys",
|
||||
"log",
|
||||
"wasm-bindgen",
|
||||
"windows-core 0.57.0",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1625,7 +1640,7 @@ dependencies = [
|
||||
"globset",
|
||||
"log",
|
||||
"memchr",
|
||||
"regex-automata 0.4.6",
|
||||
"regex-automata 0.4.13",
|
||||
"same-file",
|
||||
"walkdir",
|
||||
"winapi-util",
|
||||
@@ -1892,7 +1907,7 @@ dependencies = [
|
||||
"rustc-hash 2.1.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.12",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tower",
|
||||
@@ -1916,7 +1931,7 @@ dependencies = [
|
||||
"rustls-platform-verifier",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.12",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"tower",
|
||||
"url",
|
||||
@@ -1944,7 +1959,7 @@ dependencies = [
|
||||
"http",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.12",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2072,9 +2087,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.1"
|
||||
version = "2.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
||||
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
@@ -2456,6 +2471,7 @@ dependencies = [
|
||||
"watchexec-filterer-ignore",
|
||||
"watchexec-signals",
|
||||
"winapi",
|
||||
"wrap-ansi",
|
||||
"xxhash-rust",
|
||||
]
|
||||
|
||||
@@ -3040,14 +3056,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.3"
|
||||
version = "1.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
|
||||
checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata 0.4.6",
|
||||
"regex-syntax 0.8.2",
|
||||
"regex-automata 0.4.13",
|
||||
"regex-syntax 0.8.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3061,13 +3077,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.6"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
|
||||
checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax 0.8.2",
|
||||
"regex-syntax 0.8.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3078,9 +3094,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.2"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
||||
|
||||
[[package]]
|
||||
name = "rend"
|
||||
@@ -3616,6 +3632,18 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "string-width"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f00d94d660cfa7bf3669352ebe9e06cc0351e0c9e696a31d051a54fa4bbb2b5"
|
||||
dependencies = [
|
||||
"east-asian-width",
|
||||
"regex",
|
||||
"strip-ansi-escapes",
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "string_cache"
|
||||
version = "0.8.7"
|
||||
@@ -3654,6 +3682,15 @@ dependencies = [
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strip-ansi-escapes"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a8f8038e7e7969abb3f1b7c2a811225e9296da208539e0f79c5251d6cac0025"
|
||||
dependencies = [
|
||||
"vte 0.14.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
@@ -3962,11 +3999,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.12"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
||||
dependencies = [
|
||||
"thiserror-impl 2.0.12",
|
||||
"thiserror-impl 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3982,9 +4019,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.12"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -4459,7 +4496,7 @@ dependencies = [
|
||||
"ratatui",
|
||||
"tui-term 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.2.0",
|
||||
"vte",
|
||||
"vte 0.13.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4473,6 +4510,15 @@ dependencies = [
|
||||
"vte_generate_state_changes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vte"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "231fdcd7ef3037e8330d8e17e61011a2c244126acc0a982f4040ac3f9f0bc077"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vte_generate_state_changes"
|
||||
version = "0.1.2"
|
||||
@@ -4827,7 +4873,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
|
||||
dependencies = [
|
||||
"windows-collections",
|
||||
"windows-core 0.61.2",
|
||||
"windows-core",
|
||||
"windows-future",
|
||||
"windows-link",
|
||||
"windows-numerics",
|
||||
@@ -4839,19 +4885,7 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
|
||||
dependencies = [
|
||||
"windows-core 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.57.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
|
||||
dependencies = [
|
||||
"windows-implement 0.57.0",
|
||||
"windows-interface 0.57.0",
|
||||
"windows-result 0.1.2",
|
||||
"windows-targets 0.52.6",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4860,10 +4894,10 @@ version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
|
||||
dependencies = [
|
||||
"windows-implement 0.60.2",
|
||||
"windows-interface 0.59.3",
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link",
|
||||
"windows-result 0.3.4",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
]
|
||||
|
||||
@@ -4873,22 +4907,11 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
|
||||
dependencies = [
|
||||
"windows-core 0.61.2",
|
||||
"windows-core",
|
||||
"windows-link",
|
||||
"windows-threading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.57.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.60.2"
|
||||
@@ -4900,17 +4923,6 @@ dependencies = [
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.57.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.59.3"
|
||||
@@ -4934,19 +4946,10 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
|
||||
dependencies = [
|
||||
"windows-core 0.61.2",
|
||||
"windows-core",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.3.4"
|
||||
@@ -5253,6 +5256,18 @@ dependencies = [
|
||||
"wayland-protocols-wlr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wrap-ansi"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "848bc403c11fc8f4d6597f2bad2ce43111fbf6757c7dd7d62590199e8dade5fd"
|
||||
dependencies = [
|
||||
"ansi-escape-sequences",
|
||||
"regex",
|
||||
"string-width",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
version = "0.5.1"
|
||||
|
||||
@@ -4,6 +4,28 @@
|
||||
NX_GRADLE_DISABLE = "true"
|
||||
NX_MAVEN_DISABLE = "true"
|
||||
|
||||
# Edge Functions for tracking LLM/AI tool requests to GA4
|
||||
[[edge_functions]]
|
||||
function = "track-asset-requests"
|
||||
path = "/*.txt"
|
||||
|
||||
[[edge_functions]]
|
||||
function = "track-asset-requests"
|
||||
path = "/**/*.txt"
|
||||
|
||||
[[edge_functions]]
|
||||
function = "track-asset-requests"
|
||||
path = "/*.md"
|
||||
|
||||
[[edge_functions]]
|
||||
function = "track-asset-requests"
|
||||
path = "/**/*.md"
|
||||
|
||||
# Edge Function to add HTTP Link headers for LLM resource discovery
|
||||
[[edge_functions]]
|
||||
function = "add-link-headers"
|
||||
path = "/docs/*"
|
||||
|
||||
# Permanent redirects (301 by default)
|
||||
|
||||
# Storybook docs consolidation
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import type { Context } from 'https://edge.netlify.com';
|
||||
|
||||
/**
|
||||
* Content negotiation for LLM-friendly docs access.
|
||||
* See: https://llmstxt.org/
|
||||
*/
|
||||
export default async function handler(
|
||||
request: Request,
|
||||
context: Context
|
||||
): Promise<Response | URL> {
|
||||
const url = new URL(request.url);
|
||||
const pathname = url.pathname;
|
||||
|
||||
// Skip non-page paths (assets, API endpoints, etc.)
|
||||
if (
|
||||
pathname.endsWith('.md') ||
|
||||
pathname.endsWith('.txt') ||
|
||||
pathname.includes('/og/') ||
|
||||
pathname.includes('/_') ||
|
||||
pathname.includes('/assets/')
|
||||
) {
|
||||
return context.next();
|
||||
}
|
||||
|
||||
const acceptHeader = request.headers.get('accept') || '';
|
||||
|
||||
// Serve markdown for LLM tools that explicitly request it
|
||||
// Or if there are no accept headers passed (e.g. Cursor)
|
||||
if (!acceptHeader || acceptHeader.includes('text/markdown')) {
|
||||
const mdPath = pathname.replace(/\/?$/, '.md');
|
||||
return new URL(mdPath, request.url);
|
||||
}
|
||||
|
||||
const response = await context.next();
|
||||
|
||||
const contentType = response.headers.get('content-type') || '';
|
||||
if (!contentType.includes('text/html')) {
|
||||
return response;
|
||||
}
|
||||
|
||||
const mdPath = pathname.replace(/\/?$/, '.md');
|
||||
|
||||
const linkHeader = [
|
||||
`<${mdPath}>; rel="alternate"; type="text/markdown"`,
|
||||
`</docs/llms.txt>; rel="alternate"; type="text/markdown"; title="LLM Index"`,
|
||||
`</docs/llms-full.txt>; rel="alternate"; type="text/markdown"; title="Full Documentation"`,
|
||||
].join(', ');
|
||||
|
||||
// Netlify responses are immutable
|
||||
const newHeaders = new Headers(response.headers);
|
||||
newHeaders.set('Link', linkHeader);
|
||||
|
||||
return new Response(response.body, {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
headers: newHeaders,
|
||||
});
|
||||
}
|
||||
|
||||
export const config = {
|
||||
path: ['/docs/*'],
|
||||
};
|
||||
@@ -0,0 +1,103 @@
|
||||
import type { Context } from 'https://edge.netlify.com';
|
||||
|
||||
// Configuration - set these in Netlify environment variables
|
||||
const GA_MEASUREMENT_ID =
|
||||
Netlify.env.get('GA_MEASUREMENT_ID') || 'G-XXXXXXXXXX';
|
||||
const GA_API_SECRET = Netlify.env.get('GA_API_SECRET') || '';
|
||||
|
||||
function getClientId(request: Request): string {
|
||||
// Try to extract existing GA client ID from cookie
|
||||
const cookies = request.headers.get('cookie') || '';
|
||||
const gaMatch = cookies.match(/_ga=GA\d+\.\d+\.(\d+\.\d+)/);
|
||||
if (gaMatch) {
|
||||
return gaMatch[1];
|
||||
}
|
||||
|
||||
// Generate a new client ID for this request
|
||||
// For non-browser clients (AI tools), this creates a session-based ID
|
||||
const timestamp = Date.now();
|
||||
const random = Math.floor(Math.random() * 1000000000);
|
||||
return `${random}.${timestamp}`;
|
||||
}
|
||||
|
||||
async function sendToGA4(
|
||||
request: Request,
|
||||
context: Context,
|
||||
pathname: string
|
||||
): Promise<void> {
|
||||
if (!GA_API_SECRET) {
|
||||
console.warn('GA_API_SECRET not configured, skipping analytics');
|
||||
return;
|
||||
}
|
||||
|
||||
const clientId = getClientId(request);
|
||||
const userAgent = request.headers.get('user-agent') || 'unknown';
|
||||
|
||||
// Detect AI tools from user agent
|
||||
const isAITool =
|
||||
/bot|crawler|spider|gpt|claude|anthropic|openai|perplexity|cohere/i.test(
|
||||
userAgent
|
||||
);
|
||||
|
||||
const payload = {
|
||||
client_id: clientId,
|
||||
events: [
|
||||
{
|
||||
name: 'page_view',
|
||||
params: {
|
||||
page_location: request.url,
|
||||
page_title: pathname,
|
||||
page_path: pathname,
|
||||
// Custom parameters for filtering
|
||||
file_extension: pathname.substring(pathname.lastIndexOf('.')),
|
||||
user_agent: userAgent,
|
||||
is_ai_tool: isAITool ? 'true' : 'false',
|
||||
country: context.geo?.country?.code || 'unknown',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
console.log(`Tracked asset path: ${pathname}`);
|
||||
|
||||
const endpoint = `https://www.google-analytics.com/mp/collect?measurement_id=${GA_MEASUREMENT_ID}&api_secret=${GA_API_SECRET}`;
|
||||
|
||||
try {
|
||||
await fetch(endpoint, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
} catch (error) {
|
||||
// Log but don't fail the request
|
||||
console.error('Failed to send to GA4:', error);
|
||||
}
|
||||
}
|
||||
|
||||
export default async function handler(
|
||||
request: Request,
|
||||
context: Context
|
||||
): Promise<Response> {
|
||||
const url = new URL(request.url);
|
||||
const pathname = url.pathname;
|
||||
|
||||
// Send analytics in background (non-blocking)
|
||||
context.waitUntil(sendToGA4(request, context, pathname));
|
||||
|
||||
// Continue to serve the actual file
|
||||
const response = await context.next();
|
||||
|
||||
// Netlify Edge Function responses are immutable, so create a new Response
|
||||
const newHeaders = new Headers(response.headers);
|
||||
newHeaders.set('x-nx-edge-function', 'track-asset-requests');
|
||||
|
||||
return new Response(response.body, {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
headers: newHeaders,
|
||||
});
|
||||
}
|
||||
|
||||
export const config = {
|
||||
// Track all .txt and .md requests for AI/LLM usage analytics
|
||||
path: ['/*.txt', '/**/*.txt', '/*.md', '/**/*.md'],
|
||||
};
|
||||
@@ -144,6 +144,78 @@
|
||||
window.twq('config', 'obtp4');
|
||||
};
|
||||
|
||||
// Scroll depth tracking
|
||||
const SCROLL_THRESHOLDS = [10, 25, 50, 75, 90];
|
||||
let firedThresholds = new Set();
|
||||
let scrollTrackingEnabled = false;
|
||||
let scrollRafId = null;
|
||||
|
||||
function getScrollPercentage() {
|
||||
const scrollTop = window.scrollY || document.documentElement.scrollTop;
|
||||
const scrollHeight = document.documentElement.scrollHeight;
|
||||
const clientHeight = window.innerHeight;
|
||||
return (scrollTop + clientHeight) / scrollHeight;
|
||||
}
|
||||
|
||||
function handleScrollTracking() {
|
||||
if (!scrollTrackingEnabled) return;
|
||||
|
||||
const scrollPercentage = getScrollPercentage() * 100;
|
||||
|
||||
// Fire events for all thresholds we've passed but haven't fired yet
|
||||
for (const threshold of SCROLL_THRESHOLDS) {
|
||||
if (scrollPercentage >= threshold && !firedThresholds.has(threshold)) {
|
||||
firedThresholds.add(threshold);
|
||||
sendSearchEvent(`scroll_${threshold}`, {
|
||||
event_category: 'scroll',
|
||||
event_label: window.location.pathname,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function throttledScrollHandler() {
|
||||
if (scrollRafId !== null) return;
|
||||
|
||||
scrollRafId = requestAnimationFrame(() => {
|
||||
handleScrollTracking();
|
||||
scrollRafId = null;
|
||||
});
|
||||
}
|
||||
|
||||
function attachScrollListener() {
|
||||
window.addEventListener('scroll', throttledScrollHandler, {
|
||||
passive: true,
|
||||
});
|
||||
}
|
||||
|
||||
function setupScrollTracking() {
|
||||
// Reset scroll depth on navigation (for SPA-like behavior via View Transitions)
|
||||
firedThresholds = new Set();
|
||||
scrollTrackingEnabled = false;
|
||||
|
||||
// Delay tracking start to avoid false triggers during navigation
|
||||
setTimeout(() => {
|
||||
scrollTrackingEnabled = true;
|
||||
// Immediately check current scroll position to capture thresholds
|
||||
// that may have been passed during the delay
|
||||
handleScrollTracking();
|
||||
}, 500);
|
||||
|
||||
attachScrollListener();
|
||||
|
||||
// Handle Astro View Transitions - reset on navigation
|
||||
document.addEventListener('astro:after-swap', () => {
|
||||
firedThresholds = new Set();
|
||||
scrollTrackingEnabled = false;
|
||||
setTimeout(() => {
|
||||
scrollTrackingEnabled = true;
|
||||
// Immediately check current scroll position after navigation
|
||||
handleScrollTracking();
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
|
||||
const SEARCH_DEBOUNCE_MS = 1000;
|
||||
let searchDebounceTimer;
|
||||
let lastSearchQuery = '';
|
||||
@@ -209,12 +281,14 @@
|
||||
loadGTM();
|
||||
loadHubSpot();
|
||||
setupSearchTracking();
|
||||
setupScrollTracking();
|
||||
} else if (window.Cookiebot && window.Cookiebot.consent) {
|
||||
// Statistics cookies (Google Analytics, GTM, Search Tracking)
|
||||
// Statistics cookies (Google Analytics, GTM, Search, Scroll Tracking)
|
||||
if (window.Cookiebot.consent.statistics) {
|
||||
loadGoogleAnalytics();
|
||||
loadGTM();
|
||||
setupSearchTracking();
|
||||
setupScrollTracking();
|
||||
}
|
||||
|
||||
// Marketing cookies (HubSpot, Apollo, Hotjar, Twitter)
|
||||
|
||||
@@ -122,6 +122,33 @@ steps:
|
||||
|
||||
{% /tabitem %}
|
||||
|
||||
{% tabitem label="Bitbucket Pipelines" %}
|
||||
|
||||
```yaml
|
||||
# bitbucket-pipelines.yml
|
||||
image: node:22
|
||||
|
||||
pipelines:
|
||||
pull-requests:
|
||||
'**':
|
||||
- step:
|
||||
name: CI
|
||||
script:
|
||||
# Your existing steps which start-ci-run, install
|
||||
# dependencies, etc.
|
||||
# These are just illustrative examples...
|
||||
- npx nx-cloud start-ci-run
|
||||
- npm ci
|
||||
- npx nx affected -t lint test build
|
||||
after-script:
|
||||
# NEW: Add this section at the end of your step
|
||||
# IMPORTANT: after-script runs regardless of step success/failure
|
||||
# so it's like if: always() on GitHub
|
||||
- npx nx fix-ci
|
||||
```
|
||||
|
||||
{% /tabitem %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
> NOTE: If all tasks succeed then the `fix-ci` command becomes a no-op automatically, so that is why "always" is recommended.
|
||||
@@ -182,31 +209,62 @@ Tasks matching these patterns will also have high-confidence, verified code chan
|
||||
|
||||
Tasks matching these patterns will **never** have code changes auto-applied, even if they match the include patterns or presets specified above. For example: `*e2e*`.
|
||||
|
||||
## Customization with CLAUDE.md
|
||||
## Configuration with SELF_HEALING.md
|
||||
|
||||
Create a `CLAUDE.md` file in your repository root to provide additional context to the AI agent:
|
||||
Create a `.nx/SELF_HEALING.md` file in your repository to provide project-specific instructions to the Self-Healing CI agent. This file contains freeform markdown that the AI agent reads and interprets naturally.
|
||||
|
||||
### Failure Classification Rules
|
||||
{% aside title="Why a dedicated file?" type="note" %}
|
||||
Using `.nx/SELF_HEALING.md` instead of `AGENTS.md` (or equivalent) separates CI-specific instructions from local development context. The file lives in the `.nx` directory alongside other Nx Cloud configuration.
|
||||
{% /aside %}
|
||||
|
||||
Override how the AI categorizes failures:
|
||||
### Example SELF_HEALING.md
|
||||
|
||||
```markdown
|
||||
## Failure Classification
|
||||
# Self-Healing Configuration
|
||||
|
||||
- Failures in `**/migrations/**` should be classified as `environment_state`
|
||||
- Test timeouts in e2e tests are usually `flaky_task`
|
||||
## Confidence Rules
|
||||
|
||||
- Fixes involving "test" targets should require high confidence
|
||||
- Formatting fixes can be applied with medium confidence
|
||||
|
||||
## Off-Limits Areas
|
||||
|
||||
- `/src/generated/` - auto-generated, do not modify
|
||||
- `/legacy/` - requires manual review
|
||||
|
||||
## Fix Preferences
|
||||
|
||||
- Prefer updating ESLint rules over adding disable comments
|
||||
- For type errors, prefer explicit types over `any`
|
||||
|
||||
## Context
|
||||
|
||||
See ARCHITECTURE.md for module boundaries.
|
||||
```
|
||||
|
||||
### Predefined Fixes
|
||||
### What to Include
|
||||
|
||||
Specify deterministic solutions for common failures:
|
||||
| Section | Purpose | Example |
|
||||
| -------------------- | --------------------------------------------------- | ---------------------------------------------------------------------------- |
|
||||
| **Confidence Rules** | Override how the AI categorizes failure severity | "Failures in `**/migrations/**` should be classified as `environment_state`" |
|
||||
| **Off-Limits Areas** | Directories or files the agent should never modify | "`/src/generated/` - auto-generated code" |
|
||||
| **Fix Preferences** | Guide the agent's approach to common issues | "Prefer updating ESLint rules over adding disable comments" |
|
||||
| **Predefined Fixes** | Specify deterministic solutions for known failures | "For lint failures, always try running `nx lint --fix` first" |
|
||||
| **Context** | Reference other documentation the agent should read | "See ARCHITECTURE.md for module boundaries" |
|
||||
|
||||
```markdown
|
||||
## Predefined Fixes
|
||||
### Using CLAUDE.md
|
||||
|
||||
- For lint failures, always try running `nx lint --fix` first
|
||||
- Format failures should use `nx format:write`
|
||||
```
|
||||
If your repository already has a `CLAUDE.md` file at the root, the Self-Healing CI agent will read it for additional context. When both files exist:
|
||||
|
||||
- **SELF_HEALING.md takes precedence** for any conflicting instructions
|
||||
- Both files are read, so general context in `CLAUDE.md` is still available
|
||||
- CI-specific instructions should go in `SELF_HEALING.md`
|
||||
|
||||
This allows teams to maintain `CLAUDE.md` for local development workflows while using `SELF_HEALING.md` for CI-specific behavior.
|
||||
|
||||
### Viewing Configuration Status
|
||||
|
||||
After a CI run, navigate to the pipeline execution in Nx Cloud and check the **Configurations** tab to see whether `SELF_HEALING.md` was detected and applied.
|
||||
|
||||
## Receiving Fix Notifications
|
||||
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
import type { APIRoute } from 'astro';
|
||||
import { getCollection } from 'astro:content';
|
||||
import { readFileSync, existsSync } from 'node:fs';
|
||||
import { join, dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const contentDocsDir = join(__dirname, '../content/docs');
|
||||
|
||||
interface DocEntry {
|
||||
slug: string;
|
||||
title: string;
|
||||
content: string;
|
||||
section: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips YAML frontmatter from markdown content.
|
||||
* Frontmatter is delimited by --- at the start of the file.
|
||||
*/
|
||||
function stripFrontmatter(content: string): string {
|
||||
// Match frontmatter: starts with ---, ends with ---
|
||||
const frontmatterRegex = /^---\r?\n[\s\S]*?\r?\n---\r?\n?/;
|
||||
return content.replace(frontmatterRegex, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates llms-full.txt - a concatenated file of all Nx documentation.
|
||||
* This file contains the full content of all docs for LLM consumption.
|
||||
* See: https://llmstxt.org/
|
||||
*/
|
||||
export const GET: APIRoute = async ({ site }) => {
|
||||
const siteUrl = site?.origin ?? 'https://nx.dev';
|
||||
const entries: DocEntry[] = [];
|
||||
|
||||
// Preferred section order (same as llms.txt)
|
||||
const sectionOrder = [
|
||||
'quickstart',
|
||||
'getting-started',
|
||||
'concepts',
|
||||
'features',
|
||||
'guides',
|
||||
'extending-nx',
|
||||
'technologies',
|
||||
'reference',
|
||||
'enterprise',
|
||||
'troubleshooting',
|
||||
];
|
||||
|
||||
// Section display names
|
||||
const sectionNames: Record<string, string> = {
|
||||
'getting-started': 'Getting Started',
|
||||
concepts: 'Core Concepts',
|
||||
features: 'Features',
|
||||
guides: 'Guides',
|
||||
'extending-nx': 'Extending Nx',
|
||||
technologies: 'Technologies',
|
||||
reference: 'Reference',
|
||||
enterprise: 'Enterprise',
|
||||
troubleshooting: 'Troubleshooting',
|
||||
quickstart: 'Quickstart',
|
||||
};
|
||||
|
||||
// Get all docs from the content collection (static .mdoc/.mdx files)
|
||||
const docs = await getCollection('docs');
|
||||
|
||||
for (const doc of docs) {
|
||||
const slug = doc.id;
|
||||
const title = doc.data.title || slug.split('/').pop() || slug;
|
||||
const section = slug.split('/')[0] || 'other';
|
||||
|
||||
// Try to get file path from doc.filePath, or try common extensions
|
||||
let filePath = doc.filePath;
|
||||
if (!filePath) {
|
||||
const extensions = ['.mdoc', '.mdx', '.md'];
|
||||
for (const ext of extensions) {
|
||||
const testPath = join(contentDocsDir, doc.id + ext);
|
||||
if (existsSync(testPath)) {
|
||||
filePath = testPath;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Skip if no file path found or not readable
|
||||
if (!filePath || !existsSync(filePath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
const rawContent = readFileSync(filePath, 'utf-8');
|
||||
const content = stripFrontmatter(rawContent);
|
||||
entries.push({ slug, title, content, section });
|
||||
} catch {
|
||||
// Skip files that can't be read
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Get plugin docs (executors, generators for each plugin)
|
||||
try {
|
||||
const pluginDocs = await getCollection('plugin-docs');
|
||||
for (const doc of pluginDocs) {
|
||||
if (doc.data.slug && doc.body) {
|
||||
const slug = doc.data.slug;
|
||||
const section = slug.split('/')[0] || 'technologies';
|
||||
entries.push({
|
||||
slug,
|
||||
title: doc.data.title || slug,
|
||||
content: stripFrontmatter(doc.body),
|
||||
section,
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// plugin-docs collection might not exist
|
||||
}
|
||||
|
||||
// Note: Excluding nx-reference-packages (devkit API docs) for now
|
||||
// to keep the file size under 2MB. These are highly technical
|
||||
// and can be accessed individually via .md endpoints.
|
||||
|
||||
// Sort entries by section order, then by slug within section
|
||||
entries.sort((a, b) => {
|
||||
const sectionIndexA = sectionOrder.indexOf(a.section);
|
||||
const sectionIndexB = sectionOrder.indexOf(b.section);
|
||||
const orderA = sectionIndexA === -1 ? 999 : sectionIndexA;
|
||||
const orderB = sectionIndexB === -1 ? 999 : sectionIndexB;
|
||||
|
||||
if (orderA !== orderB) {
|
||||
return orderA - orderB;
|
||||
}
|
||||
return a.slug.localeCompare(b.slug);
|
||||
});
|
||||
|
||||
// Generate the llms-full.txt content
|
||||
const lines: string[] = [
|
||||
'# Nx Documentation',
|
||||
'',
|
||||
'> Complete Nx documentation compiled into a single file for LLM consumption.',
|
||||
'',
|
||||
'Nx is a powerful, open source, technology-agnostic build platform designed to efficiently manage codebases of any scale. From small single projects to large enterprise monorepos, Nx provides intelligent task execution, caching, and CI optimization.',
|
||||
'',
|
||||
`This file was generated from ${entries.length} documentation pages.`,
|
||||
`Individual pages are available at: ${siteUrl}/docs/{slug}.md`,
|
||||
'',
|
||||
];
|
||||
|
||||
// Track current section for headers
|
||||
let currentSection = '';
|
||||
|
||||
for (const entry of entries) {
|
||||
// Add section header when section changes
|
||||
if (entry.section !== currentSection) {
|
||||
currentSection = entry.section;
|
||||
const sectionName = sectionNames[currentSection] || currentSection;
|
||||
lines.push('');
|
||||
lines.push(`# ${sectionName}`);
|
||||
lines.push('');
|
||||
}
|
||||
|
||||
// URL encode spaces in the slug
|
||||
const encodedSlug = entry.slug.replace(/ /g, '%20');
|
||||
const sourceUrl = `${siteUrl}/docs/${encodedSlug}.md`;
|
||||
|
||||
lines.push('---');
|
||||
lines.push(`<!-- source: ${sourceUrl} -->`);
|
||||
lines.push(`## ${entry.title}`);
|
||||
lines.push('');
|
||||
lines.push(entry.content.trim());
|
||||
lines.push('');
|
||||
}
|
||||
|
||||
const content = lines.join('\n');
|
||||
|
||||
return new Response(content, {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'text/markdown; charset=utf-8',
|
||||
'Cache-Control': 'public, max-age=3600',
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -237,7 +237,11 @@ describe('nx release - independent projects', () => {
|
||||
const versionWithGitActionsCLIOutput = runCLI(
|
||||
`release version 999.9.9-version-git-operations-test.2 -p ${pkg1} --git-commit --git-tag --verbose` // add verbose so we get richer output
|
||||
);
|
||||
expect(versionWithGitActionsCLIOutput).toMatchInlineSnapshot(`
|
||||
const filteredOutput = versionWithGitActionsCLIOutput.replace(
|
||||
/\[plugin-(pool|worker)\].*\n/g,
|
||||
''
|
||||
);
|
||||
expect(filteredOutput).toMatchInlineSnapshot(`
|
||||
|
||||
NX Your filter "{project-name}" matched the following projects:
|
||||
|
||||
@@ -320,7 +324,11 @@ describe('nx release - independent projects', () => {
|
||||
const versionWithGitActionsConfigOutput = runCLI(
|
||||
`release version 999.9.9-version-git-operations-test.3 --verbose --gitTag` // add verbose so we get richer output
|
||||
);
|
||||
expect(versionWithGitActionsConfigOutput).toMatchInlineSnapshot(`
|
||||
const filteredConfigOutput = versionWithGitActionsConfigOutput.replace(
|
||||
/\[plugin-(pool|worker)\].*\n/g,
|
||||
''
|
||||
);
|
||||
expect(filteredConfigOutput).toMatchInlineSnapshot(`
|
||||
|
||||
NX Running release version for project: {project-name}
|
||||
|
||||
@@ -516,7 +524,11 @@ describe('nx release - independent projects', () => {
|
||||
const versionWithGitActionsCLIOutput = runCLI(
|
||||
`release changelog 999.9.9-changelog-git-operations-test.1 -p ${pkg1} --verbose`
|
||||
);
|
||||
expect(versionWithGitActionsCLIOutput).toMatchInlineSnapshot(`
|
||||
const filteredChangelogOutput = versionWithGitActionsCLIOutput.replace(
|
||||
/\[plugin-(pool|worker)\].*\n/g,
|
||||
''
|
||||
);
|
||||
expect(filteredChangelogOutput).toMatchInlineSnapshot(`
|
||||
|
||||
NX Your filter "{project-name}" matched the following projects:
|
||||
|
||||
|
||||
@@ -54,6 +54,8 @@ expect.addSnapshotSerializer({
|
||||
.replaceAll('pnpm install --lockfile-only', '{lock-file-command}')
|
||||
.replaceAll(getSelectedPackageManager(), '{package-manager}')
|
||||
.replaceAll(e2eRegistryUrl, '{registryUrl}')
|
||||
// Filter out plugin worker verbose logs
|
||||
.replaceAll(/\[plugin-(pool|worker)\].*\n/g, '')
|
||||
// We trim each line to reduce the chances of snapshot flakiness
|
||||
.split('\n')
|
||||
.map((r) => r.trim())
|
||||
|
||||
@@ -47,6 +47,8 @@ expect.addSnapshotSerializer({
|
||||
/Integrity:\s*.*/g,
|
||||
'Integrity: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
|
||||
)
|
||||
// Filter out plugin worker verbose logs
|
||||
.replaceAll(/\[plugin-(pool|worker)\].*\n/g, '')
|
||||
|
||||
.split('\n')
|
||||
.map((r) => r.trim())
|
||||
|
||||
@@ -32,6 +32,8 @@ expect.addSnapshotSerializer({
|
||||
.replaceAll(/Test @[\w\d]+/g, 'Test @{COMMIT_AUTHOR}')
|
||||
// Normalize the version title date.
|
||||
.replaceAll(/\(\d{4}-\d{2}-\d{2}\)/g, '(YYYY-MM-DD)')
|
||||
// Filter out plugin worker verbose logs
|
||||
.replaceAll(/\[plugin-(pool|worker)\].*\n/g, '')
|
||||
// We trim each line to reduce the chances of snapshot flakiness
|
||||
.split('\n')
|
||||
.map((r) => r.trim())
|
||||
|
||||
@@ -29,6 +29,8 @@ expect.addSnapshotSerializer({
|
||||
.replaceAll(/Test @[\w\d]+/g, 'Test @{COMMIT_AUTHOR}')
|
||||
// Normalize the version title date.
|
||||
.replaceAll(/\(\d{4}-\d{2}-\d{2}\)/g, '(YYYY-MM-DD)')
|
||||
// Filter out plugin worker verbose logs
|
||||
.replaceAll(/\[plugin-(pool|worker)\].*\n/g, '')
|
||||
// We trim each line to reduce the chances of snapshot flakiness
|
||||
.split('\n')
|
||||
.map((r) => r.trim())
|
||||
|
||||
@@ -136,7 +136,7 @@ export function FeedContainer(): JSX.Element {
|
||||
<div
|
||||
className={cx(
|
||||
'left0 fixed bottom-0 right-0 w-full px-4 py-4 lg:px-0 lg:py-6',
|
||||
'bg-gradient-to-t from-white via-white/75 dark:from-slate-900 dark:via-slate-900/75'
|
||||
'bg-gradient-to-t from-white via-white/75 dark:from-zinc-900 dark:via-zinc-900/75'
|
||||
)}
|
||||
>
|
||||
<Prompt
|
||||
|
||||
@@ -51,7 +51,7 @@ export function FeedAnswer({
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="grid h-12 w-12 items-center justify-center rounded-full bg-white text-slate-900 ring-1 ring-slate-200 dark:bg-slate-900 dark:text-white dark:ring-slate-700">
|
||||
<div className="grid h-12 w-12 items-center justify-center rounded-full bg-white text-zinc-900 ring-1 ring-zinc-200 dark:bg-zinc-900 dark:text-white dark:ring-zinc-700">
|
||||
<svg
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
@@ -65,23 +65,20 @@ export function FeedAnswer({
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div>
|
||||
<div className="flex items-center gap-2 text-lg text-slate-900 dark:text-slate-100">
|
||||
<div className="flex items-center gap-2 text-lg text-zinc-900 dark:text-zinc-100">
|
||||
Nx Assistant
|
||||
</div>
|
||||
<p className="mt-0.5 flex items-center gap-x-1 text-sm text-slate-500">
|
||||
<ChatGptLogo
|
||||
className="h-4 w-4 text-slate-400"
|
||||
aria-hidden="true"
|
||||
/>{' '}
|
||||
<p className="mt-0.5 flex items-center gap-x-1 text-sm text-zinc-500">
|
||||
<ChatGptLogo className="h-4 w-4 text-zinc-400" aria-hidden="true" />{' '}
|
||||
AI powered
|
||||
</p>
|
||||
</div>
|
||||
<div className="prose prose-slate dark:prose-invert mt-2 w-full max-w-none 2xl:max-w-4xl">
|
||||
<div className="prose prose-zinc dark:prose-invert mt-2 w-full max-w-none 2xl:max-w-4xl">
|
||||
{!isFirst && callout}
|
||||
{renderMarkdown(normalizedContent, { filePath: '' }).node}
|
||||
</div>
|
||||
{!isFirst && (
|
||||
<div className="text-md group flex-1 gap-4 text-slate-400 transition hover:text-slate-500 md:flex md:items-center md:justify-end">
|
||||
<div className="text-md group flex-1 gap-4 text-zinc-400 transition hover:text-zinc-500 md:flex md:items-center md:justify-end">
|
||||
{feedbackStatement ? (
|
||||
<p className="italic group-hover:flex">
|
||||
{feedbackStatement === 'good'
|
||||
@@ -96,7 +93,7 @@ export function FeedAnswer({
|
||||
<div className="flex gap-4">
|
||||
<button
|
||||
className={cx(
|
||||
'p-1 transition-all hover:rotate-12 hover:text-blue-500 disabled:cursor-not-allowed dark:hover:text-sky-500',
|
||||
'p-1 transition-all hover:rotate-12 hover:text-blue-500 disabled:cursor-not-allowed dark:hover:text-blue-500',
|
||||
{ 'text-blue-500': feedbackStatement === 'bad' }
|
||||
)}
|
||||
disabled={!!feedbackStatement}
|
||||
@@ -108,7 +105,7 @@ export function FeedAnswer({
|
||||
</button>
|
||||
<button
|
||||
className={cx(
|
||||
'p-1 transition-all hover:rotate-12 hover:text-blue-500 disabled:cursor-not-allowed dark:hover:text-sky-500',
|
||||
'p-1 transition-all hover:rotate-12 hover:text-blue-500 disabled:cursor-not-allowed dark:hover:text-blue-500',
|
||||
{ 'text-blue-500': feedbackStatement === 'good' }
|
||||
)}
|
||||
disabled={!!feedbackStatement}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export function FeedQuestion({ content }: { content: string }) {
|
||||
return (
|
||||
<div className="flex w-full justify-end">
|
||||
<p className="whitespace-pre-wrap break-words rounded-lg bg-blue-500 px-4 py-2 text-base text-white selection:bg-sky-900 dark:bg-sky-500">
|
||||
<p className="whitespace-pre-wrap break-words rounded-lg bg-blue-500 px-4 py-2 text-base text-white selection:bg-blue-900 dark:bg-blue-500">
|
||||
{content}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export function LoadingState(): JSX.Element {
|
||||
return (
|
||||
<div className="flex w-full items-center justify-center gap-4 px-4 py-2 text-blue-500 transition duration-150 ease-in-out dark:text-sky-500">
|
||||
<div className="flex w-full items-center justify-center gap-4 px-4 py-2 text-blue-500 transition duration-150 ease-in-out dark:text-blue-500">
|
||||
<svg
|
||||
className="h-5 w-5 animate-spin"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
||||
@@ -62,7 +62,7 @@ export function Prompt({
|
||||
<form
|
||||
ref={formRef}
|
||||
onSubmit={handleSubmit}
|
||||
className="relative mx-auto flex max-w-3xl gap-2 rounded-md border border-slate-300 bg-white px-2 py-2 shadow-lg dark:border-slate-900 dark:bg-slate-700"
|
||||
className="relative mx-auto flex max-w-3xl gap-2 rounded-md border border-zinc-300 bg-white px-2 py-2 shadow-lg dark:border-zinc-900 dark:bg-zinc-700"
|
||||
>
|
||||
<div
|
||||
className={cx(
|
||||
@@ -74,7 +74,7 @@ export function Prompt({
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="small"
|
||||
className={cx('bg-white dark:bg-slate-900')}
|
||||
className={cx('bg-white dark:bg-zinc-900')}
|
||||
onClick={handleStopGenerating}
|
||||
>
|
||||
<StopIcon aria-hidden="true" className="h-5 w-5" />
|
||||
@@ -85,7 +85,7 @@ export function Prompt({
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="small"
|
||||
className={cx('bg-white dark:bg-slate-900')}
|
||||
className={cx('bg-white dark:bg-zinc-900')}
|
||||
onClick={handleNewChat}
|
||||
>
|
||||
<XMarkIcon aria-hidden="true" className="h-5 w-5" />
|
||||
@@ -96,7 +96,7 @@ export function Prompt({
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="small"
|
||||
className={cx('bg-white dark:bg-slate-900')}
|
||||
className={cx('bg-white dark:bg-zinc-900')}
|
||||
onClick={onRegenerate}
|
||||
>
|
||||
<ArrowPathIcon aria-hidden="true" className="h-5 w-5" />
|
||||
@@ -123,14 +123,14 @@ export function Prompt({
|
||||
name="query"
|
||||
maxLength={500}
|
||||
disabled={isGenerating}
|
||||
className="block w-full resize-none border-none bg-transparent p-0 py-3 pl-2 text-sm placeholder-slate-500 focus-within:outline-none focus:placeholder-slate-400 focus:outline-none focus:ring-0 disabled:cursor-not-allowed dark:text-white dark:focus:placeholder-slate-300"
|
||||
className="block w-full resize-none border-none bg-transparent p-0 py-3 pl-2 text-sm placeholder-zinc-500 focus-within:outline-none focus:placeholder-zinc-400 focus:outline-none focus:ring-0 disabled:cursor-not-allowed dark:text-white dark:focus:placeholder-zinc-300"
|
||||
placeholder="How does caching work?"
|
||||
rows={1}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex">
|
||||
<Button
|
||||
variant="primary"
|
||||
variant="contrast"
|
||||
size="small"
|
||||
type="submit"
|
||||
disabled={isGenerating}
|
||||
|
||||
@@ -2,16 +2,16 @@ import { InformationCircleIcon } from '@heroicons/react/24/outline';
|
||||
|
||||
export function ActivityLimitReached(): JSX.Element {
|
||||
return (
|
||||
<div className="rounded-md bg-slate-50 p-4 shadow-sm ring-1 ring-slate-100 dark:bg-slate-800/40 dark:ring-slate-700">
|
||||
<div className="rounded-md bg-zinc-50 p-4 shadow-sm ring-1 ring-zinc-100 dark:bg-zinc-800/40 dark:ring-zinc-700">
|
||||
<div className="flex">
|
||||
<div className="flex-shrink-0">
|
||||
<InformationCircleIcon
|
||||
className="h-5 w-5 text-slate-500 dark:text-slate-300"
|
||||
className="h-5 w-5 text-zinc-500 dark:text-zinc-300"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
<div className="ml-3 flex-1 md:flex md:justify-between">
|
||||
<p className="text-sm text-slate-700 dark:text-slate-400">
|
||||
<p className="text-sm text-zinc-700 dark:text-zinc-400">
|
||||
You've reached the maximum message history limit. Previous messages
|
||||
will be removed.
|
||||
</p>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ReactNode } from 'react';
|
||||
export function SidebarContainer({ children }: { children: ReactNode[] }) {
|
||||
return (
|
||||
<div id="sidebar" data-testid="sidebar">
|
||||
<div className="hidden h-full w-72 flex-col border-r border-slate-200 md:flex dark:border-slate-700 dark:bg-slate-900">
|
||||
<div className="hidden h-full w-72 flex-col border-r border-zinc-200 md:flex dark:border-zinc-700 dark:bg-zinc-900">
|
||||
<div className="relative flex flex-col gap-4 overflow-y-scroll p-4">
|
||||
{...children}
|
||||
</div>
|
||||
|
||||
@@ -4,17 +4,11 @@ import { useEffect, useRef, useCallback } from 'react';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { sendCustomEvent } from './google-analytics';
|
||||
|
||||
function getScrollDepth(pct: number): 0 | 25 | 50 | 75 | 90 {
|
||||
if (pct >= 0.9) return 90;
|
||||
if (pct < 0.25) return 0;
|
||||
if (pct < 0.5) return 25;
|
||||
if (pct < 0.75) return 50;
|
||||
return 75;
|
||||
}
|
||||
const SCROLL_THRESHOLDS = [10, 25, 50, 75, 90] as const;
|
||||
|
||||
export function useWindowScrollDepth(): void {
|
||||
const pathname = usePathname();
|
||||
const scrollDepth = useRef(0);
|
||||
const firedThresholds = useRef<Set<number>>(new Set());
|
||||
const shouldTrackScroll = useRef(true);
|
||||
const rafId = useRef<number | null>(null);
|
||||
|
||||
@@ -23,13 +17,19 @@ export function useWindowScrollDepth(): void {
|
||||
if (typeof window === 'undefined') return;
|
||||
|
||||
const scrollPercentage =
|
||||
(window.scrollY + window.innerHeight) /
|
||||
document.documentElement.scrollHeight;
|
||||
const depth = getScrollDepth(scrollPercentage);
|
||||
((window.scrollY + window.innerHeight) /
|
||||
document.documentElement.scrollHeight) *
|
||||
100;
|
||||
|
||||
if (depth > scrollDepth.current) {
|
||||
scrollDepth.current = depth;
|
||||
sendCustomEvent(`scroll_${depth}`, 'scroll', pathname || '/');
|
||||
// Fire events for all thresholds we've passed but haven't fired yet
|
||||
for (const threshold of SCROLL_THRESHOLDS) {
|
||||
if (
|
||||
scrollPercentage >= threshold &&
|
||||
!firedThresholds.current.has(threshold)
|
||||
) {
|
||||
firedThresholds.current.add(threshold);
|
||||
sendCustomEvent(`scroll_${threshold}`, 'scroll', pathname || '/');
|
||||
}
|
||||
}
|
||||
}, [pathname]);
|
||||
|
||||
@@ -46,12 +46,15 @@ export function useWindowScrollDepth(): void {
|
||||
shouldTrackScroll.current = false;
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
scrollDepth.current = 0;
|
||||
firedThresholds.current = new Set();
|
||||
shouldTrackScroll.current = true;
|
||||
// Immediately check current scroll position to capture thresholds
|
||||
// that may have been passed during the delay
|
||||
handleScroll();
|
||||
}, 500);
|
||||
|
||||
return () => clearTimeout(timeout);
|
||||
}, [pathname]);
|
||||
}, [pathname, handleScroll]);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window === 'undefined') return;
|
||||
|
||||
@@ -135,7 +135,7 @@ export function DocViewer({
|
||||
ref={ref}
|
||||
data-document="main"
|
||||
className={cx(
|
||||
'prose prose-slate dark:prose-invert w-full max-w-none 2xl:max-w-4xl',
|
||||
'prose prose-zinc dark:prose-invert w-full max-w-none 2xl:max-w-4xl',
|
||||
{ 'xl:max-w-2xl': !hideTableOfContent }
|
||||
)}
|
||||
>
|
||||
@@ -146,7 +146,7 @@ export function DocViewer({
|
||||
<div>
|
||||
<div
|
||||
className={cx(
|
||||
'sticky top-2 z-20 ml-[max(2rem,calc(50%-8rem))] hidden w-60 space-y-6 overflow-y-auto bg-white text-sm xl:block dark:bg-slate-900'
|
||||
'sticky top-2 z-20 ml-[max(2rem,calc(50%-8rem))] hidden w-60 space-y-6 overflow-y-auto bg-white text-sm xl:block dark:bg-zinc-900'
|
||||
)}
|
||||
>
|
||||
{widgetData.githubStarsCount > 0 && (
|
||||
@@ -163,18 +163,18 @@ export function DocViewer({
|
||||
document={document}
|
||||
>
|
||||
<>
|
||||
<div className="my-4 flex items-center justify-center space-x-2 rounded-md border border-slate-200 pl-2 pr-2 hover:border-slate-400 dark:border-slate-700 print:hidden">
|
||||
<div className="my-4 flex items-center justify-center space-x-2 rounded-md border border-zinc-200 pl-2 pr-2 hover:border-zinc-400 dark:border-zinc-700 print:hidden">
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Give feedback on this page"
|
||||
title="Give feedback of this page"
|
||||
className="whitespace-nowrap border-transparent px-4 py-2 font-bold hover:text-slate-900 dark:hover:text-sky-400"
|
||||
className="whitespace-nowrap border-transparent px-4 py-2 font-bold hover:text-zinc-900 dark:hover:text-blue-400"
|
||||
onClick={() => setShowFeedback(true)}
|
||||
>
|
||||
Feedback
|
||||
</button>
|
||||
</div>
|
||||
<div className="my-4 flex items-center justify-center space-x-2 rounded-md border border-slate-200 pl-2 pr-2 hover:border-slate-400 dark:border-slate-700 print:hidden">
|
||||
<div className="my-4 flex items-center justify-center space-x-2 rounded-md border border-zinc-200 pl-2 pr-2 hover:border-zinc-400 dark:border-zinc-700 print:hidden">
|
||||
{document.filePath ? (
|
||||
<a
|
||||
aria-hidden="true"
|
||||
@@ -190,7 +190,7 @@ export function DocViewer({
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
title="Edit this page on GitHub"
|
||||
className="whitespace-nowrap border-transparent px-4 py-2 font-bold hover:text-slate-900 dark:hover:text-sky-400"
|
||||
className="whitespace-nowrap border-transparent px-4 py-2 font-bold hover:text-zinc-900 dark:hover:text-blue-400"
|
||||
>
|
||||
Edit this page
|
||||
</a>
|
||||
@@ -207,7 +207,7 @@ export function DocViewer({
|
||||
<div
|
||||
data-document="related"
|
||||
className={cx(
|
||||
'prose prose-slate dark:prose-invert w-full max-w-none pt-8 2xl:max-w-4xl',
|
||||
'prose prose-zinc dark:prose-invert w-full max-w-none pt-8 2xl:max-w-4xl',
|
||||
{ 'xl:max-w-2xl': !hideTableOfContent }
|
||||
)}
|
||||
>
|
||||
@@ -221,7 +221,7 @@ export function DocViewer({
|
||||
hideTableOfContent ? '' : 'xl:hidden'
|
||||
}`}
|
||||
>
|
||||
<div className="ml-4 flex h-0.5 w-full flex-grow rounded bg-slate-50 dark:bg-slate-800/60" />
|
||||
<div className="ml-4 flex h-0.5 w-full flex-grow rounded bg-zinc-50 dark:bg-zinc-800/60" />
|
||||
<div className="relative z-0 inline-flex flex-shrink-0 rounded-md shadow-sm">
|
||||
<button
|
||||
type="button"
|
||||
@@ -230,7 +230,7 @@ export function DocViewer({
|
||||
className={`relative inline-flex items-center rounded-l-md ${
|
||||
// If there is no file path for this page then don't show edit button.
|
||||
document.filePath ? '' : 'rounded-r-md'
|
||||
}border border-slate-200 bg-white px-4 py-2 text-xs font-medium text-slate-600 focus-within:ring-blue-500 hover:bg-slate-50 focus:z-10 focus:outline-none focus:ring-1 dark:border-slate-700 dark:bg-slate-800/60 dark:text-slate-400 dark:focus-within:ring-sky-500 dark:hover:bg-slate-800`}
|
||||
}border border-zinc-200 bg-white px-4 py-2 text-xs font-medium text-zinc-600 focus-within:ring-blue-500 hover:bg-zinc-50 focus:z-10 focus:outline-none focus:ring-1 dark:border-zinc-700 dark:bg-zinc-800/60 dark:text-zinc-400 dark:focus-within:ring-blue-500 dark:hover:bg-zinc-800`}
|
||||
onClick={() => setShowFeedback(true)}
|
||||
>
|
||||
Feedback
|
||||
@@ -247,7 +247,7 @@ export function DocViewer({
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
title="Edit this page on GitHub"
|
||||
className="relative -ml-px inline-flex items-center rounded-r-md border border-slate-200 bg-white px-4 py-2 text-xs font-medium text-slate-600 focus-within:ring-blue-500 hover:bg-slate-50 focus:z-10 focus:outline-none focus:ring-1 dark:border-slate-700 dark:bg-slate-800/60 dark:text-slate-400 dark:focus-within:ring-sky-500 dark:hover:bg-slate-800"
|
||||
className="relative -ml-px inline-flex items-center rounded-r-md border border-zinc-200 bg-white px-4 py-2 text-xs font-medium text-zinc-600 focus-within:ring-blue-500 hover:bg-zinc-50 focus:z-10 focus:outline-none focus:ring-1 dark:border-zinc-700 dark:bg-zinc-800/60 dark:text-zinc-400 dark:focus-within:ring-blue-500 dark:hover:bg-zinc-800"
|
||||
>
|
||||
Edit this page
|
||||
</a>
|
||||
|
||||
@@ -40,12 +40,12 @@ const iconMap: { [key: string]: JSX.Element } = {
|
||||
|
||||
function CategoryBox({ category }: { category: RelatedDocumentsCategory }) {
|
||||
return (
|
||||
<div className="rounded-lg border border-slate-200 bg-white/60 p-5 dark:border-slate-800/40 dark:bg-slate-800/60">
|
||||
<div className="rounded-lg border border-zinc-200 bg-white/60 p-5 dark:border-zinc-800/40 dark:bg-zinc-800/60">
|
||||
<h4 className="mt-0 flex items-center pb-2 text-xl font-bold">
|
||||
{iconMap[category.id] ?? iconMap.default}
|
||||
{category.name}
|
||||
</h4>
|
||||
<ul className="list-none divide-y divide-slate-300 pl-0 dark:divide-slate-700">
|
||||
<ul className="list-none divide-y divide-zinc-300 pl-0 dark:divide-zinc-700">
|
||||
{category.relatedDocuments.map((d) => (
|
||||
<li
|
||||
key={d.id}
|
||||
@@ -53,11 +53,11 @@ function CategoryBox({ category }: { category: RelatedDocumentsCategory }) {
|
||||
>
|
||||
<Link
|
||||
href={d.path}
|
||||
className="flex flex-grow items-center justify-between no-underline transition-colors ease-out hover:text-blue-700 hover:underline dark:text-sky-500 dark:hover:text-sky-400"
|
||||
className="flex flex-grow items-center justify-between no-underline transition-colors ease-out hover:text-blue-700 hover:underline dark:text-blue-500 dark:hover:text-blue-400"
|
||||
prefetch={false}
|
||||
>
|
||||
<span>{d.name}</span>
|
||||
<ArrowRightIcon className="h-4 w-4 text-slate-500 dark:text-slate-400" />
|
||||
<ArrowRightIcon className="h-4 w-4 text-zinc-500 dark:text-zinc-400" />
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
|
||||
@@ -86,9 +86,9 @@ export function TableOfContents({
|
||||
<Link
|
||||
href={href}
|
||||
className={cx(
|
||||
'block w-full border-l-4 border-slate-200 py-1 pl-3 transition hover:border-slate-500 dark:border-slate-700/40 dark:hover:border-slate-700',
|
||||
'block w-full border-l-4 border-zinc-200 py-1 pl-3 transition hover:border-zinc-500 dark:border-zinc-700/40 dark:hover:border-zinc-700',
|
||||
{
|
||||
'border-slate-500 bg-slate-50 dark:border-slate-700 dark:bg-slate-800/60':
|
||||
'border-zinc-500 bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-800/60':
|
||||
activeId === item.id && !item.highlightColor,
|
||||
// region Highlight Color
|
||||
'border-blue-200 bg-blue-50 hover:border-blue-500 dark:border-blue-700/40 dark:bg-blue-800/40 dark:hover:border-blue-700':
|
||||
|
||||
@@ -93,10 +93,10 @@ function FeedbackDialog({
|
||||
leaveFrom="opacity-100 scale-100"
|
||||
leaveTo="opacity-0 scale-95"
|
||||
>
|
||||
<DialogPanel className="relative w-full max-w-2xl transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all dark:bg-slate-900">
|
||||
<DialogPanel className="relative w-full max-w-2xl transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all dark:bg-zinc-900">
|
||||
<DialogTitle
|
||||
as="h3"
|
||||
className="bg-white p-4 text-center text-lg font-medium leading-6 text-slate-700 dark:bg-slate-900 dark:text-slate-400"
|
||||
className="bg-white p-4 text-center text-lg font-medium leading-6 text-zinc-700 dark:bg-zinc-900 dark:text-zinc-400"
|
||||
>
|
||||
What is on your mind?
|
||||
<button className={styles.closebutton} onClick={closeDialog}>
|
||||
@@ -154,7 +154,7 @@ function FeedbackDialog({
|
||||
htmlFor="idea"
|
||||
tabIndex={0}
|
||||
onKeyDown={(e) => keydownHandler(e)}
|
||||
className="inline-flex w-full cursor-pointer items-center justify-between rounded-lg border border-gray-200 bg-white p-5 text-gray-500 hover:bg-slate-50 focus:outline-none focus:ring-1 peer-checked:border-sky-500 peer-checked:text-sky-500 dark:border-gray-700 dark:bg-gray-800 dark:text-slate-400 dark:focus-within:ring-sky-500 dark:hover:bg-slate-800 dark:hover:text-gray-300 dark:peer-checked:text-sky-500"
|
||||
className="inline-flex w-full cursor-pointer items-center justify-between rounded-lg border border-gray-200 bg-white p-5 text-gray-500 hover:bg-zinc-50 focus:outline-none focus:ring-1 peer-checked:border-blue-500 peer-checked:text-blue-500 dark:border-gray-700 dark:bg-gray-800 dark:text-zinc-400 dark:focus-within:ring-blue-500 dark:hover:bg-zinc-800 dark:hover:text-gray-300 dark:peer-checked:text-blue-500"
|
||||
>
|
||||
<div className="block">
|
||||
<div className="w-full text-lg font-semibold">Idea</div>
|
||||
@@ -242,10 +242,10 @@ function FeedbackDialog({
|
||||
onClick={submitFeedback}
|
||||
disabled={formDisabled}
|
||||
className={cx(
|
||||
'rounded-md border border-slate-200 bg-white px-4 py-2 text-base font-medium text-slate-600 dark:border-slate-700 dark:bg-slate-800/60 dark:text-slate-400',
|
||||
'rounded-md border border-zinc-200 bg-white px-4 py-2 text-base font-medium text-zinc-600 dark:border-zinc-700 dark:bg-zinc-800/60 dark:text-zinc-400',
|
||||
{ 'cursor-not-allowed': formDisabled },
|
||||
{
|
||||
'focus-within:ring-blue-500 hover:bg-slate-50 focus:z-10 focus:outline-none focus:ring-1 dark:focus-within:ring-sky-500 dark:hover:bg-slate-800':
|
||||
'focus-within:ring-blue-500 hover:bg-zinc-50 focus:z-10 focus:outline-none focus:ring-1 dark:focus-within:ring-blue-500 dark:hover:bg-zinc-800':
|
||||
!formDisabled,
|
||||
}
|
||||
)}
|
||||
|
||||
@@ -129,7 +129,7 @@ export function Content({
|
||||
<div
|
||||
aria-hidden="true"
|
||||
data-tooltip="Schema type"
|
||||
className="relative inline-flex rounded-md border border-slate-200 bg-slate-50 px-4 py-2 text-xs font-medium uppercase dark:border-slate-700 dark:bg-slate-800/60"
|
||||
className="relative inline-flex rounded-md border border-zinc-200 bg-zinc-50 px-4 py-2 text-xs font-medium uppercase dark:border-zinc-700 dark:bg-zinc-800/60"
|
||||
>
|
||||
{schemaViewModel.type}
|
||||
</div>
|
||||
@@ -157,7 +157,7 @@ export function Content({
|
||||
href={schemaViewModel.packageUrl}
|
||||
title="See package information"
|
||||
className={cx(
|
||||
'relative inline-flex items-center rounded-l-md border border-slate-200 bg-white px-4 py-2 text-xs font-medium text-slate-600 focus-within:ring-blue-500 hover:bg-slate-50 focus:z-10 focus:outline-none focus:ring-1 dark:border-slate-700 dark:bg-slate-800/60 dark:text-slate-400 dark:focus-within:ring-sky-500 dark:hover:bg-slate-800',
|
||||
'relative inline-flex items-center rounded-l-md border border-zinc-200 bg-white px-4 py-2 text-xs font-medium text-zinc-600 focus-within:ring-blue-500 hover:bg-zinc-50 focus:z-10 focus:outline-none focus:ring-1 dark:border-zinc-700 dark:bg-zinc-800/60 dark:text-zinc-400 dark:focus-within:ring-blue-500 dark:hover:bg-zinc-800',
|
||||
schemaViewModel.packageName.startsWith('@nx/powerpack')
|
||||
? 'rounded-md'
|
||||
: 'rounded-l-md'
|
||||
@@ -173,7 +173,7 @@ export function Content({
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
title="See this schema on GitHub"
|
||||
className="relative -ml-px inline-flex items-center rounded-r-md border border-slate-200 bg-white px-4 py-2 text-xs font-medium text-slate-600 focus-within:ring-blue-500 hover:bg-slate-50 focus:z-10 focus:outline-none focus:ring-1 dark:border-slate-700 dark:bg-slate-800/60 dark:text-slate-400 dark:focus-within:ring-sky-500 dark:hover:bg-slate-800"
|
||||
className="relative -ml-px inline-flex items-center rounded-r-md border border-zinc-200 bg-white px-4 py-2 text-xs font-medium text-zinc-600 focus-within:ring-blue-500 hover:bg-zinc-50 focus:z-10 focus:outline-none focus:ring-1 dark:border-zinc-700 dark:bg-zinc-800/60 dark:text-zinc-400 dark:focus-within:ring-blue-500 dark:hover:bg-zinc-800"
|
||||
>
|
||||
<svg
|
||||
className="mr-2 h-4 w-4"
|
||||
@@ -237,7 +237,7 @@ export function Content({
|
||||
{/* We remove the top description on sub property lookup */}
|
||||
{!schemaViewModel.subReference && (
|
||||
<>
|
||||
<div className="prose prose-slate dark:prose-invert max-w-none">
|
||||
<div className="prose prose-zinc dark:prose-invert max-w-none">
|
||||
{vm.markdown.header}
|
||||
{vm.markdown.customContent}
|
||||
{vm.markdown.usageAndExamples}
|
||||
@@ -269,7 +269,7 @@ export function Content({
|
||||
setPresets(p.keys);
|
||||
}}
|
||||
type="button"
|
||||
className="relative inline-flex items-center rounded-md border border-slate-200 bg-white px-4 py-2 text-xs font-medium text-slate-600 hover:bg-slate-50 dark:border-slate-700 dark:bg-slate-800/60 dark:text-slate-400 dark:hover:bg-slate-800"
|
||||
className="relative inline-flex items-center rounded-md border border-zinc-200 bg-white px-4 py-2 text-xs font-medium text-zinc-600 hover:bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-800/60 dark:text-zinc-400 dark:hover:bg-zinc-800"
|
||||
>
|
||||
{p.name}
|
||||
</button>
|
||||
@@ -278,7 +278,7 @@ export function Content({
|
||||
<button
|
||||
onClick={() => setPresets([])}
|
||||
type="button"
|
||||
className="relative inline-flex items-center rounded-md border border-slate-200 bg-white px-4 py-2 text-xs font-medium text-slate-600 hover:bg-slate-50 dark:border-slate-700 dark:bg-slate-800/60 dark:text-slate-400 dark:hover:bg-slate-800"
|
||||
className="relative inline-flex items-center rounded-md border border-zinc-200 bg-white px-4 py-2 text-xs font-medium text-zinc-600 hover:bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-800/60 dark:text-zinc-400 dark:hover:bg-zinc-800"
|
||||
>
|
||||
Reset <XCircleIcon className="ml-1.5 h-4 w-4" />
|
||||
</button>
|
||||
@@ -286,7 +286,7 @@ export function Content({
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<div className="rounded-md border border-slate-200 p-0.5 dark:border-slate-700">
|
||||
<div className="rounded-md border border-zinc-200 p-0.5 dark:border-zinc-700">
|
||||
<SchemaEditor
|
||||
packageName={schemaViewModel.packageName}
|
||||
schemaName={schemaViewModel.schemaMetadata.name}
|
||||
|
||||
@@ -21,7 +21,7 @@ export function MigrationViewer({
|
||||
<summary className="cursor-pointer">
|
||||
<Heading3 title={schema.name}></Heading3>
|
||||
</summary>
|
||||
<div className="prose prose-slate dark:prose-invert mb-6 ml-5">
|
||||
<div className="prose prose-zinc dark:prose-invert mb-6 ml-5">
|
||||
<p>{schema.description}</p>
|
||||
<div className="my-1">
|
||||
<strong>Version</strong>: {schema.version}
|
||||
|
||||
@@ -125,7 +125,7 @@ export function PackageSchemaList({
|
||||
|
||||
<div className="h-12">{/* SPACER */}</div>
|
||||
<Heading2 title={'Migrations'} />
|
||||
<ul className="divide-y divide-slate-100 dark:divide-slate-800">
|
||||
<ul className="divide-y divide-zinc-100 dark:divide-zinc-800">
|
||||
{!!filesAndLabels.length
|
||||
? filesAndLabels.map((schema) =>
|
||||
typeof schema === 'string' ? (
|
||||
|
||||
@@ -116,7 +116,7 @@ export function PackageSchemaSubList({
|
||||
) : null}
|
||||
|
||||
{vm.type === 'migration' ? (
|
||||
<ul className="divide-y divide-slate-100 dark:divide-slate-800">
|
||||
<ul className="divide-y divide-zinc-100 dark:divide-zinc-800">
|
||||
{filesAndLabels.map((schema) =>
|
||||
typeof schema === 'string' ? (
|
||||
<VersionLabelListItem
|
||||
@@ -142,7 +142,7 @@ export function PackageSchemaSubList({
|
||||
|
||||
export const VersionLabelListItem = ({ label }: { label: string }) => {
|
||||
return label ? (
|
||||
<li className="relative flex px-1 pt-2 transition focus-within:ring-2 focus-within:ring-blue-500 focus-within:ring-offset-2 hover:bg-slate-50 dark:focus-within:ring-sky-500 dark:hover:bg-slate-800/60">
|
||||
<li className="relative flex px-1 pt-2 transition focus-within:ring-2 focus-within:ring-blue-500 focus-within:ring-offset-2 hover:bg-zinc-50 dark:focus-within:ring-blue-500 dark:hover:bg-zinc-800/60">
|
||||
<div className="pt-2">
|
||||
<span className="text-sm font-bold">
|
||||
<Heading2 title={label} />
|
||||
|
||||
@@ -24,13 +24,13 @@ export const ParameterView = (props: {
|
||||
{props.alias && (
|
||||
<span
|
||||
data-tooltip="Property alias"
|
||||
className="relative -top-0.5 inline-flex rounded-md px-2 text-xs font-semibold leading-5 dark:bg-slate-700"
|
||||
className="relative -top-0.5 inline-flex rounded-md px-2 text-xs font-semibold leading-5 dark:bg-zinc-700"
|
||||
>
|
||||
{props.alias}
|
||||
</span>
|
||||
)}
|
||||
{props.required && (
|
||||
<span className="relative -top-0.5 inline-flex rounded-md bg-slate-100 px-2 text-xs font-semibold uppercase leading-5 dark:bg-slate-700">
|
||||
<span className="relative -top-0.5 inline-flex rounded-md bg-zinc-100 px-2 text-xs font-semibold uppercase leading-5 dark:bg-zinc-700">
|
||||
Required
|
||||
</span>
|
||||
)}
|
||||
@@ -68,7 +68,7 @@ export const ParameterView = (props: {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="prose prose-slate dark:prose-invert -mt-4 max-w-none">
|
||||
<div className="prose prose-zinc dark:prose-invert -mt-4 max-w-none">
|
||||
{
|
||||
renderMarkdown(props.description, {
|
||||
filePath: '',
|
||||
@@ -78,7 +78,7 @@ export const ParameterView = (props: {
|
||||
|
||||
{props.deprecated &&
|
||||
typeof (props.schema as any)['x-deprecated'] === 'string' ? (
|
||||
<div className="prose prose-slate dark:prose-invert mt-2 rounded-md bg-red-100 px-4 text-red-800 dark:bg-red-800 dark:text-red-100">
|
||||
<div className="prose prose-zinc dark:prose-invert mt-2 rounded-md bg-red-100 px-4 text-red-800 dark:bg-red-800 dark:text-red-100">
|
||||
{
|
||||
renderMarkdown(String((props.schema as any)['x-deprecated']), {
|
||||
filePath: '',
|
||||
|
||||
@@ -5,7 +5,7 @@ import Link from 'next/link';
|
||||
export const Heading1 = ({ title }: { title: string }) => (
|
||||
<h1
|
||||
id={slugify(title)}
|
||||
className="group mb-5 text-4xl font-extrabold tracking-tight text-slate-900 dark:text-slate-100"
|
||||
className="group mb-5 text-4xl font-extrabold tracking-tight text-zinc-900 dark:text-zinc-100"
|
||||
>
|
||||
<span>{title}</span>
|
||||
<Link aria-hidden="true" tabIndex={-1} href={'#' + slugify(title)}>
|
||||
@@ -20,7 +20,7 @@ export const Heading1 = ({ title }: { title: string }) => (
|
||||
export const Heading2 = ({ title }: { title: string }) => (
|
||||
<h2
|
||||
id={slugify(title)}
|
||||
className="group mb-5 text-2xl font-bold tracking-tight text-slate-800 dark:text-slate-200"
|
||||
className="group mb-5 text-2xl font-bold tracking-tight text-zinc-800 dark:text-zinc-200"
|
||||
>
|
||||
<span>{title}</span>
|
||||
<Link aria-hidden="true" tabIndex={-1} href={'#' + slugify(title)}>
|
||||
@@ -35,7 +35,7 @@ export const Heading2 = ({ title }: { title: string }) => (
|
||||
export const Heading3 = ({ title }: { title: string }) => (
|
||||
<h3
|
||||
id={slugify(title)}
|
||||
className="group text-xl font-semibold tracking-tight text-slate-700 dark:text-slate-300"
|
||||
className="group text-xl font-semibold tracking-tight text-zinc-700 dark:text-zinc-300"
|
||||
>
|
||||
<span>{title}</span>
|
||||
<Link aria-hidden="true" tabIndex={-1} href={'#' + slugify(title)}>
|
||||
|
||||
@@ -16,7 +16,7 @@ export function DocumentList({
|
||||
documents: DocumentMetadata[];
|
||||
}): JSX.Element {
|
||||
return (
|
||||
<ul className="divide-y divide-slate-100 dark:divide-slate-800">
|
||||
<ul className="divide-y divide-zinc-100 dark:divide-zinc-800">
|
||||
{!!documents.length ? (
|
||||
documents.map((guide) => (
|
||||
<DocumentListItem key={guide.id} document={guide} />
|
||||
@@ -36,9 +36,9 @@ function DocumentListItem({
|
||||
return (
|
||||
<li
|
||||
key={document.name}
|
||||
className="relative flex px-2 py-2 transition focus-within:ring-2 focus-within:ring-blue-500 focus-within:ring-offset-2 hover:bg-slate-50 dark:focus-within:ring-sky-500 dark:hover:bg-slate-800/60"
|
||||
className="relative flex px-2 py-2 transition focus-within:ring-2 focus-within:ring-blue-500 focus-within:ring-offset-2 hover:bg-zinc-50 dark:focus-within:ring-blue-500 dark:hover:bg-zinc-800/60"
|
||||
>
|
||||
<div className="flex-shrink-0 self-start rounded-lg border-slate-200 bg-slate-100 p-2 dark:border-slate-600 dark:bg-slate-700">
|
||||
<div className="flex-shrink-0 self-start rounded-lg border-zinc-200 bg-zinc-100 p-2 dark:border-zinc-600 dark:bg-zinc-700">
|
||||
<DocumentIcon className="h-5 w-5" role="img" />
|
||||
</div>
|
||||
<div className="ml-3 py-2">
|
||||
@@ -61,7 +61,7 @@ export function SchemaList({
|
||||
type: 'executor' | 'generator';
|
||||
}): JSX.Element {
|
||||
return (
|
||||
<ul className="divide-y divide-slate-100 dark:divide-slate-800">
|
||||
<ul className="divide-y divide-zinc-100 dark:divide-zinc-800">
|
||||
{!!files.length ? (
|
||||
files.map((schema) => (
|
||||
<SchemaListItem key={schema.name} file={schema} />
|
||||
@@ -77,9 +77,9 @@ function SchemaListItem({ file }: { file: FileMetadata }): JSX.Element {
|
||||
return (
|
||||
<li
|
||||
key={file.name}
|
||||
className="relative flex px-2 py-2 transition focus-within:ring-2 focus-within:ring-blue-500 focus-within:ring-offset-2 hover:bg-slate-50 dark:focus-within:ring-sky-500 dark:hover:bg-slate-800/60"
|
||||
className="relative flex px-2 py-2 transition focus-within:ring-2 focus-within:ring-blue-500 focus-within:ring-offset-2 hover:bg-zinc-50 dark:focus-within:ring-blue-500 dark:hover:bg-zinc-800/60"
|
||||
>
|
||||
<div className="flex-shrink-0 self-start rounded-lg border-slate-200 bg-slate-100 p-2 dark:border-slate-600 dark:bg-slate-700">
|
||||
<div className="flex-shrink-0 self-start rounded-lg border-zinc-200 bg-zinc-100 p-2 dark:border-zinc-600 dark:bg-zinc-700">
|
||||
{file.type === 'executor' ? (
|
||||
<CpuChipIcon className="h-5 w-5" role="img" />
|
||||
) : (
|
||||
@@ -99,7 +99,7 @@ function SchemaListItem({ file }: { file: FileMetadata }): JSX.Element {
|
||||
</span>
|
||||
)}
|
||||
</p>
|
||||
<div className="prose prose-slate dark:prose-invert prose-sm">
|
||||
<div className="prose prose-zinc dark:prose-invert prose-sm">
|
||||
{
|
||||
renderMarkdown(file.description, {
|
||||
filePath: '',
|
||||
@@ -117,10 +117,10 @@ function EmptyList({
|
||||
type: 'executor' | 'generator' | 'document';
|
||||
}): JSX.Element {
|
||||
return (
|
||||
<li className="relative flex px-2 py-2 transition focus-within:ring-2 focus-within:ring-blue-500 focus-within:ring-offset-2 hover:bg-slate-50 dark:focus-within:ring-sky-500 dark:hover:bg-slate-800/60">
|
||||
<div className="flex-shrink-0 self-start rounded-lg border-slate-200 bg-slate-100 p-2 dark:border-slate-600 dark:bg-slate-700">
|
||||
<li className="relative flex px-2 py-2 transition focus-within:ring-2 focus-within:ring-blue-500 focus-within:ring-offset-2 hover:bg-zinc-50 dark:focus-within:ring-blue-500 dark:hover:bg-zinc-800/60">
|
||||
<div className="flex-shrink-0 self-start rounded-lg border-zinc-200 bg-zinc-100 p-2 dark:border-zinc-600 dark:bg-zinc-700">
|
||||
<InformationCircleIcon
|
||||
className="h-5 w-5 flex-shrink-0 rounded-md border-slate-200 bg-slate-50 dark:bg-slate-700 dark:bg-slate-800"
|
||||
className="h-5 w-5 flex-shrink-0 rounded-md border-zinc-200 bg-zinc-50 dark:bg-zinc-700 dark:bg-zinc-800"
|
||||
role="img"
|
||||
/>
|
||||
</div>
|
||||
@@ -136,7 +136,7 @@ function EmptyList({
|
||||
{type} available for this package yet!
|
||||
</Link>
|
||||
</p>
|
||||
<div className="prose prose-slate dark:prose-invert prose-sm">
|
||||
<div className="prose prose-zinc dark:prose-invert prose-sm">
|
||||
<a
|
||||
href="https://github.com/nrwl/nx/discussions"
|
||||
target="_blank"
|
||||
|
||||
@@ -11,7 +11,7 @@ export function TopSchemaLayout({
|
||||
<div className="mb-8 flex w-full items-center space-x-2">
|
||||
<div className="w-full flex-grow">
|
||||
<div
|
||||
className="relative inline-flex rounded-md border border-slate-200 bg-slate-50 px-4 py-2 text-xs font-medium uppercase dark:border-slate-700 dark:bg-slate-800/60"
|
||||
className="relative inline-flex rounded-md border border-zinc-200 bg-zinc-50 px-4 py-2 text-xs font-medium uppercase dark:border-zinc-700 dark:bg-zinc-800/60"
|
||||
aria-hidden="true"
|
||||
data-tooltip="Installable Package"
|
||||
>
|
||||
@@ -26,7 +26,7 @@ export function TopSchemaLayout({
|
||||
rel="noreferrer"
|
||||
aria-hidden="true"
|
||||
title="See package on GitHub"
|
||||
className="relative inline-flex items-center rounded-md border border-slate-200 bg-slate-50 px-4 py-2 text-xs font-medium dark:border-slate-700 dark:bg-slate-800/60"
|
||||
className="relative inline-flex items-center rounded-md border border-zinc-200 bg-zinc-50 px-4 py-2 text-xs font-medium dark:border-zinc-700 dark:bg-zinc-800/60"
|
||||
>
|
||||
<svg
|
||||
className="mr-2 h-4 w-4"
|
||||
|
||||
@@ -92,15 +92,15 @@ export function AlgoliaSearch({
|
||||
type="button"
|
||||
ref={searchButtonRef}
|
||||
onClick={handleOpen}
|
||||
className="flex w-full items-center rounded-md bg-white px-2 py-1.5 text-sm leading-4 ring-1 ring-slate-300 transition dark:bg-slate-700 dark:ring-slate-900"
|
||||
className="flex w-full items-center rounded-md bg-white px-2 py-1.5 text-sm leading-4 ring-1 ring-zinc-300 transition dark:bg-zinc-700 dark:ring-zinc-900"
|
||||
>
|
||||
<MagnifyingGlassIcon className="h-4 w-4 flex-none" />
|
||||
<span className="mx-3 inline-flex text-xs text-slate-300 md:text-sm dark:text-slate-400">
|
||||
<span className="mx-3 inline-flex text-xs text-zinc-300 md:text-sm dark:text-zinc-400">
|
||||
Search
|
||||
</span>
|
||||
<span
|
||||
style={{ opacity: browserDetected ? '1' : '0' }}
|
||||
className="ml-auto hidden flex-none rounded-md border border-slate-200 bg-slate-50 px-1 py-0.5 text-xs font-semibold text-slate-500 md:block dark:border-slate-700 dark:bg-slate-800/60"
|
||||
className="ml-auto hidden flex-none rounded-md border border-zinc-200 bg-zinc-50 px-1 py-0.5 text-xs font-semibold text-zinc-500 md:block dark:border-zinc-700 dark:bg-zinc-800/60"
|
||||
>
|
||||
<span className="sr-only">Press </span>
|
||||
<kbd className="font-sans">
|
||||
@@ -122,7 +122,7 @@ export function AlgoliaSearch({
|
||||
>
|
||||
<span
|
||||
style={{ opacity: browserDetected ? '1' : '0' }}
|
||||
className="ml-auto block flex-none rounded-md border border-slate-200 bg-slate-50/60 px-1 py-0.5 text-xs font-semibold text-slate-400 transition hover:text-slate-500 dark:border-slate-700 dark:bg-slate-800/60 dark:text-slate-500 dark:hover:text-slate-400"
|
||||
className="ml-auto block flex-none rounded-md border border-zinc-200 bg-zinc-50/60 px-1 py-0.5 text-xs font-semibold text-zinc-400 transition hover:text-zinc-500 dark:border-zinc-700 dark:bg-zinc-800/60 dark:text-zinc-500 dark:hover:text-zinc-400"
|
||||
>
|
||||
<span className="sr-only">Press </span>
|
||||
<kbd className="font-sans">
|
||||
|
||||
@@ -119,7 +119,7 @@ export default function RootLayout({ children }: { children: ReactNode }) {
|
||||
}}
|
||||
/>
|
||||
</head>
|
||||
<body className="h-full bg-white text-slate-700 antialiased selection:bg-blue-500 selection:text-white dark:bg-slate-900 dark:text-slate-400 dark:selection:bg-sky-500">
|
||||
<body className="h-full bg-white text-zinc-700 antialiased selection:bg-blue-500 selection:text-white dark:bg-zinc-900 dark:text-zinc-400 dark:selection:bg-blue-500">
|
||||
<GlobalSearchHandler />
|
||||
{children}
|
||||
{bannerCollection.map((bannerConfig) => {
|
||||
|
||||
@@ -15,7 +15,7 @@ interface ResourceCardProps {
|
||||
|
||||
function Hero(): JSX.Element {
|
||||
return (
|
||||
<section className="relative overflow-hidden py-16 dark:from-slate-900 dark:to-slate-950">
|
||||
<section className="relative overflow-hidden py-16 dark:from-zinc-900 dark:to-zinc-950">
|
||||
<div className="mx-auto max-w-3xl text-center">
|
||||
<SectionHeading
|
||||
as="h1"
|
||||
@@ -27,7 +27,7 @@ function Hero(): JSX.Element {
|
||||
<SectionHeading
|
||||
as="p"
|
||||
variant="subtitle"
|
||||
className="mx-auto mt-6 max-w-3xl text-xl text-slate-600 dark:text-slate-400"
|
||||
className="mx-auto mt-6 max-w-3xl text-xl text-zinc-600 dark:text-zinc-400"
|
||||
>
|
||||
Learning ⋅ Events ⋅ Company
|
||||
</SectionHeading>
|
||||
@@ -41,8 +41,8 @@ function ResourceCard({ item }: ResourceCardProps) {
|
||||
<a href={item.href} className="block h-full transform-gpu">
|
||||
<div
|
||||
className={cx(
|
||||
'group relative h-full w-full overflow-hidden rounded-2xl border border-slate-200 bg-white p-8',
|
||||
'dark:border-slate-800 dark:bg-slate-900 dark:hover:border-blue-900 dark:hover:shadow-blue-900/20',
|
||||
'group relative h-full w-full overflow-hidden rounded-2xl border border-zinc-200 bg-white p-8',
|
||||
'dark:border-zinc-800 dark:bg-zinc-900 dark:hover:border-blue-900 dark:hover:shadow-blue-900/20',
|
||||
'before:absolute before:inset-0 before:z-0 before:bg-gradient-to-br before:from-blue-50 before:to-transparent before:opacity-0 before:transition-opacity',
|
||||
'transition-all duration-300 ease-out',
|
||||
'hover:-translate-y-2 hover:border-blue-200 hover:shadow-xl hover:shadow-blue-100/50',
|
||||
@@ -51,15 +51,15 @@ function ResourceCard({ item }: ResourceCardProps) {
|
||||
>
|
||||
<div className="relative z-10">
|
||||
{item.icon && (
|
||||
<div className="mb-6 flex h-14 w-14 items-center justify-center rounded-xl bg-blue-50 group-hover:bg-blue-100 dark:bg-slate-800 dark:group-hover:bg-blue-900">
|
||||
<div className="mb-6 flex h-14 w-14 items-center justify-center rounded-xl bg-blue-50 group-hover:bg-blue-100 dark:bg-zinc-800 dark:group-hover:bg-blue-900">
|
||||
<item.icon className="h-8 w-8 text-blue-600 transition-transform duration-300 group-hover:scale-110 dark:text-blue-400" />
|
||||
</div>
|
||||
)}
|
||||
<p className="text-xl font-medium text-slate-900 transition-colors duration-200 dark:text-slate-100">
|
||||
<p className="text-xl font-medium text-zinc-900 transition-colors duration-200 dark:text-zinc-100">
|
||||
{item.name}
|
||||
</p>
|
||||
{item.description && (
|
||||
<p className="mt-3 text-slate-600 transition-colors duration-200 dark:text-slate-400">
|
||||
<p className="mt-3 text-zinc-600 transition-colors duration-200 dark:text-zinc-400">
|
||||
{item.description}
|
||||
</p>
|
||||
)}
|
||||
|
||||
@@ -25,7 +25,8 @@ module.exports = withNx({
|
||||
},
|
||||
async rewrites() {
|
||||
// Only configure rewrites if NEXT_PUBLIC_ASTRO_URL is set
|
||||
const astroDocsUrl = process.env.NEXT_PUBLIC_ASTRO_URL;
|
||||
// Remove trailing slash to prevent double slashes in rewrite destinations
|
||||
const astroDocsUrl = process.env.NEXT_PUBLIC_ASTRO_URL?.replace(/\/$/, '');
|
||||
|
||||
if (!astroDocsUrl) {
|
||||
// Skip rewrites if env var is not set
|
||||
@@ -49,6 +50,10 @@ module.exports = withNx({
|
||||
source: '/llms.txt',
|
||||
destination: `${astroDocsUrl}/docs/llms.txt`,
|
||||
},
|
||||
{
|
||||
source: '/llms-full.txt',
|
||||
destination: `${astroDocsUrl}/docs/llms-full.txt`,
|
||||
},
|
||||
];
|
||||
|
||||
// For Vite assets only in development mode
|
||||
|
||||
@@ -45,7 +45,7 @@ export function FourOhFour(): JSX.Element {
|
||||
src={illustrationUrl}
|
||||
className="drop-shadow"
|
||||
/>
|
||||
<h1 className="mt-4 text-4xl font-extrabold tracking-tight text-slate-900 sm:text-6xl lg:ml-8 dark:text-slate-100">
|
||||
<h1 className="mt-4 text-4xl font-extrabold tracking-tight text-zinc-900 sm:text-6xl lg:ml-8 dark:text-zinc-100">
|
||||
<span className="sr-only">404 - </span>Page not found!
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@@ -22,7 +22,7 @@ export default function FiveOhOh(): JSX.Element {
|
||||
src="/images/illustrations/500.svg"
|
||||
className="drop-shadow"
|
||||
/>
|
||||
<h1 className="mt-4 text-4xl font-extrabold tracking-tight text-slate-900 sm:text-6xl lg:ml-8 dark:text-slate-100">
|
||||
<h1 className="mt-4 text-4xl font-extrabold tracking-tight text-zinc-900 sm:text-6xl lg:ml-8 dark:text-zinc-100">
|
||||
<div className="sr-only">500 - </div>Internal Server Error!
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@@ -43,7 +43,7 @@ export default function Document(): ReactElement {
|
||||
}}
|
||||
/>
|
||||
</Head>
|
||||
<body className="h-full bg-white text-slate-700 antialiased selection:bg-blue-500 selection:text-white dark:bg-slate-900 dark:text-slate-400 dark:selection:bg-sky-500">
|
||||
<body className="h-full bg-white text-zinc-700 antialiased selection:bg-blue-500 selection:text-white dark:bg-zinc-900 dark:text-zinc-400 dark:selection:bg-blue-500">
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
|
||||
@@ -225,7 +225,7 @@ export default function Changelog(props: ChangeLogProps): JSX.Element {
|
||||
<Breadcrumbs path={router.asPath} />
|
||||
</div>
|
||||
<header className="mt-0">
|
||||
<h1 className="text-3xl font-semibold tracking-tight text-slate-900 sm:text-5xl dark:text-slate-100">
|
||||
<h1 className="text-3xl font-semibold tracking-tight text-zinc-900 sm:text-5xl dark:text-zinc-100">
|
||||
Nx Changelog
|
||||
</h1>
|
||||
<p className="mt-4">
|
||||
@@ -249,10 +249,10 @@ export default function Changelog(props: ChangeLogProps): JSX.Element {
|
||||
'absolute left-0 top-0 hidden w-6 justify-center sm:flex'
|
||||
)}
|
||||
>
|
||||
<div className="w-px bg-slate-200 dark:bg-slate-700" />
|
||||
<div className="w-px bg-zinc-200 dark:bg-zinc-700" />
|
||||
</div>
|
||||
<div className="relative mt-1 hidden h-6 w-6 flex-none items-center justify-center sm:flex">
|
||||
<div className="h-2 w-2 rounded-full bg-slate-100 ring-1 ring-slate-300 dark:bg-slate-600 dark:ring-slate-500" />
|
||||
<div className="h-2 w-2 rounded-full bg-zinc-100 ring-1 ring-zinc-300 dark:bg-zinc-600 dark:ring-zinc-500" />
|
||||
</div>
|
||||
<div
|
||||
id={changelog.version}
|
||||
@@ -264,7 +264,7 @@ export default function Changelog(props: ChangeLogProps): JSX.Element {
|
||||
href={`https://github.com/nrwl/nx/releases/tag/${changelog.version}`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="text-xl font-medium leading-5 text-slate-900 hover:underline dark:text-slate-100"
|
||||
className="text-xl font-medium leading-5 text-zinc-900 hover:underline dark:text-zinc-100"
|
||||
>
|
||||
<TagIcon
|
||||
className="inline-flex h-4 w-4"
|
||||
@@ -276,7 +276,7 @@ export default function Changelog(props: ChangeLogProps): JSX.Element {
|
||||
<LinkIcon className="mb-1 ml-2 inline h-5 w-5 opacity-0 group-hover:opacity-100" />
|
||||
</Link>
|
||||
</p>
|
||||
<p className="py-0.5 text-xs leading-5 text-slate-400 dark:text-slate-500">
|
||||
<p className="py-0.5 text-xs leading-5 text-zinc-400 dark:text-zinc-500">
|
||||
<time
|
||||
dateTime={convertToDate(
|
||||
changelog.date
|
||||
@@ -288,7 +288,7 @@ export default function Changelog(props: ChangeLogProps): JSX.Element {
|
||||
</div>
|
||||
{/* CONTAINER */}
|
||||
<div className="flex flex-grow flex-col gap-8 md:ml-12">
|
||||
<div className="prose prose-slate dark:prose-invert max-w-none">
|
||||
<div className="prose prose-zinc dark:prose-invert max-w-none">
|
||||
{changelog.content}
|
||||
</div>
|
||||
{changelog.patches.length > 0 && (
|
||||
@@ -299,7 +299,7 @@ export default function Changelog(props: ChangeLogProps): JSX.Element {
|
||||
href={`https://github.com/nrwl/nx/releases/tag/${version}`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="inline-flex items-center rounded-md bg-slate-50 px-2 py-1 text-xs font-medium text-slate-600 ring-1 ring-inset ring-slate-500/10 hover:underline dark:bg-slate-600/30 dark:text-slate-500 dark:ring-slate-700"
|
||||
className="inline-flex items-center rounded-md bg-zinc-50 px-2 py-1 text-xs font-medium text-zinc-600 ring-1 ring-inset ring-zinc-500/10 hover:underline dark:bg-zinc-600/30 dark:text-zinc-500 dark:ring-zinc-700"
|
||||
>
|
||||
{version}
|
||||
</a>
|
||||
|
||||
@@ -60,7 +60,7 @@ export default function Community(): JSX.Element {
|
||||
<div className="w-full">
|
||||
<div
|
||||
id="connect-with-us"
|
||||
className="py-18 bg-slate-50 dark:bg-slate-800/40"
|
||||
className="py-18 bg-zinc-50 dark:bg-zinc-800/40"
|
||||
>
|
||||
<ConnectWithUs />
|
||||
</div>
|
||||
@@ -81,7 +81,7 @@ export default function Community(): JSX.Element {
|
||||
</SectionHeading>
|
||||
</header>
|
||||
<div className="mt-8 flex gap-16 font-normal">
|
||||
<p className="max-w-xl text-lg text-slate-700 dark:text-slate-400">
|
||||
<p className="max-w-xl text-lg text-zinc-700 dark:text-zinc-400">
|
||||
These friendly people promote Nx in the community by
|
||||
publishing content and sharing their expertise. They also
|
||||
gather feedback from the community to help improve Nx.
|
||||
|
||||
@@ -38,7 +38,7 @@ export function Company(): JSX.Element {
|
||||
as="h2"
|
||||
variant="subtitle"
|
||||
id="trusted"
|
||||
className="scroll-mt-24 font-medium tracking-tight text-slate-950 sm:text-3xl dark:text-white"
|
||||
className="scroll-mt-24 font-medium tracking-tight text-zinc-950 sm:text-3xl dark:text-white"
|
||||
>
|
||||
Trusted by leading OSS projects and Fortune 500 companies.
|
||||
</SectionHeading>
|
||||
|
||||
@@ -18,7 +18,7 @@ export function Customers(): JSX.Element {
|
||||
const scrollCTAConfig: ButtonLinkProps[] = [
|
||||
{
|
||||
href: '/contact/sales',
|
||||
variant: 'primary',
|
||||
variant: 'contrast',
|
||||
size: 'small',
|
||||
target: '_blank',
|
||||
title: 'Book a demo',
|
||||
|
||||
@@ -36,7 +36,7 @@ export function Enterprise(): ReactElement {
|
||||
const scrollCTAConfig: ButtonLinkProps[] = [
|
||||
{
|
||||
href: '/enterprise/trial',
|
||||
variant: 'primary',
|
||||
variant: 'contrast',
|
||||
size: 'small',
|
||||
title: 'Request a free trial',
|
||||
children: 'Request a free trial',
|
||||
|
||||
@@ -43,7 +43,7 @@ export default function Index(): JSX.Element {
|
||||
<div className="mt-32 lg:mt-56">
|
||||
<Problem />
|
||||
</div>
|
||||
<div className="bg-white/50 bg-[url(/images/home/wave.svg)] bg-cover bg-center py-32 bg-blend-soft-light lg:py-56 dark:bg-slate-900/50 dark:bg-[url(/images/home/wave-dark.svg)] dark:bg-blend-darken">
|
||||
<div className="bg-white/50 bg-[url(/images/home/wave.svg)] bg-cover bg-center py-32 bg-blend-soft-light lg:py-56 dark:bg-zinc-900/50 dark:bg-[url(/images/home/wave-dark.svg)] dark:bg-blend-darken">
|
||||
<Solution />
|
||||
</div>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ export function EnterpriseSolutionsEngineering(): ReactElement {
|
||||
const scrollCTAConfig: ButtonLinkProps[] = [
|
||||
{
|
||||
href: '/contact/sales',
|
||||
variant: 'primary',
|
||||
variant: 'contrast',
|
||||
size: 'small',
|
||||
title: 'Talk to our team',
|
||||
children: 'Talk to our team',
|
||||
|
||||
@@ -22,7 +22,7 @@ export function EnterpriseSolutionsLeadership(): ReactElement {
|
||||
const scrollCTAConfig: ButtonLinkProps[] = [
|
||||
{
|
||||
href: '/contact/sales',
|
||||
variant: 'primary',
|
||||
variant: 'contrast',
|
||||
size: 'small',
|
||||
title: 'Talk to our team',
|
||||
children: 'Talk to our team',
|
||||
|
||||
@@ -22,7 +22,7 @@ export function EnterpriseSolutionsManagement(): ReactElement {
|
||||
const scrollCTAConfig: ButtonLinkProps[] = [
|
||||
{
|
||||
href: '/contact/sales',
|
||||
variant: 'primary',
|
||||
variant: 'contrast',
|
||||
size: 'small',
|
||||
title: 'Talk to our team',
|
||||
children: 'Talk to our team',
|
||||
|
||||
@@ -22,7 +22,7 @@ export function EnterpriseSolutionsPlatform(): ReactElement {
|
||||
const scrollCTAConfig: ButtonLinkProps[] = [
|
||||
{
|
||||
href: '/contact/sales',
|
||||
variant: 'primary',
|
||||
variant: 'contrast',
|
||||
size: 'small',
|
||||
title: 'Talk to our team',
|
||||
children: 'Talk to our team',
|
||||
|
||||
@@ -104,7 +104,7 @@ export function WhitePaperFastCI(): ReactElement {
|
||||
</ButtonLink>
|
||||
</div>
|
||||
|
||||
<figure className="mt-16 rounded-lg bg-slate-100 p-4 pl-8 dark:bg-slate-800">
|
||||
<figure className="mt-16 rounded-lg bg-zinc-100 p-4 pl-8 dark:bg-zinc-800">
|
||||
<blockquote className="text-base/7">
|
||||
<p>
|
||||
“The decision to jump to Nx Cloud was really something
|
||||
@@ -124,13 +124,13 @@ export function WhitePaperFastCI(): ReactElement {
|
||||
<div className="font-semibold">
|
||||
Justin Schwartzenberger
|
||||
</div>
|
||||
<div className="text-slate-500">
|
||||
<div className="text-zinc-500">
|
||||
Principal Software Engineer, SiriusXM
|
||||
</div>
|
||||
</div>
|
||||
<SiriusxmAlternateIcon
|
||||
aria-hidden="true"
|
||||
className="ml-auto size-10 rounded text-[#0000EB] dark:bg-slate-200"
|
||||
className="ml-auto size-10 rounded text-[#0000EB] dark:bg-zinc-200"
|
||||
/>
|
||||
</figcaption>
|
||||
</figure>
|
||||
@@ -156,7 +156,7 @@ export function WhitePaperFastCI(): ReactElement {
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
<section className="flex-1 rounded-xl border border-slate-200 bg-white p-8 md:self-start dark:border-slate-800/40">
|
||||
<section className="flex-1 rounded-xl border border-zinc-200 bg-white p-8 md:self-start dark:border-zinc-800/40">
|
||||
<HubspotForm
|
||||
region="na1"
|
||||
portalId="2757427"
|
||||
|
||||
@@ -26,7 +26,7 @@ export function CallToAction(): ReactElement {
|
||||
<svg
|
||||
x="50%"
|
||||
y={0}
|
||||
className="overflow-visible fill-slate-200/20 dark:fill-slate-800/20"
|
||||
className="overflow-visible fill-zinc-200/20 dark:fill-zinc-800/20"
|
||||
>
|
||||
<path
|
||||
d="M-200 0h201v201h-201Z M600 0h201v201h-201Z M-400 600h201v201h-201Z M200 800h201v201h-201Z"
|
||||
@@ -57,7 +57,7 @@ export function CallToAction(): ReactElement {
|
||||
|
||||
{/* Content */}
|
||||
<div className="mx-auto max-w-3xl text-center">
|
||||
<h2 className="text-3xl font-medium tracking-tight text-slate-950 sm:text-5xl dark:text-white">
|
||||
<h2 className="text-3xl font-medium tracking-tight text-zinc-950 sm:text-5xl dark:text-white">
|
||||
Transform your AI assistant in minutes
|
||||
</h2>
|
||||
<div className="mt-10 flex items-center justify-center gap-x-6">
|
||||
@@ -65,7 +65,7 @@ export function CallToAction(): ReactElement {
|
||||
href={'/docs/features/enhance-ai#setting-up-nx-mcp'}
|
||||
title="Get started with Nx AI integration"
|
||||
prefetch={false}
|
||||
className="rounded-md bg-slate-950 px-3.5 py-2.5 text-sm font-semibold text-slate-100 shadow-sm hover:bg-slate-800 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white dark:bg-white dark:text-slate-900 dark:hover:bg-slate-100"
|
||||
className="rounded-md bg-zinc-950 px-3.5 py-2.5 text-sm font-semibold text-zinc-100 shadow-sm hover:bg-zinc-800 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white dark:bg-white dark:text-zinc-900 dark:hover:bg-zinc-100"
|
||||
>
|
||||
Start here{' '}
|
||||
<span
|
||||
|
||||
@@ -12,7 +12,7 @@ export function Features(): ReactElement {
|
||||
Make your AI assistant workspace-aware
|
||||
</SectionHeading>
|
||||
|
||||
<p className="mt-4 text-lg text-slate-500 dark:text-slate-400">
|
||||
<p className="mt-4 text-lg text-zinc-500 dark:text-zinc-400">
|
||||
Transform your LLM from context-blind to architecture-aware with
|
||||
complete workspace intelligence.
|
||||
</p>
|
||||
@@ -276,8 +276,8 @@ function FeatureCard({
|
||||
<a href={href} className="block h-full transform-gpu">
|
||||
<div
|
||||
className={cx(
|
||||
'group relative h-full w-full overflow-hidden rounded-lg border border-slate-200 bg-white p-6',
|
||||
'dark:border-slate-800 dark:bg-slate-900 dark:hover:border-blue-900 dark:hover:shadow-blue-900/20',
|
||||
'group relative h-full w-full overflow-hidden rounded-lg border border-zinc-200 bg-white p-6',
|
||||
'dark:border-zinc-800 dark:bg-zinc-900 dark:hover:border-blue-900 dark:hover:shadow-blue-900/20',
|
||||
'before:absolute before:inset-0 before:z-0 before:bg-gradient-to-br before:from-blue-50 before:to-transparent before:opacity-0 before:transition-opacity',
|
||||
'transition-all duration-300 ease-out',
|
||||
'hover:-translate-y-2 hover:border-blue-200 hover:shadow-xl hover:shadow-blue-100/50',
|
||||
@@ -285,11 +285,11 @@ function FeatureCard({
|
||||
)}
|
||||
>
|
||||
<div className="relative z-10">
|
||||
<div className="mb-4 flex h-12 w-12 items-center justify-center rounded-lg bg-blue-50 text-blue-600 transition-transform duration-300 group-hover:scale-110 dark:bg-slate-800 dark:text-blue-400 dark:group-hover:bg-blue-900">
|
||||
<div className="mb-4 flex h-12 w-12 items-center justify-center rounded-lg bg-blue-50 text-blue-600 transition-transform duration-300 group-hover:scale-110 dark:bg-zinc-800 dark:text-blue-400 dark:group-hover:bg-blue-900">
|
||||
{icon}
|
||||
</div>
|
||||
<h3 className="mb-2 text-lg font-medium">{title}</h3>
|
||||
<p className="text-slate-500 dark:text-slate-400">{description}</p>
|
||||
<p className="text-zinc-500 dark:text-zinc-400">{description}</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
@@ -197,7 +197,7 @@ export function Hero(): JSX.Element {
|
||||
<div className="relative">
|
||||
<div className="absolute bottom-0 start-0 -z-10 -translate-x-14 translate-y-10">
|
||||
<svg
|
||||
className="h-auto max-w-40 text-slate-200 dark:text-slate-800"
|
||||
className="h-auto max-w-40 text-zinc-200 dark:text-zinc-800"
|
||||
width="696"
|
||||
height="653"
|
||||
viewBox="0 0 696 653"
|
||||
@@ -370,8 +370,7 @@ export function Hero(): JSX.Element {
|
||||
{
|
||||
'bg-blue-50 ring-2 ring-blue-500 dark:bg-blue-950/50 dark:ring-blue-400':
|
||||
isSelected,
|
||||
'hover:bg-slate-100 dark:hover:bg-slate-800':
|
||||
!isSelected,
|
||||
'hover:bg-zinc-100 dark:hover:bg-zinc-800': !isSelected,
|
||||
}
|
||||
)}
|
||||
>
|
||||
@@ -398,7 +397,7 @@ export function Hero(): JSX.Element {
|
||||
'relative text-base font-medium leading-6 transition-colors',
|
||||
isSelected
|
||||
? 'text-blue-900 dark:text-blue-100'
|
||||
: 'text-slate-900 group-hover:text-blue-600 dark:text-slate-100 dark:group-hover:text-blue-400'
|
||||
: 'text-zinc-900 group-hover:text-blue-600 dark:text-zinc-100 dark:group-hover:text-blue-400'
|
||||
)}
|
||||
>
|
||||
{feature.title}
|
||||
@@ -420,7 +419,7 @@ export function Hero(): JSX.Element {
|
||||
'mt-2 text-sm leading-6 transition-colors',
|
||||
isSelected
|
||||
? 'text-blue-700 dark:text-blue-200'
|
||||
: 'text-slate-600 dark:text-slate-400'
|
||||
: 'text-zinc-600 dark:text-zinc-400'
|
||||
)}
|
||||
>
|
||||
{feature.description}
|
||||
@@ -439,7 +438,7 @@ export function Hero(): JSX.Element {
|
||||
>
|
||||
<ButtonLink
|
||||
href={'/docs/features/enhance-ai#setting-up-nx-mcp'}
|
||||
variant="primary"
|
||||
variant="contrast"
|
||||
size="default"
|
||||
title="Enhance your AI assistant"
|
||||
onClick={() =>
|
||||
|
||||
@@ -27,7 +27,7 @@ export function AiHero(): ReactElement {
|
||||
<ButtonLink
|
||||
href={'/docs/getting-started/ai-setup'}
|
||||
title="Nx AI Integration"
|
||||
variant="primary"
|
||||
variant="contrast"
|
||||
size="small"
|
||||
>
|
||||
Integrate Nx with your Coding Assistant
|
||||
@@ -36,7 +36,7 @@ export function AiHero(): ReactElement {
|
||||
<div className="mt-8 flex flex-wrap items-center gap-4">
|
||||
<a
|
||||
href="#while-coding"
|
||||
className="inline-flex items-center gap-1.5 rounded-full bg-slate-100 px-2 py-1.5 text-xs font-medium text-slate-700 hover:bg-slate-200 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-slate-800 dark:text-slate-300 dark:hover:bg-slate-700"
|
||||
className="inline-flex items-center gap-1.5 rounded-full bg-zinc-100 px-2 py-1.5 text-xs font-medium text-zinc-700 hover:bg-zinc-200 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-zinc-300 dark:hover:bg-zinc-700"
|
||||
aria-label="Jump to While Coding section"
|
||||
>
|
||||
<CodeBracketIcon aria-hidden="true" className="size-4 shrink-0" />
|
||||
@@ -44,7 +44,7 @@ export function AiHero(): ReactElement {
|
||||
</a>
|
||||
<a
|
||||
href="#while-running-ci"
|
||||
className="inline-flex items-center gap-1.5 rounded-full bg-slate-100 px-2 py-1.5 text-xs font-medium text-slate-700 hover:bg-slate-200 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-slate-800 dark:text-slate-300 dark:hover:bg-slate-700"
|
||||
className="inline-flex items-center gap-1.5 rounded-full bg-zinc-100 px-2 py-1.5 text-xs font-medium text-zinc-700 hover:bg-zinc-200 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-zinc-300 dark:hover:bg-zinc-700"
|
||||
aria-label="Jump to While Running CI section"
|
||||
>
|
||||
<ServerStackIcon aria-hidden="true" className="size-4 shrink-0" />
|
||||
@@ -52,7 +52,7 @@ export function AiHero(): ReactElement {
|
||||
</a>
|
||||
<a
|
||||
href="#while-scaling-your-organization"
|
||||
className="inline-flex items-center gap-1.5 rounded-full bg-slate-100 px-2 py-1.5 text-xs font-medium text-slate-700 hover:bg-slate-200 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-slate-800 dark:text-slate-300 dark:hover:bg-slate-700"
|
||||
className="inline-flex items-center gap-1.5 rounded-full bg-zinc-100 px-2 py-1.5 text-xs font-medium text-zinc-700 hover:bg-zinc-200 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-zinc-300 dark:hover:bg-zinc-700"
|
||||
aria-label="Jump to Scaling Your Organization section"
|
||||
>
|
||||
<UserGroupIcon aria-hidden="true" className="size-4 shrink-0" />
|
||||
|
||||
@@ -50,7 +50,7 @@ export function FeatureCard({
|
||||
return (
|
||||
<div key={id} className="flex flex-col">
|
||||
<dt className="text-base/7 font-semibold">
|
||||
<div className="relative mb-6 aspect-video max-h-52 w-full overflow-hidden rounded-xl bg-slate-200 dark:bg-slate-700/60">
|
||||
<div className="relative mb-6 aspect-video max-h-52 w-full overflow-hidden rounded-xl bg-zinc-200 dark:bg-zinc-700/60">
|
||||
<Image
|
||||
src={imageUrl}
|
||||
alt={`Thumbnail for ${title}`}
|
||||
|
||||
@@ -32,7 +32,7 @@ export function NxPowerAi({
|
||||
<li className="relative isolate flex aspect-square h-20 items-center justify-center">
|
||||
<HexagonShape
|
||||
aria-hidden="true"
|
||||
className="absolute inset-0 z-0 text-slate-50/90 drop-shadow-sm dark:text-white/5"
|
||||
className="absolute inset-0 z-0 text-zinc-50/90 drop-shadow-sm dark:text-white/5"
|
||||
/>
|
||||
</li>
|
||||
<li className="relative isolate flex aspect-square h-20 items-center justify-center">
|
||||
@@ -48,7 +48,7 @@ export function NxPowerAi({
|
||||
<li className="relative isolate flex aspect-square h-20 items-center justify-center">
|
||||
<HexagonShape
|
||||
aria-hidden="true"
|
||||
className="absolute inset-0 z-0 text-slate-50/90 drop-shadow-sm dark:text-white/5"
|
||||
className="absolute inset-0 z-0 text-zinc-50/90 drop-shadow-sm dark:text-white/5"
|
||||
/>
|
||||
</li>
|
||||
<li className="invisible aspect-square" />
|
||||
@@ -57,7 +57,7 @@ export function NxPowerAi({
|
||||
<li className="flex aspect-square translate-x-1/2 items-center justify-center">
|
||||
<HexagonShape
|
||||
aria-hidden="true"
|
||||
className="absolute inset-0 z-0 text-slate-50/90 drop-shadow-sm dark:text-white/5"
|
||||
className="absolute inset-0 z-0 text-zinc-50/90 drop-shadow-sm dark:text-white/5"
|
||||
/>
|
||||
</li>
|
||||
<li className="relative isolate flex aspect-square h-20 translate-x-1/2 items-center justify-center">
|
||||
@@ -83,7 +83,7 @@ export function NxPowerAi({
|
||||
<li className="flex aspect-square translate-x-1/2 items-center justify-center">
|
||||
<HexagonShape
|
||||
aria-hidden="true"
|
||||
className="absolute inset-0 z-0 text-slate-50/90 drop-shadow-sm dark:text-white/5"
|
||||
className="absolute inset-0 z-0 text-zinc-50/90 drop-shadow-sm dark:text-white/5"
|
||||
/>
|
||||
</li>
|
||||
<li className="invisible"></li>
|
||||
@@ -93,7 +93,7 @@ export function NxPowerAi({
|
||||
<li className="relative isolate flex aspect-square h-20 items-center justify-center">
|
||||
<HexagonShape
|
||||
aria-hidden="true"
|
||||
className="absolute inset-0 z-0 text-slate-50/90 drop-shadow-sm dark:text-white/5"
|
||||
className="absolute inset-0 z-0 text-zinc-50/90 drop-shadow-sm dark:text-white/5"
|
||||
/>
|
||||
</li>
|
||||
<li className="relative isolate flex aspect-square h-20 items-center justify-center">
|
||||
@@ -109,7 +109,7 @@ export function NxPowerAi({
|
||||
<li className="relative isolate flex aspect-square h-20 items-center justify-center">
|
||||
<HexagonShape
|
||||
aria-hidden="true"
|
||||
className="absolute inset-0 z-0 text-slate-50/90 drop-shadow-sm dark:text-white/5"
|
||||
className="absolute inset-0 z-0 text-zinc-50/90 drop-shadow-sm dark:text-white/5"
|
||||
/>
|
||||
</li>
|
||||
<li className="invisible" />
|
||||
@@ -119,20 +119,20 @@ export function NxPowerAi({
|
||||
{/* Steps List */}
|
||||
<div className="relative mt-12 space-y-2">
|
||||
{/* Active Step */}
|
||||
<div className="rounded-xl border border-slate-200 bg-slate-50 p-4 shadow-sm backdrop-blur-sm dark:border-slate-800/40 dark:bg-slate-800/60">
|
||||
<div className="rounded-xl border border-zinc-200 bg-zinc-50 p-4 shadow-sm backdrop-blur-sm dark:border-zinc-800/40 dark:bg-zinc-800/60">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="flex size-5 items-center justify-center rounded-full border border-white/25 bg-gradient-to-br from-slate-200 to-slate-300 dark:border-slate-900 dark:from-slate-700 dark:to-slate-800">
|
||||
<div className="size-2 rounded-full bg-white dark:bg-slate-900" />
|
||||
<div className="flex size-5 items-center justify-center rounded-full border border-white/25 bg-gradient-to-br from-zinc-200 to-zinc-300 dark:border-zinc-900 dark:from-zinc-700 dark:to-zinc-800">
|
||||
<div className="size-2 rounded-full bg-white dark:bg-zinc-900" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<p className="font-mono text-xs leading-tight text-slate-900 dark:text-slate-100">
|
||||
<p className="font-mono text-xs leading-tight text-zinc-900 dark:text-zinc-100">
|
||||
Generating a fix for test "ui-profile:test:save-preferences"
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<span className="text-xs text-slate-600 dark:text-slate-400">
|
||||
<span className="text-xs text-zinc-600 dark:text-zinc-400">
|
||||
Working...
|
||||
</span>
|
||||
<span className="relative flex size-1.5">
|
||||
@@ -144,20 +144,20 @@ export function NxPowerAi({
|
||||
</div>
|
||||
|
||||
{/* Completed Step */}
|
||||
<div className="rounded-xl border border-slate-200 bg-slate-50 p-4 opacity-50 shadow-sm backdrop-blur-sm dark:border-slate-800/40 dark:bg-slate-800/60">
|
||||
<div className="rounded-xl border border-zinc-200 bg-zinc-50 p-4 opacity-50 shadow-sm backdrop-blur-sm dark:border-zinc-800/40 dark:bg-zinc-800/60">
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<div className="flex grow items-center space-x-3">
|
||||
<div className="flex size-5 items-center justify-center rounded-full border border-white/25 bg-gradient-to-br from-slate-200 to-slate-300 dark:border-slate-900 dark:from-slate-700 dark:to-slate-800">
|
||||
<div className="size-2 rounded-full bg-white dark:bg-slate-900" />
|
||||
<div className="flex size-5 items-center justify-center rounded-full border border-white/25 bg-gradient-to-br from-zinc-200 to-zinc-300 dark:border-zinc-900 dark:from-zinc-700 dark:to-zinc-800">
|
||||
<div className="size-2 rounded-full bg-white dark:bg-zinc-900" />
|
||||
</div>
|
||||
|
||||
<div className="w-full grow space-y-1">
|
||||
<div className="h-1 w-8 rounded-sm bg-slate-800/15 dark:bg-slate-200/35" />
|
||||
<div className="h-1 w-1/2 rounded-sm bg-slate-500/10 dark:bg-slate-400/35" />
|
||||
<div className="h-1 w-8 rounded-sm bg-zinc-800/15 dark:bg-zinc-200/35" />
|
||||
<div className="h-1 w-1/2 rounded-sm bg-zinc-500/10 dark:bg-zinc-400/35" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<span className="text-xs text-slate-600 dark:text-slate-300">
|
||||
<span className="text-xs text-zinc-600 dark:text-zinc-300">
|
||||
Done
|
||||
</span>
|
||||
<div className="size-1.5 rounded-full bg-green-500 shadow-sm" />
|
||||
@@ -166,13 +166,13 @@ export function NxPowerAi({
|
||||
</div>
|
||||
|
||||
{/* Pending Step */}
|
||||
<div className="rounded-xl border border-slate-200 bg-slate-50 p-4 opacity-40 shadow-sm backdrop-blur-sm dark:border-slate-800/40 dark:bg-slate-800/60">
|
||||
<div className="rounded-xl border border-zinc-200 bg-zinc-50 p-4 opacity-40 shadow-sm backdrop-blur-sm dark:border-zinc-800/40 dark:bg-zinc-800/60">
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="flex size-5 items-center justify-center rounded-full border border-white/25 bg-gradient-to-br from-slate-200 to-slate-300 dark:border-slate-900 dark:from-slate-700 dark:to-slate-800">
|
||||
<div className="size-2 rounded-full bg-white dark:bg-slate-900" />
|
||||
<div className="flex size-5 items-center justify-center rounded-full border border-white/25 bg-gradient-to-br from-zinc-200 to-zinc-300 dark:border-zinc-900 dark:from-zinc-700 dark:to-zinc-800">
|
||||
<div className="size-2 rounded-full bg-white dark:bg-zinc-900" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="h-1 w-16 rounded-sm bg-slate-400/20" />
|
||||
<div className="h-1 w-16 rounded-sm bg-zinc-400/20" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -57,7 +57,7 @@ export function PlayButton({
|
||||
initial="initial"
|
||||
whileHover="hover"
|
||||
variants={parent}
|
||||
className="relative isolate flex size-20 cursor-pointer items-center justify-center gap-6 rounded-full border-2 border-slate-100 bg-white/10 p-6 text-white antialiased backdrop-blur-xl"
|
||||
className="relative isolate flex size-20 cursor-pointer items-center justify-center gap-6 rounded-full border-2 border-zinc-100 bg-white/10 p-6 text-white antialiased backdrop-blur-xl"
|
||||
>
|
||||
<PlayIcon aria-hidden="true" className="absolute left-6 top-6 size-8" />
|
||||
<motion.div variants={child} className="absolute left-20 top-4 w-48">
|
||||
|
||||
@@ -100,7 +100,7 @@ export function WhileCoding(): ReactElement {
|
||||
className="mx-auto max-w-7xl scroll-mt-32 px-6 lg:px-8"
|
||||
>
|
||||
<div className="max-w-2xl">
|
||||
<div className="h-8 w-36 border-t-2 border-blue-500 dark:border-sky-500" />
|
||||
<div className="h-8 w-36 border-t-2 border-blue-500 dark:border-blue-500" />
|
||||
<SectionHeading as="h2" variant="title" id="while-coding-title">
|
||||
While Coding
|
||||
</SectionHeading>
|
||||
|
||||
@@ -65,7 +65,7 @@ export function WhileRunningCi(): ReactElement {
|
||||
const [openVideoUrl, setOpenVideoUrl] = useState<string | null>(null);
|
||||
|
||||
return (
|
||||
<div className="relative bg-slate-50 py-32 dark:bg-slate-800">
|
||||
<div className="relative bg-zinc-50 py-32 dark:bg-zinc-800">
|
||||
<div
|
||||
id="while-running-ci"
|
||||
className="mx-auto max-w-7xl scroll-mt-32 px-6 lg:px-8"
|
||||
|
||||
@@ -15,7 +15,7 @@ export function ProblemStatement({
|
||||
Your AI assistant is blind to your workspace architecture
|
||||
</SectionHeading>
|
||||
|
||||
<p className="mt-4 text-lg text-slate-500 dark:text-slate-400">
|
||||
<p className="mt-4 text-lg text-zinc-500 dark:text-zinc-400">
|
||||
As monorepos scale, AI tools become progressively less effective
|
||||
without true workspace understanding.
|
||||
</p>
|
||||
@@ -24,7 +24,7 @@ export function ProblemStatement({
|
||||
<div className="grid grid-cols-1 gap-x-8 gap-y-4 md:grid-cols-2">
|
||||
{/* Left Column - Problems */}
|
||||
<div>
|
||||
<h3 className="mb-3 text-lg font-bold text-slate-900 dark:text-white">
|
||||
<h3 className="mb-3 text-lg font-bold text-zinc-900 dark:text-white">
|
||||
The challenges
|
||||
</h3>
|
||||
|
||||
@@ -50,10 +50,10 @@ export function ProblemStatement({
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="mb-1 text-sm font-medium leading-tight text-slate-900 dark:text-slate-100">
|
||||
<h4 className="mb-1 text-sm font-medium leading-tight text-zinc-900 dark:text-zinc-100">
|
||||
Limited context
|
||||
</h4>
|
||||
<p className="text-sm text-slate-600 dark:text-slate-300">
|
||||
<p className="text-sm text-zinc-600 dark:text-zinc-300">
|
||||
LLMs only see individual files, missing the architectural
|
||||
relationships in large monorepos.
|
||||
</p>
|
||||
@@ -77,10 +77,10 @@ export function ProblemStatement({
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="mb-1 text-sm font-medium leading-tight text-slate-900 dark:text-slate-100">
|
||||
<h4 className="mb-1 text-sm font-medium leading-tight text-zinc-900 dark:text-zinc-100">
|
||||
Inconsistent output
|
||||
</h4>
|
||||
<p className="text-sm text-slate-600 dark:text-slate-300">
|
||||
<p className="text-sm text-zinc-600 dark:text-zinc-300">
|
||||
AI generates code that doesn't follow team standards or may
|
||||
break components it can't see.
|
||||
</p>
|
||||
@@ -106,10 +106,10 @@ export function ProblemStatement({
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="mb-1 text-sm font-medium leading-tight text-slate-900 dark:text-slate-100">
|
||||
<h4 className="mb-1 text-sm font-medium leading-tight text-zinc-900 dark:text-zinc-100">
|
||||
No workspace awareness
|
||||
</h4>
|
||||
<p className="text-sm text-slate-600 dark:text-slate-300">
|
||||
<p className="text-sm text-zinc-600 dark:text-zinc-300">
|
||||
AI can't understand project dependencies, ownership, or
|
||||
cross-project integration points.
|
||||
</p>
|
||||
@@ -136,10 +136,10 @@ export function ProblemStatement({
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="mb-1 text-sm font-medium leading-tight text-slate-900 dark:text-slate-100">
|
||||
<h4 className="mb-1 text-sm font-medium leading-tight text-zinc-900 dark:text-zinc-100">
|
||||
Manual context burden
|
||||
</h4>
|
||||
<p className="text-sm text-slate-600 dark:text-slate-300">
|
||||
<p className="text-sm text-zinc-600 dark:text-zinc-300">
|
||||
Developers must repeatedly provide the same contextual
|
||||
information about project structure.
|
||||
</p>
|
||||
@@ -150,7 +150,7 @@ export function ProblemStatement({
|
||||
|
||||
{/* Right Column - Solutions */}
|
||||
<div>
|
||||
<h3 className="mb-3 text-lg font-bold text-slate-900 dark:text-white">
|
||||
<h3 className="mb-3 text-lg font-bold text-zinc-900 dark:text-white">
|
||||
How Nx helps
|
||||
</h3>
|
||||
|
||||
@@ -176,10 +176,10 @@ export function ProblemStatement({
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="mb-1 text-sm font-medium leading-tight text-slate-900 dark:text-slate-100">
|
||||
<h4 className="mb-1 text-sm font-medium leading-tight text-zinc-900 dark:text-zinc-100">
|
||||
Architectural awareness
|
||||
</h4>
|
||||
<p className="text-sm text-slate-600 dark:text-slate-300">
|
||||
<p className="text-sm text-zinc-600 dark:text-zinc-300">
|
||||
Move from file-level to workspace-level understanding with
|
||||
rich project relationship metadata.
|
||||
</p>
|
||||
@@ -203,10 +203,10 @@ export function ProblemStatement({
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="mb-1 text-sm font-medium leading-tight text-slate-900 dark:text-slate-100">
|
||||
<h4 className="mb-1 text-sm font-medium leading-tight text-zinc-900 dark:text-zinc-100">
|
||||
Predictable + intelligent
|
||||
</h4>
|
||||
<p className="text-sm text-slate-600 dark:text-slate-300">
|
||||
<p className="text-sm text-zinc-600 dark:text-zinc-300">
|
||||
Combine consistent generators with AI customization that
|
||||
follows team standards.
|
||||
</p>
|
||||
@@ -241,10 +241,10 @@ export function ProblemStatement({
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="mb-1 text-sm font-medium leading-tight text-slate-900 dark:text-slate-100">
|
||||
<h4 className="mb-1 text-sm font-medium leading-tight text-zinc-900 dark:text-zinc-100">
|
||||
Integrated workflows
|
||||
</h4>
|
||||
<p className="text-sm text-slate-600 dark:text-slate-300">
|
||||
<p className="text-sm text-zinc-600 dark:text-zinc-300">
|
||||
Connect editor, terminal, CI, and AI for truly context-aware
|
||||
assistance across your entire workspace.
|
||||
</p>
|
||||
@@ -290,10 +290,10 @@ export function ProblemStatement({
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="mb-1 text-sm font-medium leading-tight text-slate-900 dark:text-slate-100">
|
||||
<h4 className="mb-1 text-sm font-medium leading-tight text-zinc-900 dark:text-zinc-100">
|
||||
Up-to-Date Documentation
|
||||
</h4>
|
||||
<p className="text-sm text-slate-600 dark:text-slate-300">
|
||||
<p className="text-sm text-zinc-600 dark:text-zinc-300">
|
||||
Access current docs and best practices for accurate,
|
||||
workspace-specific guidance.
|
||||
</p>
|
||||
|
||||
@@ -13,7 +13,7 @@ export function TechnicalImplementation({
|
||||
}: TechnicalImplementationProps): JSX.Element {
|
||||
return (
|
||||
<section
|
||||
className={`bg-gradient-to-b from-white to-slate-50 py-12 dark:from-slate-900 dark:to-slate-800 ${
|
||||
className={`bg-gradient-to-b from-white to-zinc-50 py-12 dark:from-zinc-900 dark:to-zinc-800 ${
|
||||
className || ''
|
||||
}`}
|
||||
>
|
||||
@@ -21,7 +21,7 @@ export function TechnicalImplementation({
|
||||
<div className="mb-12 grid grid-cols-1 gap-8 md:grid-cols-2 lg:gap-12">
|
||||
{/* Left Side - Title and How It Works */}
|
||||
<div className="flex flex-col justify-center">
|
||||
<h2 className="mb-8 text-left text-3xl font-bold text-slate-900 md:text-4xl dark:text-white">
|
||||
<h2 className="mb-8 text-left text-3xl font-bold text-zinc-900 md:text-4xl dark:text-white">
|
||||
Powered by Nx workspace intelligence
|
||||
</h2>
|
||||
|
||||
@@ -31,7 +31,7 @@ export function TechnicalImplementation({
|
||||
<span className="text-lg font-semibold">1</span>
|
||||
</div>
|
||||
<div className="flex-1 pt-1">
|
||||
<p className="text-slate-600 dark:text-slate-300">
|
||||
<p className="text-zinc-600 dark:text-zinc-300">
|
||||
Nx daemon runs in the background, maintaining up-to-date
|
||||
workspace metadata
|
||||
</p>
|
||||
@@ -43,7 +43,7 @@ export function TechnicalImplementation({
|
||||
<span className="text-lg font-semibold">2</span>
|
||||
</div>
|
||||
<div className="flex-1 pt-1">
|
||||
<p className="text-slate-600 dark:text-slate-300">
|
||||
<p className="text-zinc-600 dark:text-zinc-300">
|
||||
This rich contextual data is processed and optimized for AI
|
||||
consumption
|
||||
</p>
|
||||
@@ -55,7 +55,7 @@ export function TechnicalImplementation({
|
||||
<span className="text-lg font-semibold">3</span>
|
||||
</div>
|
||||
<div className="flex-1 pt-1">
|
||||
<p className="text-slate-600 dark:text-slate-300">
|
||||
<p className="text-zinc-600 dark:text-zinc-300">
|
||||
Nx Console exposes the data to your AI assistant via an MCP
|
||||
</p>
|
||||
</div>
|
||||
@@ -82,16 +82,16 @@ export function TechnicalImplementation({
|
||||
{/* Flow diagram with connected boxes */}
|
||||
<div className="grid grid-cols-1 gap-6 md:grid-cols-3 lg:gap-8">
|
||||
{/* Nx Console Box */}
|
||||
<div className="relative rounded-xl border border-slate-200 bg-slate-50 p-6 shadow-md dark:border-slate-700 dark:bg-slate-800/50">
|
||||
<div className="relative rounded-xl border border-zinc-200 bg-zinc-50 p-6 shadow-md dark:border-zinc-700 dark:bg-zinc-800/50">
|
||||
<div className="mb-4 flex items-center">
|
||||
<div className="mr-4 flex h-16 w-16 flex-shrink-0 items-center justify-center rounded-full bg-blue-500 text-white">
|
||||
<NxConsoleSmallIcon className="h-24 w-24" />
|
||||
</div>
|
||||
<h4 className="text-xl font-bold text-slate-900 dark:text-white">
|
||||
<h4 className="text-xl font-bold text-zinc-900 dark:text-white">
|
||||
Start with Nx Console
|
||||
</h4>
|
||||
</div>
|
||||
<p className="text-slate-600 dark:text-slate-300">
|
||||
<p className="text-zinc-600 dark:text-zinc-300">
|
||||
Install the Nx Console Extension, available for VSCode, Cursor,
|
||||
and IntelliJ.
|
||||
</p>
|
||||
@@ -132,16 +132,16 @@ export function TechnicalImplementation({
|
||||
</div>
|
||||
|
||||
{/* MCP Box */}
|
||||
<div className="relative rounded-xl border border-slate-200 bg-slate-50 p-6 shadow-md dark:border-slate-700 dark:bg-slate-800/50">
|
||||
<div className="relative rounded-xl border border-zinc-200 bg-zinc-50 p-6 shadow-md dark:border-zinc-700 dark:bg-zinc-800/50">
|
||||
<div className="mb-4 flex items-center">
|
||||
<div className="mr-4 flex h-16 w-16 flex-shrink-0 items-center justify-center rounded-full bg-indigo-500 text-white">
|
||||
<ModelContextProtocolIcon className="h-8 w-8" />
|
||||
</div>
|
||||
<h4 className="text-xl font-bold text-slate-900 dark:text-white">
|
||||
<h4 className="text-xl font-bold text-zinc-900 dark:text-white">
|
||||
Nx MCP
|
||||
</h4>
|
||||
</div>
|
||||
<p className="text-slate-600 dark:text-slate-300">
|
||||
<p className="text-zinc-600 dark:text-zinc-300">
|
||||
Nx Console automatically registers its MCP server or you can
|
||||
configure it in any MCP compatible client.
|
||||
</p>
|
||||
@@ -182,7 +182,7 @@ export function TechnicalImplementation({
|
||||
</div>
|
||||
|
||||
{/* Enhanced LLM Workflow Box */}
|
||||
<div className="rounded-xl border border-slate-200 bg-slate-50 p-6 shadow-md dark:border-slate-700 dark:bg-slate-800/50">
|
||||
<div className="rounded-xl border border-zinc-200 bg-zinc-50 p-6 shadow-md dark:border-zinc-700 dark:bg-zinc-800/50">
|
||||
<div className="mb-4 flex items-center">
|
||||
<div className="mr-4 flex h-16 w-16 flex-shrink-0 items-center justify-center rounded-full bg-blue-600 text-white">
|
||||
<svg
|
||||
@@ -200,11 +200,11 @@ export function TechnicalImplementation({
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<h4 className="text-xl font-bold text-slate-900 dark:text-white">
|
||||
<h4 className="text-xl font-bold text-zinc-900 dark:text-white">
|
||||
Enhanced LLM workflow
|
||||
</h4>
|
||||
</div>
|
||||
<p className="text-slate-600 dark:text-slate-300">
|
||||
<p className="text-zinc-600 dark:text-zinc-300">
|
||||
Your existing AI tools understand your workspace architecture
|
||||
without changing your development habits.
|
||||
</p>
|
||||
|
||||
@@ -8,7 +8,7 @@ interface AuthorDetailProps {
|
||||
|
||||
export default function AuthorDetail({ author }: AuthorDetailProps) {
|
||||
return (
|
||||
<div className="space-between invisible absolute left-[65%] right-0 z-30 mt-2 flex w-60 translate-x-[-50%] items-center gap-4 rounded bg-slate-50 p-4 text-sm text-slate-700 opacity-0 shadow-lg ring-1 ring-slate-200 transition-all delay-75 duration-300 ease-in-out md:group-hover:visible md:group-hover:opacity-100 dark:bg-slate-900 dark:text-slate-400 dark:ring-slate-800">
|
||||
<div className="space-between invisible absolute left-[65%] right-0 z-30 mt-2 flex w-60 translate-x-[-50%] items-center gap-4 rounded bg-zinc-50 p-4 text-sm text-zinc-700 opacity-0 shadow-lg ring-1 ring-zinc-200 transition-all delay-75 duration-300 ease-in-out md:group-hover:visible md:group-hover:opacity-100 dark:bg-zinc-900 dark:text-zinc-400 dark:ring-zinc-800">
|
||||
<span>
|
||||
<Image
|
||||
alt={author.name}
|
||||
@@ -18,7 +18,7 @@ export default function AuthorDetail({ author }: AuthorDetailProps) {
|
||||
height="40"
|
||||
decoding="async"
|
||||
src={`/documentation/blog/images/authors/${author.name}.jpeg`}
|
||||
className="rounded-full ring-1 ring-white grayscale dark:ring-slate-900"
|
||||
className="rounded-full ring-1 ring-white grayscale dark:ring-zinc-900"
|
||||
/>
|
||||
</span>
|
||||
<span className="text-balance">{author.name}</span>
|
||||
|
||||
@@ -21,7 +21,7 @@ export function BlogAuthors({
|
||||
height="48"
|
||||
decoding="async"
|
||||
src={`/documentation/blog/images/authors/${author.name}.jpeg`}
|
||||
className="relative inline-block h-6 w-6 rounded-full ring-1 ring-white grayscale dark:ring-slate-900"
|
||||
className="relative inline-block h-6 w-6 rounded-full ring-1 ring-white grayscale dark:ring-zinc-900"
|
||||
/>
|
||||
{showAuthorDetails && <AuthorDetail author={author} />}
|
||||
</div>
|
||||
|
||||
@@ -77,7 +77,7 @@ export function BlogContainer({ blogPosts, tags }: BlogContainerProps) {
|
||||
<header className="mb-8 mt-20">
|
||||
<h1
|
||||
id="blog-title"
|
||||
className="text-xl font-semibold tracking-tight text-slate-900 md:text-2xl dark:text-slate-100"
|
||||
className="text-xl font-semibold tracking-tight text-zinc-900 md:text-2xl dark:text-zinc-100"
|
||||
>
|
||||
{selectedFilterHeading}
|
||||
</h1>
|
||||
@@ -100,7 +100,7 @@ export function BlogContainer({ blogPosts, tags }: BlogContainerProps) {
|
||||
<FeaturedBlogs blogs={firstFiveBlogs} />
|
||||
{!!remainingBlogs.length && (
|
||||
<>
|
||||
<div className="mx-auto mb-8 mt-20 flex items-center justify-between border-b-2 border-slate-300 pb-3 text-sm dark:border-slate-700">
|
||||
<div className="mx-auto mb-8 mt-20 flex items-center justify-between border-b-2 border-zinc-300 pb-3 text-sm dark:border-zinc-700">
|
||||
<h2 className="font-semibold">All blogs</h2>
|
||||
<div className="flex gap-2">
|
||||
<Link
|
||||
@@ -108,14 +108,14 @@ export function BlogContainer({ blogPosts, tags }: BlogContainerProps) {
|
||||
aria-label="RSS feed"
|
||||
prefetch={false}
|
||||
>
|
||||
<RssIcon className="h-5 w-5 text-slate-600 hover:text-slate-800 dark:text-slate-400 dark:hover:text-slate-200" />
|
||||
<RssIcon className="h-5 w-5 text-zinc-600 hover:text-zinc-800 dark:text-zinc-400 dark:hover:text-zinc-200" />
|
||||
</Link>
|
||||
<Link
|
||||
href="/blog/atom.xml"
|
||||
aria-label="Atom feed"
|
||||
prefetch={false}
|
||||
>
|
||||
<AtSymbolIcon className="h-5 w-5 text-slate-600 hover:text-slate-800 dark:text-slate-400 dark:hover:text-slate-200" />
|
||||
<AtSymbolIcon className="h-5 w-5 text-zinc-600 hover:text-zinc-800 dark:text-zinc-400 dark:hover:text-zinc-200" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -48,7 +48,7 @@ export function BlogDetails({ post, allPosts }: BlogDetailsProps) {
|
||||
<div className="mx-auto flex justify-between px-4">
|
||||
<Link
|
||||
href="/blog"
|
||||
className="flex w-20 shrink-0 items-center gap-2 text-slate-400 hover:text-slate-800 dark:text-slate-600 dark:hover:text-slate-200"
|
||||
className="flex w-20 shrink-0 items-center gap-2 text-zinc-400 hover:text-zinc-800 dark:text-zinc-600 dark:hover:text-zinc-200"
|
||||
prefetch={false}
|
||||
>
|
||||
<ChevronLeftIcon className="h-3 w-3" />
|
||||
@@ -56,7 +56,7 @@ export function BlogDetails({ post, allPosts }: BlogDetailsProps) {
|
||||
</Link>
|
||||
<div className="flex max-w-sm flex-1 grow items-center justify-end gap-2">
|
||||
<BlogAuthors authors={post.authors} />
|
||||
<span className="text-sm text-slate-400 dark:text-slate-600">
|
||||
<span className="text-sm text-zinc-400 dark:text-zinc-600">
|
||||
{formattedDate}
|
||||
</span>
|
||||
</div>
|
||||
@@ -64,7 +64,7 @@ export function BlogDetails({ post, allPosts }: BlogDetailsProps) {
|
||||
|
||||
{/* Title */}
|
||||
<header className="mx-auto mb-16 mt-8 px-4">
|
||||
<h1 className="text-center text-4xl font-semibold text-slate-900 dark:text-white">
|
||||
<h1 className="text-center text-4xl font-semibold text-zinc-900 dark:text-white">
|
||||
{post.title}
|
||||
</h1>
|
||||
</header>
|
||||
@@ -120,7 +120,7 @@ export function BlogDetails({ post, allPosts }: BlogDetailsProps) {
|
||||
)}
|
||||
<div
|
||||
data-document="main"
|
||||
className="prose prose-lg prose-slate dark:prose-invert w-full max-w-none"
|
||||
className="prose prose-lg prose-zinc dark:prose-invert w-full max-w-none"
|
||||
>
|
||||
{node}
|
||||
</div>
|
||||
@@ -137,10 +137,10 @@ export function BlogDetails({ post, allPosts }: BlogDetailsProps) {
|
||||
|
||||
{/* Related Posts Section */}
|
||||
{post.tags.length > 0 && relatedPosts.length > 0 && (
|
||||
<section className="mt-24 border-b border-t border-slate-200 bg-slate-50 py-24 sm:py-32 dark:border-slate-800 dark:bg-slate-900">
|
||||
<section className="mt-24 border-b border-t border-zinc-200 bg-zinc-50 py-24 sm:py-32 dark:border-zinc-800 dark:bg-zinc-900">
|
||||
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
<div className="mx-auto max-w-2xl lg:mx-0 lg:max-w-none">
|
||||
<h2 className="mb-8 flex items-center gap-3 text-2xl font-semibold text-slate-900 dark:text-white">
|
||||
<h2 className="mb-8 flex items-center gap-3 text-2xl font-semibold text-zinc-900 dark:text-white">
|
||||
{primaryTopic ? (
|
||||
<>
|
||||
<primaryTopic.icon className="h-7 w-7" />
|
||||
|
||||
@@ -10,7 +10,7 @@ export interface BlogEntryProps {
|
||||
|
||||
export function BlogEntry({ post, overrideLink }: BlogEntryProps) {
|
||||
return (
|
||||
<div className="relative flex h-full transform-gpu flex-col overflow-hidden rounded-2xl border border-slate-200 shadow transition-all duration-300 ease-in-out hover:scale-[1.02] hover:shadow-lg dark:border-slate-800">
|
||||
<div className="relative flex h-full transform-gpu flex-col overflow-hidden rounded-2xl border border-zinc-200 shadow transition-all duration-300 ease-in-out hover:scale-[1.02] hover:shadow-lg dark:border-zinc-800">
|
||||
{post.cover_image && (
|
||||
<div className="aspect-[1.7] w-full">
|
||||
<Image
|
||||
@@ -28,7 +28,7 @@ export function BlogEntry({ post, overrideLink }: BlogEntryProps) {
|
||||
<Link
|
||||
href={overrideLink ? overrideLink : `/blog/${post.slug}`}
|
||||
title={post.title}
|
||||
className="text-balance text-lg font-semibold text-slate-900 dark:text-white"
|
||||
className="text-balance text-lg font-semibold text-zinc-900 dark:text-white"
|
||||
prefetch={false}
|
||||
>
|
||||
<span className="absolute inset-0" aria-hidden="true" />
|
||||
|
||||
@@ -65,13 +65,13 @@ export function EpisodePlayer({
|
||||
</div>
|
||||
<div className="flex basis-1/2 flex-wrap justify-end gap-6 sm:gap-4">
|
||||
<button
|
||||
className="flex shrink-0 items-center gap-2 text-slate-400 hover:text-slate-800 dark:text-slate-600 dark:hover:text-slate-200"
|
||||
className="flex shrink-0 items-center gap-2 text-zinc-400 hover:text-zinc-800 dark:text-zinc-600 dark:hover:text-zinc-200"
|
||||
onClick={() => setViewType(getOpposite(viewType))}
|
||||
>
|
||||
Switch to {getOpposite(viewType) === 'audio' ? 'Audio' : 'Video'}
|
||||
</button>
|
||||
<Link
|
||||
className="flex shrink-0 items-center gap-2 text-slate-400 hover:text-slate-800 dark:text-slate-600 dark:hover:text-slate-200"
|
||||
className="flex shrink-0 items-center gap-2 text-zinc-400 hover:text-zinc-800 dark:text-zinc-600 dark:hover:text-zinc-200"
|
||||
href="/podcast"
|
||||
>
|
||||
More Podcasts
|
||||
@@ -124,7 +124,7 @@ export function PlatformLinks({
|
||||
return (
|
||||
<li
|
||||
key={platform.name}
|
||||
className="inline-block cursor-pointer place-items-center rounded-2xl border border-slate-100 bg-white p-4 text-slate-600 transition-all hover:scale-[1.02] hover:text-slate-950 dark:border-slate-800/60 dark:bg-slate-950 dark:text-slate-400 dark:hover:text-white"
|
||||
className="inline-block cursor-pointer place-items-center rounded-2xl border border-zinc-100 bg-white p-4 text-zinc-600 transition-all hover:scale-[1.02] hover:text-zinc-950 dark:border-zinc-800/60 dark:bg-zinc-950 dark:text-zinc-400 dark:hover:text-white"
|
||||
>
|
||||
<a
|
||||
href={platform.url}
|
||||
|
||||
@@ -85,7 +85,7 @@ export function Filters({
|
||||
aria-label={`Filter by ${filter.label}`}
|
||||
scroll={false}
|
||||
prefetch={false}
|
||||
className="flex items-center justify-center gap-2 rounded-full border border-slate-400 bg-white px-2.5 py-1.5 font-medium text-slate-700 shadow-sm transition hover:bg-slate-50 hover:text-slate-600 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-200 dark:hover:bg-slate-700"
|
||||
className="flex items-center justify-center gap-2 rounded-full border border-zinc-400 bg-white px-2.5 py-1.5 font-medium text-zinc-700 shadow-sm transition hover:bg-zinc-50 hover:text-zinc-600 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-200 dark:hover:bg-zinc-700"
|
||||
onClick={() => setSelectedFilterHeading(filter.heading)}
|
||||
>
|
||||
{filter.icon && (
|
||||
@@ -101,7 +101,7 @@ export function Filters({
|
||||
<div className="relative lg:hidden">
|
||||
<Menu as="div" className="inline-block text-left">
|
||||
<MenuButton
|
||||
className="inline-flex w-full justify-center rounded-md border border-slate-400 bg-white px-3 py-1.5 text-sm font-medium text-slate-700 shadow-sm transition hover:bg-slate-50 hover:text-slate-600 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-200 dark:hover:bg-slate-700"
|
||||
className="inline-flex w-full justify-center rounded-md border border-zinc-400 bg-white px-3 py-1.5 text-sm font-medium text-zinc-700 shadow-sm transition hover:bg-zinc-50 hover:text-zinc-600 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-200 dark:hover:bg-zinc-700"
|
||||
aria-label="Select filter topic"
|
||||
>
|
||||
Topics
|
||||
@@ -121,7 +121,7 @@ export function Filters({
|
||||
>
|
||||
<MenuItems
|
||||
as="ul"
|
||||
className="absolute right-0 z-[31] mt-2 flex w-56 origin-top-right flex-col gap-4 rounded-md bg-white p-4 shadow-lg ring-1 ring-black/5 focus:outline-none dark:bg-slate-800 dark:text-white"
|
||||
className="absolute right-0 z-[31] mt-2 flex w-56 origin-top-right flex-col gap-4 rounded-md bg-white p-4 shadow-lg ring-1 ring-black/5 focus:outline-none dark:bg-zinc-800 dark:text-white"
|
||||
aria-label="Filter topics"
|
||||
>
|
||||
{filters
|
||||
|
||||
@@ -24,10 +24,10 @@ export function MoreBlogs({ blogs }: MoreBlogsProps) {
|
||||
<Link
|
||||
href={`/blog/${post.slug}`}
|
||||
key={post.slug}
|
||||
className="relative flex items-center gap-6 border-b border-slate-200 py-5 text-sm before:absolute before:inset-x-[-16px] before:inset-y-[-2px] before:z-[-1] before:rounded-xl before:bg-slate-200 before:opacity-0 last:border-0 before:hover:opacity-100 dark:border-slate-800 dark:before:bg-slate-800/50"
|
||||
className="relative flex items-center gap-6 border-b border-zinc-200 py-5 text-sm before:absolute before:inset-x-[-16px] before:inset-y-[-2px] before:z-[-1] before:rounded-xl before:bg-zinc-200 before:opacity-0 last:border-0 before:hover:opacity-100 dark:border-zinc-800 dark:before:bg-zinc-800/50"
|
||||
prefetch={false}
|
||||
>
|
||||
<span className="w-1/2 flex-none text-balance font-medium text-slate-500 sm:w-5/12 dark:text-white">
|
||||
<span className="w-1/2 flex-none text-balance font-medium text-zinc-500 sm:w-5/12 dark:text-white">
|
||||
{post.title}
|
||||
</span>
|
||||
<span className="w-1/2 flex-none sm:w-3/12">
|
||||
|
||||
@@ -26,13 +26,13 @@ export function LernaBrand() {
|
||||
in a way that confuses Nrwl with another brand.
|
||||
</SectionDescription>
|
||||
</header>
|
||||
<h4 className="mt-4 text-lg leading-8 text-slate-700 sm:text-xl dark:text-slate-300">
|
||||
<h4 className="mt-4 text-lg leading-8 text-zinc-700 sm:text-xl dark:text-zinc-300">
|
||||
Spelling
|
||||
</h4>
|
||||
<p className="mt-2 text-base text-slate-700 dark:text-slate-400">
|
||||
<p className="mt-2 text-base text-zinc-700 dark:text-zinc-400">
|
||||
The preferred written format is Lerna. <br /> For social media
|
||||
usage,
|
||||
<span className="mx-1 inline-flex items-center rounded-full bg-slate-100 px-3 py-0.5 text-sm font-medium text-slate-800 dark:bg-slate-700 dark:text-slate-300">
|
||||
<span className="mx-1 inline-flex items-center rounded-full bg-zinc-100 px-3 py-0.5 text-sm font-medium text-zinc-800 dark:bg-zinc-700 dark:text-zinc-300">
|
||||
#Lerna
|
||||
</span>{' '}
|
||||
is an accepted format.
|
||||
@@ -53,9 +53,9 @@ export function LernaBrand() {
|
||||
</ButtonLink>
|
||||
</div>
|
||||
<div aria-hidden="true">
|
||||
<div className="w-full rounded-md border border-slate-100 bg-slate-50/20 p-4 dark:border-slate-800 dark:bg-slate-800/60">
|
||||
<div className="grid grid-cols-1 items-center justify-items-center rounded-sm bg-white p-2 ring-1 ring-slate-50 dark:bg-slate-800/80 dark:ring-slate-800">
|
||||
<LernaIcon className="m-16 h-36 w-36 text-slate-900 dark:text-slate-100" />
|
||||
<div className="w-full rounded-md border border-zinc-100 bg-zinc-50/20 p-4 dark:border-zinc-800 dark:bg-zinc-800/60">
|
||||
<div className="grid grid-cols-1 items-center justify-items-center rounded-sm bg-white p-2 ring-1 ring-zinc-50 dark:bg-zinc-800/80 dark:ring-zinc-800">
|
||||
<LernaIcon className="m-16 h-36 w-36 text-zinc-900 dark:text-zinc-100" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -26,12 +26,12 @@ export function NxBrand() {
|
||||
a way that confuses Nx with another brand.
|
||||
</SectionDescription>
|
||||
</header>
|
||||
<h4 className="mt-4 text-lg leading-8 text-slate-700 sm:text-xl dark:text-slate-300">
|
||||
<h4 className="mt-4 text-lg leading-8 text-zinc-700 sm:text-xl dark:text-zinc-300">
|
||||
Spelling
|
||||
</h4>
|
||||
<p className="mt-2 text-base text-slate-700 dark:text-slate-400">
|
||||
<p className="mt-2 text-base text-zinc-700 dark:text-zinc-400">
|
||||
The preferred written format is Nx. <br /> For social media usage,
|
||||
<span className="mx-1 inline-flex items-center rounded-full bg-slate-100 px-3 py-0.5 text-sm font-medium text-slate-800 dark:bg-slate-700 dark:text-slate-300">
|
||||
<span className="mx-1 inline-flex items-center rounded-full bg-zinc-100 px-3 py-0.5 text-sm font-medium text-zinc-800 dark:bg-zinc-700 dark:text-zinc-300">
|
||||
#NxDevTools
|
||||
</span>{' '}
|
||||
is an accepted format.
|
||||
@@ -51,9 +51,9 @@ export function NxBrand() {
|
||||
</ButtonLink>
|
||||
</div>
|
||||
<div aria-hidden="true">
|
||||
<div className="w-full rounded-md border border-slate-100 bg-slate-50/20 p-4 dark:border-slate-800 dark:bg-slate-800/60">
|
||||
<div className="grid grid-cols-1 items-center justify-items-center rounded-sm bg-white p-2 ring-1 ring-slate-50 dark:bg-slate-800/80 dark:ring-slate-800">
|
||||
<NxIcon className="m-20 h-28 w-28 text-slate-900 dark:text-slate-100" />
|
||||
<div className="w-full rounded-md border border-zinc-100 bg-zinc-50/20 p-4 dark:border-zinc-800 dark:bg-zinc-800/60">
|
||||
<div className="grid grid-cols-1 items-center justify-items-center rounded-sm bg-white p-2 ring-1 ring-zinc-50 dark:bg-zinc-800/80 dark:ring-zinc-800">
|
||||
<NxIcon className="m-20 h-28 w-28 text-zinc-900 dark:text-zinc-100" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -26,13 +26,13 @@ export function NxCloudBrand() {
|
||||
a way that confuses Nx with another brand.
|
||||
</SectionDescription>
|
||||
</header>
|
||||
<h4 className="mt-4 text-lg leading-8 text-slate-700 sm:text-xl dark:text-slate-300">
|
||||
<h4 className="mt-4 text-lg leading-8 text-zinc-700 sm:text-xl dark:text-zinc-300">
|
||||
Spelling
|
||||
</h4>
|
||||
<p className="mt-2 text-base text-slate-700 dark:text-slate-400">
|
||||
<p className="mt-2 text-base text-zinc-700 dark:text-zinc-400">
|
||||
The preferred written format is Nx Cloud. <br /> For social media
|
||||
usage,
|
||||
<span className="mx-1 inline-flex items-center rounded-full bg-slate-100 px-3 py-0.5 text-sm font-medium text-slate-800 dark:bg-slate-700 dark:text-slate-300">
|
||||
<span className="mx-1 inline-flex items-center rounded-full bg-zinc-100 px-3 py-0.5 text-sm font-medium text-zinc-800 dark:bg-zinc-700 dark:text-zinc-300">
|
||||
#NxCloud
|
||||
</span>{' '}
|
||||
is an accepted format.
|
||||
@@ -53,9 +53,9 @@ export function NxCloudBrand() {
|
||||
</ButtonLink>
|
||||
</div>
|
||||
<div aria-hidden="true">
|
||||
<div className="w-full rounded-md border border-slate-100 bg-slate-50/20 p-4 dark:border-slate-800 dark:bg-slate-800/60">
|
||||
<div className="grid grid-cols-1 items-center justify-items-center rounded-sm bg-white p-2 ring-1 ring-slate-50 dark:bg-slate-800/80 dark:ring-slate-800">
|
||||
<NxCloudIcon className="m-20 h-28 w-28 text-slate-900 dark:text-slate-100" />
|
||||
<div className="w-full rounded-md border border-zinc-100 bg-zinc-50/20 p-4 dark:border-zinc-800 dark:bg-zinc-800/60">
|
||||
<div className="grid grid-cols-1 items-center justify-items-center rounded-sm bg-white p-2 ring-1 ring-zinc-50 dark:bg-zinc-800/80 dark:ring-zinc-800">
|
||||
<NxCloudIcon className="m-20 h-28 w-28 text-zinc-900 dark:text-zinc-100" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -26,13 +26,13 @@ export function NxConsoleBrand() {
|
||||
Nx, or in a way that confuses Nx with another brand.
|
||||
</SectionDescription>
|
||||
</header>
|
||||
<h4 className="mt-4 text-lg leading-8 text-slate-700 sm:text-xl dark:text-slate-300">
|
||||
<h4 className="mt-4 text-lg leading-8 text-zinc-700 sm:text-xl dark:text-zinc-300">
|
||||
Spelling
|
||||
</h4>
|
||||
<p className="mt-2 text-base text-slate-700 dark:text-slate-400">
|
||||
<p className="mt-2 text-base text-zinc-700 dark:text-zinc-400">
|
||||
The preferred written format is Nx Console. <br /> For social media
|
||||
usage,
|
||||
<span className="mx-1 inline-flex items-center rounded-full bg-slate-100 px-3 py-0.5 text-sm font-medium text-slate-800 dark:bg-slate-700 dark:text-slate-300">
|
||||
<span className="mx-1 inline-flex items-center rounded-full bg-zinc-100 px-3 py-0.5 text-sm font-medium text-zinc-800 dark:bg-zinc-700 dark:text-zinc-300">
|
||||
#NxConsole
|
||||
</span>{' '}
|
||||
is an accepted format.
|
||||
@@ -53,9 +53,9 @@ export function NxConsoleBrand() {
|
||||
</ButtonLink>
|
||||
</div>
|
||||
<div aria-hidden="true">
|
||||
<div className="w-full rounded-md border border-slate-100 bg-slate-50/20 p-4 dark:border-slate-800 dark:bg-slate-800/60">
|
||||
<div className="grid grid-cols-1 items-center justify-items-center rounded-sm bg-white p-2 ring-1 ring-slate-50 dark:bg-slate-800/80 dark:ring-slate-800">
|
||||
<NxConsoleIcon className="m-16 h-40 w-40 text-slate-900 dark:text-slate-100" />
|
||||
<div className="w-full rounded-md border border-zinc-100 bg-zinc-50/20 p-4 dark:border-zinc-800 dark:bg-zinc-800/60">
|
||||
<div className="grid grid-cols-1 items-center justify-items-center rounded-sm bg-white p-2 ring-1 ring-zinc-50 dark:bg-zinc-800/80 dark:ring-zinc-800">
|
||||
<NxConsoleIcon className="m-16 h-40 w-40 text-zinc-900 dark:text-zinc-100" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9,10 +9,10 @@ export async function CurrentOpenings({ jobs }: CurrentOpeningsProps) {
|
||||
return (
|
||||
<section
|
||||
id="current-openings"
|
||||
className="border-b border-t border-slate-100 bg-slate-50/40 dark:border-slate-800 dark:bg-slate-800/60"
|
||||
className="border-b border-t border-zinc-100 bg-zinc-50/40 dark:border-zinc-800 dark:bg-zinc-800/60"
|
||||
>
|
||||
<div className="mx-auto max-w-7xl px-4 py-16 sm:px-6 lg:px-8 lg:py-24">
|
||||
<div className="relative mx-auto max-w-lg divide-y divide-slate-100 lg:max-w-7xl dark:divide-slate-700">
|
||||
<div className="relative mx-auto max-w-lg divide-y divide-zinc-100 lg:max-w-7xl dark:divide-zinc-700">
|
||||
<header className="max-w-prose">
|
||||
<SectionHeading as="h2" variant="title" className="mt-4">
|
||||
Current Openings
|
||||
@@ -23,9 +23,9 @@ export async function CurrentOpenings({ jobs }: CurrentOpeningsProps) {
|
||||
{jobs.map((post) => (
|
||||
<div
|
||||
key={post.title}
|
||||
className="relative mt-2 block rounded-lg border border-transparent p-4 transition hover:border-slate-100 hover:shadow-sm dark:hover:border-slate-700"
|
||||
className="relative mt-2 block rounded-lg border border-transparent p-4 transition hover:border-zinc-100 hover:shadow-sm dark:hover:border-zinc-700"
|
||||
>
|
||||
<p className="text-lg font-semibold leading-8 tracking-tight text-slate-800 dark:text-slate-200">
|
||||
<p className="text-lg font-semibold leading-8 tracking-tight text-zinc-800 dark:text-zinc-200">
|
||||
{post.title}
|
||||
</p>
|
||||
<p className="mt-3 text-base">
|
||||
@@ -44,7 +44,7 @@ export async function CurrentOpenings({ jobs }: CurrentOpeningsProps) {
|
||||
))}
|
||||
{!jobs.length ? (
|
||||
<div className="mt-2 block">
|
||||
<p className="text-lg font-semibold leading-8 tracking-tight text-slate-800 dark:text-slate-200">
|
||||
<p className="text-lg font-semibold leading-8 tracking-tight text-zinc-800 dark:text-zinc-200">
|
||||
There are no job openings at this time.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -57,10 +57,10 @@ export function WhatWeOffer(): JSX.Element {
|
||||
<div key={feature.name} className="relative">
|
||||
<dt>
|
||||
<CheckIcon
|
||||
className="absolute mt-1 h-6 w-6 text-blue-500 dark:text-sky-500"
|
||||
className="absolute mt-1 h-6 w-6 text-blue-500 dark:text-blue-500"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<p className="ml-10 text-lg font-semibold leading-8 tracking-tight text-slate-800 dark:text-slate-200">
|
||||
<p className="ml-10 text-lg font-semibold leading-8 tracking-tight text-zinc-800 dark:text-zinc-200">
|
||||
{feature.name}
|
||||
</p>
|
||||
</dt>
|
||||
|
||||
@@ -46,14 +46,14 @@ export function WhyJoinNx(): JSX.Element {
|
||||
<div key={feature.name}>
|
||||
<dt>
|
||||
<feature.icon
|
||||
className="h-8 w-8 text-blue-500 dark:text-sky-500"
|
||||
className="h-8 w-8 text-blue-500 dark:text-blue-500"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<p className="mt-4 text-lg font-semibold leading-8 tracking-tight text-slate-800 dark:text-slate-200">
|
||||
<p className="mt-4 text-lg font-semibold leading-8 tracking-tight text-zinc-800 dark:text-zinc-200">
|
||||
{feature.name}
|
||||
</p>
|
||||
</dt>
|
||||
<dd className="mt-2 text-slate-500 dark:text-slate-400">
|
||||
<dd className="mt-2 text-zinc-500 dark:text-zinc-400">
|
||||
<p className="text-base leading-7">{feature.description}</p>
|
||||
</dd>
|
||||
</div>
|
||||
|
||||
@@ -24,7 +24,7 @@ export function CallToAction(): ReactElement {
|
||||
<svg
|
||||
x="50%"
|
||||
y={0}
|
||||
className="overflow-visible fill-slate-200/20 dark:fill-slate-800/20"
|
||||
className="overflow-visible fill-zinc-200/20 dark:fill-zinc-800/20"
|
||||
>
|
||||
<path
|
||||
d="M-200 0h201v201h-201Z M600 0h201v201h-201Z M-400 600h201v201h-201Z M200 800h201v201h-201Z"
|
||||
@@ -55,7 +55,7 @@ export function CallToAction(): ReactElement {
|
||||
|
||||
{/* Content */}
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h2 className="text-3xl font-medium tracking-tight text-slate-950 sm:text-5xl dark:text-white">
|
||||
<h2 className="text-3xl font-medium tracking-tight text-zinc-950 sm:text-5xl dark:text-white">
|
||||
Don't Let Your CI Slow You Down
|
||||
</h2>
|
||||
<p className="mt-12 text-xl">
|
||||
@@ -66,7 +66,7 @@ export function CallToAction(): ReactElement {
|
||||
href="https://cloud.nx.app/get-started"
|
||||
title="Get started now"
|
||||
prefetch={false}
|
||||
className="rounded-md bg-slate-950 px-3.5 py-2.5 text-sm font-semibold text-slate-100 shadow-sm hover:bg-slate-800 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white dark:bg-white dark:text-slate-900 dark:hover:bg-slate-100"
|
||||
className="rounded-md bg-zinc-950 px-3.5 py-2.5 text-sm font-semibold text-zinc-100 shadow-sm hover:bg-zinc-800 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white dark:bg-white dark:text-zinc-900 dark:hover:bg-zinc-100"
|
||||
>
|
||||
Start here{' '}
|
||||
<span
|
||||
|
||||
@@ -23,7 +23,7 @@ const Card = forwardRef<
|
||||
<div
|
||||
ref={ref}
|
||||
className={cx(
|
||||
'rounded-lg border border-slate-200 bg-slate-50 p-4 shadow-sm backdrop-blur-sm dark:border-slate-800/40 dark:bg-slate-800/60',
|
||||
'rounded-lg border border-zinc-200 bg-zinc-50 p-4 shadow-sm backdrop-blur-sm dark:border-zinc-800/40 dark:bg-zinc-800/60',
|
||||
className
|
||||
)}
|
||||
onMouseEnter={onMouseEnter}
|
||||
@@ -57,7 +57,7 @@ export function CiBottleneckAnimation(): ReactElement {
|
||||
className="border-green-400/60 bg-green-400/40 dark:border-green-800/60 dark:bg-green-800/40"
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-3 text-slate-900 dark:text-slate-100">
|
||||
<div className="flex items-center space-x-3 text-zinc-900 dark:text-zinc-100">
|
||||
<ServerStackIcon
|
||||
aria-hidden="true"
|
||||
className="size-5 shrink-0"
|
||||
@@ -75,7 +75,7 @@ export function CiBottleneckAnimation(): ReactElement {
|
||||
className="border-green-400/60 bg-green-400/40 dark:border-green-800/60 dark:bg-green-800/40"
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-3 text-slate-900 dark:text-slate-100">
|
||||
<div className="flex items-center space-x-3 text-zinc-900 dark:text-zinc-100">
|
||||
<UserPlusIcon
|
||||
aria-hidden="true"
|
||||
className="size-5 shrink-0"
|
||||
@@ -95,7 +95,7 @@ export function CiBottleneckAnimation(): ReactElement {
|
||||
className="border-green-400/60 bg-green-400/40 dark:border-green-800/60 dark:bg-green-800/40"
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-3 text-slate-900 dark:text-slate-100">
|
||||
<div className="flex items-center space-x-3 text-zinc-900 dark:text-zinc-100">
|
||||
<WrenchScrewdriverIcon
|
||||
aria-hidden="true"
|
||||
className="size-5 shrink-0"
|
||||
@@ -114,9 +114,9 @@ export function CiBottleneckAnimation(): ReactElement {
|
||||
<div className="flex flex-col items-center">
|
||||
<Card
|
||||
ref={ciBottleneck}
|
||||
className="relative bg-white dark:border-slate-800/60 dark:bg-slate-950"
|
||||
className="relative bg-white dark:border-zinc-800/60 dark:bg-zinc-950"
|
||||
>
|
||||
<span className="absolute -bottom-8 right-0 hidden items-center gap-x-1.5 rounded-md bg-white px-2 py-1 text-xs font-medium text-slate-400 ring-1 ring-inset ring-slate-200 sm:inline-flex dark:bg-slate-950 dark:ring-slate-800/60">
|
||||
<span className="absolute -bottom-8 right-0 hidden items-center gap-x-1.5 rounded-md bg-white px-2 py-1 text-xs font-medium text-zinc-400 ring-1 ring-inset ring-zinc-200 sm:inline-flex dark:bg-zinc-950 dark:ring-zinc-800/60">
|
||||
<span className="relative flex size-1.5">
|
||||
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-orange-400/80 opacity-75" />
|
||||
<span className="relative inline-flex size-1.5 rounded-full bg-orange-500/80" />
|
||||
@@ -124,7 +124,7 @@ export function CiBottleneckAnimation(): ReactElement {
|
||||
Queue increasing
|
||||
</span>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-3 text-slate-900 dark:text-slate-100">
|
||||
<div className="flex items-center space-x-3 text-zinc-900 dark:text-zinc-100">
|
||||
<FunnelIcon aria-hidden="true" className="size-5 shrink-0" />
|
||||
<div className="flex-1">
|
||||
<p className="font-mono text-xs leading-tight">
|
||||
@@ -143,7 +143,7 @@ export function CiBottleneckAnimation(): ReactElement {
|
||||
className="border-red-400/60 bg-red-400/40 dark:border-red-800/60 dark:bg-red-800/40"
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-3 text-slate-900 dark:text-slate-100">
|
||||
<div className="flex items-center space-x-3 text-zinc-900 dark:text-zinc-100">
|
||||
<ClockIcon aria-hidden="true" className="size-5 shrink-0" />
|
||||
<div className="flex-1">
|
||||
<p className="font-mono text-xs leading-tight">
|
||||
|
||||
@@ -13,7 +13,7 @@ export function CiBottleneck(): ReactElement {
|
||||
return (
|
||||
<section
|
||||
id="ci-bottleneck"
|
||||
className="scroll-mt-24 border-b border-t border-slate-200 bg-slate-50 py-24 sm:py-32 dark:border-slate-800 dark:bg-slate-900"
|
||||
className="scroll-mt-24 border-b border-t border-zinc-200 bg-zinc-50 py-24 sm:py-32 dark:border-zinc-800 dark:bg-zinc-900"
|
||||
>
|
||||
<div className="mx-auto max-w-7xl px-6 lg:px-8">
|
||||
<div className="mx-auto max-w-3xl text-center">
|
||||
@@ -45,7 +45,7 @@ export function CiBottleneck(): ReactElement {
|
||||
key={stat.id}
|
||||
className="flex flex-col bg-white p-8 dark:bg-white/5"
|
||||
>
|
||||
<dt className="text-sm/6 font-semibold text-slate-700 dark:text-slate-300">
|
||||
<dt className="text-sm/6 font-semibold text-zinc-700 dark:text-zinc-300">
|
||||
{stat.name}
|
||||
</dt>
|
||||
<dd className="order-first text-3xl font-semibold tracking-tight text-black dark:text-white">
|
||||
|
||||
@@ -32,13 +32,13 @@ export function CustomerMetrics(): ReactElement {
|
||||
}}
|
||||
className="group relative block rounded-2xl"
|
||||
>
|
||||
<div className="absolute inset-0 z-10 flex items-center justify-center rounded-2xl bg-white/60 opacity-0 backdrop-blur-sm transition duration-300 group-hover:opacity-100 dark:bg-slate-950/60">
|
||||
<div className="flex items-center gap-2 text-lg font-semibold text-slate-950 drop-shadow dark:text-white">
|
||||
<div className="absolute inset-0 z-10 flex items-center justify-center rounded-2xl bg-white/60 opacity-0 backdrop-blur-sm transition duration-300 group-hover:opacity-100 dark:bg-zinc-950/60">
|
||||
<div className="flex items-center gap-2 text-lg font-semibold text-zinc-950 drop-shadow dark:text-white">
|
||||
<PlayIcon className="size-8" />
|
||||
Watch the interview
|
||||
</div>
|
||||
</div>
|
||||
<figure className="relative rounded-2xl bg-white shadow-lg ring-1 ring-slate-900/5 dark:bg-slate-800">
|
||||
<figure className="relative rounded-2xl bg-white shadow-lg ring-1 ring-zinc-900/5 dark:bg-zinc-800">
|
||||
<blockquote className="p-6 text-lg font-semibold tracking-tight text-black dark:text-white">
|
||||
<p>
|
||||
The number of hours we spent trying to manage CI before,
|
||||
@@ -50,15 +50,15 @@ export function CustomerMetrics(): ReactElement {
|
||||
it fast."
|
||||
</p>
|
||||
</blockquote>
|
||||
<figcaption className="flex flex-wrap items-center gap-x-4 gap-y-4 border-t border-slate-900/10 px-6 py-4 sm:flex-nowrap dark:border-slate-100/10">
|
||||
<figcaption className="flex flex-wrap items-center gap-x-4 gap-y-4 border-t border-zinc-900/10 px-6 py-4 sm:flex-nowrap dark:border-zinc-100/10">
|
||||
<img
|
||||
alt="Nicolas Beaussart image"
|
||||
src="https://avatars.githubusercontent.com/u/7281023?v=4"
|
||||
className="size-10 rounded-full bg-slate-50"
|
||||
className="size-10 rounded-full bg-zinc-50"
|
||||
/>
|
||||
<div className="flex-auto">
|
||||
<div className="font-semibold">Nicolas Beaussart</div>
|
||||
<div className="text-slate-600 dark:text-slate-500">
|
||||
<div className="text-zinc-600 dark:text-zinc-500">
|
||||
Staff Platform Engineer, Payfit
|
||||
</div>
|
||||
</div>
|
||||
@@ -86,19 +86,19 @@ export function CustomerMetrics(): ReactElement {
|
||||
</div>
|
||||
<div className="lg:flex lg:flex-auto lg:justify-center">
|
||||
<dl className="flex flex-col justify-center gap-8 sm:flex-row lg:flex-col xl:w-80">
|
||||
<div className="flex flex-col-reverse gap-y-1 border-slate-200 pl-4 text-center sm:border-l sm:text-left dark:border-slate-800">
|
||||
<div className="flex flex-col-reverse gap-y-1 border-zinc-200 pl-4 text-center sm:border-l sm:text-left dark:border-zinc-800">
|
||||
<dt className="text-base/7">faster CI</dt>
|
||||
<dd className="[text-shadow:1px 1px 0 white;] te text-5xl font-semibold tracking-tight text-black dark:text-white">
|
||||
70%
|
||||
</dd>
|
||||
</div>
|
||||
<div className="flex flex-col-reverse gap-y-1 border-slate-200 pl-4 text-center sm:border-l sm:text-left dark:border-slate-800">
|
||||
<div className="flex flex-col-reverse gap-y-1 border-zinc-200 pl-4 text-center sm:border-l sm:text-left dark:border-zinc-800">
|
||||
<dt className="text-base/7">less compute used</dt>
|
||||
<dd className="text-5xl font-semibold tracking-tight text-black dark:text-white">
|
||||
60%
|
||||
</dd>
|
||||
</div>
|
||||
<div className="flex flex-col-reverse gap-y-1 border-slate-200 pl-4 text-center sm:border-l sm:text-left dark:border-slate-800">
|
||||
<div className="flex flex-col-reverse gap-y-1 border-zinc-200 pl-4 text-center sm:border-l sm:text-left dark:border-zinc-800">
|
||||
<dt className="text-base/7">reduction in infra costs</dt>
|
||||
<dd className="text-5xl font-semibold tracking-tight text-black dark:text-white">
|
||||
75%
|
||||
|
||||
@@ -161,7 +161,7 @@ export function Faq(): ReactElement {
|
||||
Check out our most commonly asked questions.
|
||||
</SectionHeading>
|
||||
|
||||
<p className="text-md mt-4 text-slate-400 dark:text-slate-600">
|
||||
<p className="text-md mt-4 text-zinc-400 dark:text-zinc-600">
|
||||
<Link
|
||||
href="/contact"
|
||||
title="Reach out to the team"
|
||||
@@ -186,14 +186,14 @@ export function Faq(): ReactElement {
|
||||
}))}
|
||||
/>
|
||||
<div className="mt-12 lg:col-span-2 lg:mt-0">
|
||||
<dl className="mt-6 space-y-6 divide-y divide-slate-100 dark:divide-slate-800">
|
||||
<dl className="mt-6 space-y-6 divide-y divide-zinc-100 dark:divide-zinc-800">
|
||||
{faqs.map((faq) => (
|
||||
<Disclosure as="div" key={faq.question} className="pt-6">
|
||||
{({ open }) => (
|
||||
<>
|
||||
<dt className="text-lg">
|
||||
<DisclosureButton className="flex w-full items-start justify-between text-left text-slate-400">
|
||||
<span className="font-medium text-slate-800 dark:text-slate-300">
|
||||
<DisclosureButton className="flex w-full items-start justify-between text-left text-zinc-400">
|
||||
<span className="font-medium text-zinc-800 dark:text-zinc-300">
|
||||
{faq.question}
|
||||
</span>
|
||||
<span className="ml-6 flex h-7 items-center">
|
||||
@@ -217,7 +217,7 @@ export function Faq(): ReactElement {
|
||||
>
|
||||
<DisclosurePanel
|
||||
as="dd"
|
||||
className="mt-2 pr-12 text-base text-slate-500 dark:text-slate-400"
|
||||
className="mt-2 pr-12 text-base text-zinc-500 dark:text-zinc-400"
|
||||
>
|
||||
{faq.answerUi}
|
||||
</DisclosurePanel>
|
||||
|
||||
@@ -5,7 +5,7 @@ export function Features(): ReactElement {
|
||||
return (
|
||||
<section
|
||||
id="features"
|
||||
className="scroll-mt-24 border-b border-t border-slate-200 bg-slate-50 py-24 sm:py-32 dark:border-slate-800 dark:bg-slate-900"
|
||||
className="scroll-mt-24 border-b border-t border-zinc-200 bg-zinc-50 py-24 sm:py-32 dark:border-zinc-800 dark:bg-zinc-900"
|
||||
>
|
||||
<div className="mx-auto max-w-7xl px-6 lg:px-8">
|
||||
<div className="mx-auto max-w-3xl text-center">
|
||||
@@ -19,14 +19,14 @@ export function Features(): ReactElement {
|
||||
</div>
|
||||
<div className="mx-auto mt-12 grid max-w-5xl grid-cols-1 gap-4 sm:mt-16 md:grid-cols-2">
|
||||
<div className="relative">
|
||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(theme(borderRadius.lg)+1px)] bg-white shadow ring-1 ring-black/5 lg:rounded-tl-[calc(2rem+1px)] dark:bg-slate-950 dark:ring-white/10">
|
||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(theme(borderRadius.lg)+1px)] bg-white shadow ring-1 ring-black/5 lg:rounded-tl-[calc(2rem+1px)] dark:bg-zinc-950 dark:ring-white/10">
|
||||
<img
|
||||
alt="Nx Replay: remote caching"
|
||||
src="/images/enterprise/nx-replay.avif"
|
||||
className="h-80 object-cover object-center"
|
||||
/>
|
||||
<div className="relative p-10 pt-4">
|
||||
<h3 className="text-lg font-medium tracking-tight text-slate-950 dark:text-white">
|
||||
<h3 className="text-lg font-medium tracking-tight text-zinc-950 dark:text-white">
|
||||
Secure Remote Cache
|
||||
</h3>
|
||||
<p className="mt-2 max-w-lg text-sm/6">
|
||||
@@ -38,14 +38,14 @@ export function Features(): ReactElement {
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(theme(borderRadius.lg)+1px)] bg-white shadow ring-1 ring-black/5 lg:rounded-tr-[calc(2rem+1px)] dark:bg-slate-950 dark:ring-white/10">
|
||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(theme(borderRadius.lg)+1px)] bg-white shadow ring-1 ring-black/5 lg:rounded-tr-[calc(2rem+1px)] dark:bg-zinc-950 dark:ring-white/10">
|
||||
<img
|
||||
alt="Nx flaky task detection & rerun"
|
||||
src="/images/enterprise/nx-flaky-tasks-detection.avif"
|
||||
className="h-80 object-cover"
|
||||
/>
|
||||
<div className="relative p-10 pt-4">
|
||||
<h3 className="text-lg font-medium tracking-tight text-slate-950 dark:text-white">
|
||||
<h3 className="text-lg font-medium tracking-tight text-zinc-950 dark:text-white">
|
||||
Self-Healing CI
|
||||
</h3>
|
||||
<p className="mt-2 max-w-lg text-sm/6">
|
||||
@@ -57,14 +57,14 @@ export function Features(): ReactElement {
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(theme(borderRadius.lg)+1px)] bg-white shadow ring-1 ring-black/5 dark:bg-slate-950 dark:ring-white/10">
|
||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(theme(borderRadius.lg)+1px)] bg-white shadow ring-1 ring-black/5 dark:bg-zinc-950 dark:ring-white/10">
|
||||
<img
|
||||
alt="Nx Atomizer: split large tasks & E2E in chunks"
|
||||
src="/images/enterprise/nx-atomizer.avif"
|
||||
className="h-80 object-cover object-center"
|
||||
/>
|
||||
<div className="relative p-10 pt-4">
|
||||
<h3 className="text-lg font-medium tracking-tight text-slate-950 dark:text-white">
|
||||
<h3 className="text-lg font-medium tracking-tight text-zinc-950 dark:text-white">
|
||||
E2E Test Splitting
|
||||
</h3>
|
||||
<p className="mt-2 max-w-lg text-sm/6">
|
||||
@@ -76,14 +76,14 @@ export function Features(): ReactElement {
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(theme(borderRadius.lg)+1px)] bg-white shadow ring-1 ring-black/5 dark:bg-slate-950 dark:ring-white/10">
|
||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(theme(borderRadius.lg)+1px)] bg-white shadow ring-1 ring-black/5 dark:bg-zinc-950 dark:ring-white/10">
|
||||
<img
|
||||
alt="Nx Agents: simple & fast task distribution"
|
||||
src="/images/enterprise/nx-agents.avif"
|
||||
className="h-80 object-cover object-center"
|
||||
/>
|
||||
<div className="relative p-10 pt-4">
|
||||
<h3 className="text-lg font-medium tracking-tight text-slate-950 dark:text-white">
|
||||
<h3 className="text-lg font-medium tracking-tight text-zinc-950 dark:text-white">
|
||||
Distributed Task Execution
|
||||
</h3>
|
||||
<p className="mt-2 max-w-lg text-sm/6">
|
||||
@@ -95,7 +95,7 @@ export function Features(): ReactElement {
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(theme(borderRadius.lg)+1px)] bg-white shadow ring-1 ring-black/5 lg:rounded-bl-[calc(2rem+1px)] dark:bg-slate-800 dark:ring-white/10">
|
||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(theme(borderRadius.lg)+1px)] bg-white shadow ring-1 ring-black/5 lg:rounded-bl-[calc(2rem+1px)] dark:bg-zinc-800 dark:ring-white/10">
|
||||
<img
|
||||
alt="Nx Agents: simple & fast task distribution"
|
||||
src="/images/enterprise/visibility.avif"
|
||||
@@ -103,11 +103,11 @@ export function Features(): ReactElement {
|
||||
/>
|
||||
<div className="relative p-10 pt-4">
|
||||
<div className="absolute -top-10 left-10">
|
||||
<span className="inline-flex items-center rounded-md bg-slate-400/10 px-2 py-1 text-xs font-medium text-slate-400 ring-1 ring-inset ring-slate-400/20">
|
||||
<span className="inline-flex items-center rounded-md bg-zinc-400/10 px-2 py-1 text-xs font-medium text-zinc-400 ring-1 ring-inset ring-zinc-400/20">
|
||||
Enterprise
|
||||
</span>
|
||||
</div>
|
||||
<h3 className="text-lg font-medium tracking-tight text-slate-950 dark:text-white">
|
||||
<h3 className="text-lg font-medium tracking-tight text-zinc-950 dark:text-white">
|
||||
See Dependencies Across Teams & Repositories
|
||||
</h3>
|
||||
<p className="mt-2 max-w-lg text-sm/6">
|
||||
@@ -121,7 +121,7 @@ export function Features(): ReactElement {
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(theme(borderRadius.lg)+1px)] bg-white shadow ring-1 ring-black/5 lg:rounded-br-[calc(2rem+1px)] dark:bg-slate-800 dark:ring-white/10">
|
||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(theme(borderRadius.lg)+1px)] bg-white shadow ring-1 ring-black/5 lg:rounded-br-[calc(2rem+1px)] dark:bg-zinc-800 dark:ring-white/10">
|
||||
<img
|
||||
alt="Nx Atomizer: split large tasks & E2E in chunks"
|
||||
src="/images/enterprise/conformance.avif"
|
||||
@@ -129,11 +129,11 @@ export function Features(): ReactElement {
|
||||
/>
|
||||
<div className="relative p-10 pt-4">
|
||||
<div className="absolute -top-10 left-10">
|
||||
<span className="inline-flex items-center rounded-md bg-slate-400/10 px-2 py-1 text-xs font-medium text-slate-400 ring-1 ring-inset ring-slate-400/20">
|
||||
<span className="inline-flex items-center rounded-md bg-zinc-400/10 px-2 py-1 text-xs font-medium text-zinc-400 ring-1 ring-inset ring-zinc-400/20">
|
||||
Enterprise
|
||||
</span>
|
||||
</div>
|
||||
<h3 className="text-lg font-medium tracking-tight text-slate-950 dark:text-white">
|
||||
<h3 className="text-lg font-medium tracking-tight text-zinc-950 dark:text-white">
|
||||
Streamline Onboarding & Governance
|
||||
</h3>
|
||||
<p className="mt-2 max-w-lg text-sm/6">
|
||||
|
||||
@@ -12,14 +12,14 @@ export function GetStarted(): ReactElement {
|
||||
as="h2"
|
||||
variant="title"
|
||||
id="get-started-title"
|
||||
className="text-white dark:text-slate-950"
|
||||
className="text-white dark:text-zinc-950"
|
||||
>
|
||||
Get Started
|
||||
</SectionHeading>
|
||||
<SectionHeading
|
||||
as="p"
|
||||
variant="subtitle"
|
||||
className="mt-8 text-white dark:text-slate-950"
|
||||
className="mt-8 text-white dark:text-zinc-950"
|
||||
>
|
||||
In 5 minutes, you'll see the difference.
|
||||
</SectionHeading>
|
||||
|
||||
@@ -18,7 +18,7 @@ export function NxCloudHeroVideo(): ReactElement {
|
||||
<div className="h-20 w-20 bg-[radial-gradient(var(--blue-500)_40%,transparent_60%)] opacity-[0.8] dark:bg-[radial-gradient(var(--pink-500)_40%,transparent_60%)]" />
|
||||
</MovingBorder>
|
||||
</div>
|
||||
<picture className="relative flex h-full w-full items-center justify-center overflow-hidden rounded-xl border border-slate-100 bg-slate-50 antialiased backdrop-blur-xl dark:border-slate-900 dark:bg-slate-900/[0.8]">
|
||||
<picture className="relative flex h-full w-full items-center justify-center overflow-hidden rounded-xl border border-zinc-100 bg-zinc-50 antialiased backdrop-blur-xl dark:border-zinc-900 dark:bg-zinc-900/[0.8]">
|
||||
<Image
|
||||
src="/images/cloud/nrwl-ocean.avif"
|
||||
alt="App screenshot: overview"
|
||||
|
||||
@@ -51,14 +51,14 @@ export function PlayButton({
|
||||
>
|
||||
<div className="absolute inset-0">
|
||||
<MovingBorder duration={5000} rx="5%" ry="5%">
|
||||
<div className="size-20 bg-[radial-gradient(var(--blue-500)_40%,transparent_60%)] opacity-[0.8] dark:bg-[radial-gradient(var(--sky-500)_40%,transparent_60%)]" />
|
||||
<div className="size-20 bg-[radial-gradient(var(--blue-500)_40%,transparent_60%)] opacity-[0.8] dark:bg-[radial-gradient(var(--blue-500)_40%,transparent_60%)]" />
|
||||
</MovingBorder>
|
||||
</div>
|
||||
<motion.div
|
||||
initial="initial"
|
||||
whileHover="hover"
|
||||
variants={parent}
|
||||
className="relative isolate flex size-20 cursor-pointer items-center justify-center gap-6 rounded-full border-2 border-slate-100 bg-white/10 p-6 text-slate-950 antialiased backdrop-blur-xl"
|
||||
className="relative isolate flex size-20 cursor-pointer items-center justify-center gap-6 rounded-full border-2 border-zinc-100 bg-white/10 p-6 text-zinc-950 antialiased backdrop-blur-xl"
|
||||
>
|
||||
<PlayIcon aria-hidden="true" className="absolute left-6 top-6 size-8" />
|
||||
<motion.div variants={child} className="absolute left-20 top-4 w-48">
|
||||
|
||||
@@ -139,7 +139,7 @@ export function NxCloudHero(): ReactElement {
|
||||
<ButtonLink
|
||||
href="https://cloud.nx.app/get-started"
|
||||
title="Nx AI Integration"
|
||||
variant="primary"
|
||||
variant="contrast"
|
||||
size="default"
|
||||
onClick={() =>
|
||||
sendCustomEvent(
|
||||
|
||||
@@ -10,7 +10,7 @@ export function Pricing(): ReactElement {
|
||||
return (
|
||||
<section
|
||||
id="plans"
|
||||
className="scroll-mt-24 border-b border-t border-slate-200 bg-slate-50 py-24 sm:py-32 dark:border-slate-800 dark:bg-slate-900"
|
||||
className="scroll-mt-24 border-b border-t border-zinc-200 bg-zinc-50 py-24 sm:py-32 dark:border-zinc-800 dark:bg-zinc-900"
|
||||
>
|
||||
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
<header className="mx-auto max-w-4xl text-center">
|
||||
@@ -39,9 +39,9 @@ export function Pricing(): ReactElement {
|
||||
<div className="isolate -mt-16 grid max-w-full grid-cols-1 gap-6 sm:mx-auto lg:mt-0 lg:grid-cols-3 xl:-mx-4 xl:gap-8">
|
||||
{/*HOBBY*/}
|
||||
<div>
|
||||
<div className="rounded-lg border-2 border-blue-500 bg-white p-6 dark:border-sky-500 dark:bg-slate-950">
|
||||
<div className="rounded-lg border-2 border-blue-500 bg-white p-6 dark:border-blue-500 dark:bg-zinc-950">
|
||||
<div className="flex items-center gap-x-2">
|
||||
<h4 className="text-xl font-semibold leading-8 text-slate-950 dark:text-white">
|
||||
<h4 className="text-xl font-semibold leading-8 text-zinc-950 dark:text-white">
|
||||
Hobby
|
||||
</h4>
|
||||
<span className="inline-flex items-center rounded-md bg-blue-50 px-2 py-1 text-xs font-medium text-blue-700 ring-1 ring-inset ring-blue-700/10 dark:bg-blue-400/10 dark:text-blue-400 dark:ring-blue-400/30">
|
||||
@@ -53,7 +53,7 @@ export function Pricing(): ReactElement {
|
||||
product. No credit card required.
|
||||
</p>
|
||||
<p className="mt-4 pb-5 leading-5">
|
||||
<span className="text-3xl font-semibold text-slate-950 dark:text-white">
|
||||
<span className="text-3xl font-semibold text-zinc-950 dark:text-white">
|
||||
$0
|
||||
</span>
|
||||
</p>
|
||||
@@ -63,7 +63,7 @@ export function Pricing(): ReactElement {
|
||||
aria-describedby="hobby-plan"
|
||||
title="Start now"
|
||||
size="default"
|
||||
variant="primary"
|
||||
variant="contrast"
|
||||
onClick={() =>
|
||||
sendCustomEvent(
|
||||
'start-hobby-plan-click',
|
||||
@@ -76,21 +76,21 @@ export function Pricing(): ReactElement {
|
||||
Start now
|
||||
</ButtonLink>
|
||||
</div>
|
||||
<ul className="mt-4 divide-y divide-slate-200 text-sm dark:divide-slate-800">
|
||||
<ul className="mt-4 divide-y divide-zinc-200 text-sm dark:divide-zinc-800">
|
||||
<li className="py-2.5">
|
||||
<span className="font-medium">Included for free</span>
|
||||
</li>
|
||||
<li className="flex items-center justify-start gap-x-2 py-2.5">
|
||||
<CheckCircleIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-blue-500"
|
||||
/>
|
||||
<span>50,000 monthly credits</span>
|
||||
</li>
|
||||
<li className="flex items-center justify-start gap-x-2 py-2.5">
|
||||
<CheckCircleIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-blue-500"
|
||||
/>
|
||||
<Link
|
||||
href="/ai"
|
||||
@@ -111,7 +111,7 @@ export function Pricing(): ReactElement {
|
||||
<li className="flex items-center justify-start gap-x-2 py-2.5">
|
||||
<CheckCircleIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-blue-500"
|
||||
/>
|
||||
<span>
|
||||
Remote caching with{' '}
|
||||
@@ -135,7 +135,7 @@ export function Pricing(): ReactElement {
|
||||
<li className="flex items-center justify-start gap-x-2 py-2.5">
|
||||
<CheckCircleIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-blue-500"
|
||||
/>
|
||||
<span>
|
||||
Distributed task execution with{' '}
|
||||
@@ -163,9 +163,9 @@ export function Pricing(): ReactElement {
|
||||
</div>
|
||||
|
||||
{/*TEAM*/}
|
||||
<div className="rounded-lg border border-slate-200 bg-white p-6 dark:border-slate-800 dark:bg-slate-950">
|
||||
<div className="rounded-lg border border-zinc-200 bg-white p-6 dark:border-zinc-800 dark:bg-zinc-950">
|
||||
<div className="flex items-center gap-x-2">
|
||||
<h4 className="text-xl font-semibold leading-8 text-slate-950 dark:text-white">
|
||||
<h4 className="text-xl font-semibold leading-8 text-zinc-950 dark:text-white">
|
||||
Team
|
||||
</h4>
|
||||
</div>
|
||||
@@ -173,7 +173,7 @@ export function Pricing(): ReactElement {
|
||||
Start free, pay as you grow. Billed on the first of each month.
|
||||
</p>
|
||||
<p className="mt-4 leading-5">
|
||||
<span className="text-3xl font-semibold text-slate-950 dark:text-white">
|
||||
<span className="text-3xl font-semibold text-zinc-950 dark:text-white">
|
||||
$19
|
||||
</span>
|
||||
<span className="text-lg"> per Active Contributor¹</span>{' '}
|
||||
@@ -203,35 +203,35 @@ export function Pricing(): ReactElement {
|
||||
Free to start
|
||||
</ButtonLink>
|
||||
</div>
|
||||
<ul className="mt-4 divide-y divide-slate-200 text-sm dark:divide-slate-800">
|
||||
<ul className="mt-4 divide-y divide-zinc-200 text-sm dark:divide-zinc-800">
|
||||
<li className="py-2.5">
|
||||
<span className="font-medium">Included for free</span>
|
||||
</li>
|
||||
<li className="flex items-center justify-start gap-x-2 py-2.5">
|
||||
<CheckCircleIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-blue-500"
|
||||
/>
|
||||
<span>5 active contributors¹</span>
|
||||
</li>
|
||||
<li className="flex items-center justify-start gap-x-2 py-2.5">
|
||||
<CheckCircleIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-blue-500"
|
||||
/>
|
||||
<span>50,000 monthly credits</span>
|
||||
</li>
|
||||
<li className="flex items-center justify-start gap-x-2 py-2.5">
|
||||
<CheckCircleIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-blue-500"
|
||||
/>
|
||||
<span>10 concurrent CI connections</span>
|
||||
</li>
|
||||
<li className="flex items-center justify-start gap-x-2 py-2.5">
|
||||
<CheckCircleIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-blue-500"
|
||||
/>
|
||||
<Link
|
||||
href="/ai"
|
||||
@@ -252,7 +252,7 @@ export function Pricing(): ReactElement {
|
||||
<li className="flex items-center justify-start gap-x-2 py-2.5">
|
||||
<CheckCircleIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-blue-500"
|
||||
/>
|
||||
<span>Email support</span>
|
||||
</li>
|
||||
@@ -262,35 +262,35 @@ export function Pricing(): ReactElement {
|
||||
<li className="flex items-center justify-start gap-x-2 py-2.5">
|
||||
<PlusIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-blue-500"
|
||||
/>
|
||||
<span>$19 per active contributor¹ / month</span>
|
||||
</li>
|
||||
<li className="flex items-center justify-start gap-x-2 py-2.5">
|
||||
<PlusIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-blue-500"
|
||||
/>
|
||||
<span>$5.50 per 10,000 credits</span>
|
||||
</li>
|
||||
<li className="flex items-center justify-start gap-x-2 py-2.5">
|
||||
<PlusIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-blue-500"
|
||||
/>
|
||||
<span>$2.25 per concurrent CI connection</span>
|
||||
</li>
|
||||
</ul>
|
||||
<p className="mt-4 text-xs text-slate-500">
|
||||
<p className="mt-4 text-xs text-zinc-500">
|
||||
¹Any person or actor that has triggered a CI Pipeline Execution
|
||||
within the current billing cycle. Up to 50 active contributors.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* ENTERPRISE */}
|
||||
<div className="rounded-lg border border-slate-200 bg-slate-50/60 p-6 dark:border-slate-800 dark:bg-slate-900">
|
||||
<div className="rounded-lg border border-zinc-200 bg-zinc-50/60 p-6 dark:border-zinc-800 dark:bg-zinc-900">
|
||||
<div className="flex items-center gap-x-2">
|
||||
<h4 className="text-xl font-semibold leading-8 text-slate-950 dark:text-white">
|
||||
<h4 className="text-xl font-semibold leading-8 text-zinc-950 dark:text-white">
|
||||
Enterprise
|
||||
</h4>
|
||||
</div>
|
||||
@@ -299,7 +299,7 @@ export function Pricing(): ReactElement {
|
||||
& payment options available.
|
||||
</p>
|
||||
<p className="mt-4 pb-5 leading-5">
|
||||
<span className="text-3xl font-semibold text-slate-950 dark:text-white">
|
||||
<span className="text-3xl font-semibold text-zinc-950 dark:text-white">
|
||||
Custom
|
||||
</span>
|
||||
</p>
|
||||
@@ -322,28 +322,28 @@ export function Pricing(): ReactElement {
|
||||
Request a trial
|
||||
</ButtonLink>
|
||||
</div>
|
||||
<ul className="mt-4 divide-y divide-slate-200 text-sm dark:divide-slate-800">
|
||||
<ul className="mt-4 divide-y divide-zinc-200 text-sm dark:divide-zinc-800">
|
||||
<li className="py-2.5">
|
||||
<span className="font-medium">Includes</span>
|
||||
</li>
|
||||
<li className="flex items-center justify-start gap-x-2 py-2.5">
|
||||
<CheckCircleIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-blue-500"
|
||||
/>
|
||||
<span>Volume discounts on credits available</span>
|
||||
</li>
|
||||
<li className="flex items-center justify-start gap-x-2 py-2.5">
|
||||
<CheckCircleIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-blue-500"
|
||||
/>
|
||||
<span>White glove onboarding</span>
|
||||
</li>
|
||||
<li className="flex items-center justify-start gap-x-2 py-2.5">
|
||||
<CheckCircleIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-blue-500"
|
||||
/>
|
||||
<span>
|
||||
<Link
|
||||
@@ -367,7 +367,7 @@ export function Pricing(): ReactElement {
|
||||
<li className="flex items-center justify-start gap-x-2 py-2.5">
|
||||
<CheckCircleIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-blue-500"
|
||||
/>
|
||||
<span>
|
||||
Work hand-in-hand with the Nx team for continual improvement
|
||||
@@ -376,7 +376,7 @@ export function Pricing(): ReactElement {
|
||||
<li className="flex items-center justify-start gap-x-2 py-2.5">
|
||||
<CheckCircleIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-blue-500"
|
||||
/>
|
||||
<span>
|
||||
Run on the Nx Cloud servers in any region or run fully
|
||||
@@ -386,14 +386,14 @@ export function Pricing(): ReactElement {
|
||||
<li className="flex items-center justify-start gap-x-2 py-2.5">
|
||||
<CheckCircleIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-blue-500"
|
||||
/>
|
||||
<span>SSO / SAML Login</span>
|
||||
</li>
|
||||
<li className="flex items-center justify-start gap-x-2 py-2.5">
|
||||
<CheckCircleIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-blue-500"
|
||||
/>
|
||||
<span>Premium Support and SLAs available</span>
|
||||
</li>
|
||||
|
||||
@@ -41,7 +41,7 @@ export function Security(): ReactElement {
|
||||
and other regulated industries. Don't compromise.
|
||||
</SectionHeading>
|
||||
<div className="mt-8 flex flex-wrap items-center gap-4 md:gap-8">
|
||||
<div className="flex w-52 shrink-0 items-center gap-2 rounded-xl px-2 py-1 text-xs text-slate-950 ring-1 ring-slate-200 dark:text-slate-50 dark:ring-slate-700">
|
||||
<div className="flex w-52 shrink-0 items-center gap-2 rounded-xl px-2 py-1 text-xs text-zinc-950 ring-1 ring-zinc-200 dark:text-zinc-50 dark:ring-zinc-700">
|
||||
<svg
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
||||
@@ -25,7 +25,7 @@ export function TimeToGreen(): ReactElement {
|
||||
<h3 className="text-xl font-semibold">Average Time To Green</h3>
|
||||
|
||||
<div className="mt-2">
|
||||
<div className="relative grid grid-cols-1 rounded-lg bg-slate-50 text-xs font-medium text-slate-900 ring-1 ring-slate-200 sm:h-12 sm:grid-cols-12 dark:bg-slate-900 dark:text-slate-100 dark:ring-white/10">
|
||||
<div className="relative grid grid-cols-1 rounded-lg bg-zinc-50 text-xs font-medium text-zinc-900 ring-1 ring-zinc-200 sm:h-12 sm:grid-cols-12 dark:bg-zinc-900 dark:text-zinc-100 dark:ring-white/10">
|
||||
<div className="flex h-12 items-center justify-center rounded-t-lg bg-blue-400/40 sm:col-span-2 sm:h-auto sm:rounded-l-lg sm:rounded-r-none dark:bg-blue-600/40">
|
||||
<span className="px-2">Write Code</span>
|
||||
</div>
|
||||
@@ -50,7 +50,7 @@ export function TimeToGreen(): ReactElement {
|
||||
<h3 className="text-xl font-semibold">Time To Green with Nx Cloud</h3>
|
||||
<div className="mt-2 grid grid-cols-1 sm:h-12 sm:grid-cols-12">
|
||||
<div className="col-span-4 grid grid-cols-1 sm:grid-cols-6">
|
||||
<div className="grid grid-cols-1 rounded-lg bg-slate-50 text-xs font-medium text-slate-900 ring-1 ring-slate-200 sm:col-span-5 sm:grid-cols-10 dark:bg-slate-900 dark:text-slate-100 dark:ring-white/10">
|
||||
<div className="grid grid-cols-1 rounded-lg bg-zinc-50 text-xs font-medium text-zinc-900 ring-1 ring-zinc-200 sm:col-span-5 sm:grid-cols-10 dark:bg-zinc-900 dark:text-zinc-100 dark:ring-white/10">
|
||||
<div className="flex h-12 items-center justify-center rounded-t-lg bg-blue-400/40 sm:col-span-6 sm:h-auto sm:rounded-l-lg sm:rounded-r-none dark:bg-blue-600/40">
|
||||
<span className="px-2">Write Code</span>
|
||||
</div>
|
||||
|
||||
@@ -39,13 +39,10 @@ export function InlineCommand({
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className="font-input-mono duration-180 flex w-full flex-none items-center justify-center space-x-2 rounded-md border border-slate-300 bg-white py-1 text-sm leading-6 text-slate-400 transition-colors hover:text-slate-800 focus:outline-none focus:ring-2 focus:ring-slate-300 focus:ring-offset-2 focus:ring-offset-white sm:max-w-full sm:space-x-4 sm:px-3"
|
||||
className="font-input-mono duration-180 flex w-full flex-none items-center justify-center space-x-2 rounded-md border border-zinc-300 bg-white py-1 text-sm leading-6 text-zinc-400 transition-colors hover:text-zinc-800 focus:outline-none focus:ring-2 focus:ring-zinc-300 focus:ring-offset-2 focus:ring-offset-white sm:max-w-full sm:space-x-4 sm:px-3"
|
||||
>
|
||||
<span className="flex items-center overflow-auto text-slate-800">
|
||||
<span
|
||||
className="hidden text-slate-500 sm:inline"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<span className="flex items-center overflow-auto text-zinc-800">
|
||||
<span className="hidden text-zinc-500 sm:inline" aria-hidden="true">
|
||||
$
|
||||
</span>
|
||||
<SyntaxHighlighter
|
||||
|
||||
@@ -2,7 +2,7 @@ import Link from 'next/link';
|
||||
|
||||
export function AnnouncementBanner(): JSX.Element {
|
||||
return (
|
||||
<div className="group relative border border-y border-slate-200 bg-slate-50/40 transition hover:bg-slate-50 dark:border-slate-800/40 dark:bg-slate-800/60 dark:hover:bg-slate-800">
|
||||
<div className="group relative border border-y border-zinc-200 bg-zinc-50/40 transition hover:bg-zinc-50 dark:border-zinc-800/40 dark:bg-zinc-800/60 dark:hover:bg-zinc-800">
|
||||
<div className="mx-auto max-w-7xl px-3 py-3 sm:px-6 lg:px-8">
|
||||
<div className="text-center">
|
||||
<p className="text-sm font-medium">
|
||||
@@ -22,7 +22,7 @@ export function AnnouncementBanner(): JSX.Element {
|
||||
<span className="ml-2 inline-block">
|
||||
<Link
|
||||
href="https://monorepo.world?utm_source=nx.dev"
|
||||
className="font-semibold text-blue-500 underline dark:text-sky-500"
|
||||
className="font-semibold text-blue-500 underline dark:text-blue-500"
|
||||
>
|
||||
<span className="absolute inset-0" aria-hidden="true" />
|
||||
Join us!
|
||||
|
||||
@@ -82,15 +82,15 @@ export function Breadcrumbs({
|
||||
<div className="flex items-center">
|
||||
{!!index && (
|
||||
<ChevronRightIcon
|
||||
className="h-5 w-5 flex-shrink-0 text-slate-500"
|
||||
className="h-5 w-5 flex-shrink-0 text-zinc-500"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
)}
|
||||
<a
|
||||
href={crumb.href}
|
||||
className={classNames(
|
||||
'text-sm font-medium hover:text-slate-600',
|
||||
crumb.current ? 'text-slate-600' : 'text-slate-400',
|
||||
'text-sm font-medium hover:text-zinc-600',
|
||||
crumb.current ? 'text-zinc-600' : 'text-zinc-400',
|
||||
!!index ? 'ml-4' : ''
|
||||
)}
|
||||
aria-current={crumb.current ? 'page' : undefined}
|
||||
|
||||
@@ -25,11 +25,11 @@ export type ButtonLinkProps = ButtonProps & {
|
||||
|
||||
const variantStyles: Record<AllowedVariants, string> = {
|
||||
primary:
|
||||
'bg-blue-500 dark:bg-sky-500 text-white group-hover:bg-blue-600 dark:group-hover:bg-sky-600 group-focus:ring-2 group-focus:ring-blue-500 dark:group-focus:ring-sky-500 focus:group-ring-offset-2',
|
||||
'bg-blue-500 dark:bg-blue-500 text-white group-hover:bg-blue-600 dark:group-hover:bg-blue-600 group-focus:ring-2 group-focus:ring-blue-500 dark:group-focus:ring-blue-500 focus:group-ring-offset-2',
|
||||
secondary:
|
||||
'border border-slate-300 dark:border-slate-700 bg-white dark:bg-slate-800 text-slate-700 dark:text-slate-200 group-hover:bg-slate-50 dark:group-hover:bg-slate-700 group-focus:ring-2 group-focus:ring-blue-500 dark:group-focus:ring-sky-500 focus:ring-offset-2',
|
||||
'border border-zinc-300 dark:border-zinc-700 bg-white dark:bg-zinc-800 text-zinc-700 dark:text-zinc-200 group-hover:bg-zinc-50 dark:group-hover:bg-zinc-700 group-focus:ring-2 group-focus:ring-blue-500 dark:group-focus:ring-blue-500 focus:ring-offset-2',
|
||||
contrast:
|
||||
'bg-slate-950 dark:bg-white text-slate-100 dark:text-slate-950 group-hover:bg-slate-800 dark:group-hover:bg-slate-100 group-focus:ring-2 group-focus:ring-blue-500 dark:group-focus:ring-sky-500 focus:ring-offset-2',
|
||||
'bg-zinc-950 dark:bg-white text-zinc-100 dark:text-zinc-950 group-hover:bg-zinc-800 dark:group-hover:bg-zinc-100 group-focus:ring-2 group-focus:ring-blue-500 dark:group-focus:ring-blue-500 focus:ring-offset-2',
|
||||
};
|
||||
const sizes: Record<AllowedSizes, string> = {
|
||||
large: 'space-x-4 px-4 py-2 text-lg',
|
||||
@@ -52,7 +52,7 @@ function getLayoutClassName(className = ''): string {
|
||||
*/
|
||||
function ButtonInner({
|
||||
children,
|
||||
variant = 'primary',
|
||||
variant = 'contrast',
|
||||
size = 'default',
|
||||
rounded = 'default',
|
||||
}: ButtonProps): JSX.Element {
|
||||
@@ -79,7 +79,7 @@ function ButtonInner({
|
||||
export function Button({
|
||||
children,
|
||||
className = '',
|
||||
variant = 'primary',
|
||||
variant = 'contrast',
|
||||
size = 'large',
|
||||
rounded = 'default',
|
||||
...props
|
||||
@@ -102,7 +102,7 @@ export const ButtonLink = forwardRef(function (
|
||||
className = '',
|
||||
href,
|
||||
size = 'default',
|
||||
variant = 'primary',
|
||||
variant = 'contrast',
|
||||
title = '',
|
||||
...props
|
||||
}: ButtonLinkProps,
|
||||
|
||||
@@ -34,7 +34,7 @@ export function CallToAction({
|
||||
<svg
|
||||
x="50%"
|
||||
y={0}
|
||||
className="overflow-visible fill-slate-200/20 dark:fill-slate-800/20"
|
||||
className="overflow-visible fill-zinc-200/20 dark:fill-zinc-800/20"
|
||||
>
|
||||
<path
|
||||
d="M-200 0h201v201h-201Z M600 0h201v201h-201Z M-400 600h201v201h-201Z M200 800h201v201h-201Z"
|
||||
@@ -63,7 +63,7 @@ export function CallToAction({
|
||||
<div className="mx-auto max-w-2xl text-center">
|
||||
<h2
|
||||
id="cta"
|
||||
className="text-3xl font-medium tracking-tight text-slate-950 sm:text-5xl dark:text-white"
|
||||
className="text-3xl font-medium tracking-tight text-zinc-950 sm:text-5xl dark:text-white"
|
||||
>
|
||||
Ready to
|
||||
<br />
|
||||
@@ -74,7 +74,7 @@ export function CallToAction({
|
||||
href={mainActionLink}
|
||||
title={mainActionTitle}
|
||||
prefetch={false}
|
||||
className="rounded-md bg-slate-950 px-3.5 py-2.5 text-sm font-semibold text-slate-100 shadow-sm hover:bg-slate-800 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white dark:bg-white dark:text-slate-900 dark:hover:bg-slate-100"
|
||||
className="rounded-md bg-zinc-950 px-3.5 py-2.5 text-sm font-semibold text-zinc-100 shadow-sm hover:bg-zinc-800 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white dark:bg-white dark:text-zinc-900 dark:hover:bg-zinc-100"
|
||||
>
|
||||
{mainActionLinkText}
|
||||
</Link>
|
||||
@@ -82,7 +82,7 @@ export function CallToAction({
|
||||
href="/contact"
|
||||
title="Get in touch"
|
||||
prefetch={false}
|
||||
className="group text-sm font-semibold leading-6 text-slate-950 dark:text-white"
|
||||
className="group text-sm font-semibold leading-6 text-zinc-950 dark:text-white"
|
||||
onClick={() => sendCustomEvent('contact-click', 'footer-cta', '')}
|
||||
>
|
||||
Contact us{' '}
|
||||
|
||||
@@ -15,28 +15,28 @@ export interface Champion {
|
||||
|
||||
export function ChampionCard({ data }: { data: Champion }): JSX.Element {
|
||||
return (
|
||||
<figure className="relative flex flex-col justify-between rounded-lg border border-slate-200 bg-white/40 p-4 text-sm shadow-sm transition focus-within:ring-2 focus-within:ring-blue-500 focus-within:ring-offset-2 hover:bg-white dark:border-slate-800/40 dark:bg-slate-800/60 dark:hover:bg-slate-800">
|
||||
<figure className="relative flex flex-col justify-between rounded-lg border border-zinc-200 bg-white/40 p-4 text-sm shadow-sm transition focus-within:ring-2 focus-within:ring-blue-500 focus-within:ring-offset-2 hover:bg-white dark:border-zinc-800/40 dark:bg-zinc-800/60 dark:hover:bg-zinc-800">
|
||||
<figcaption className="flex items-center space-x-4">
|
||||
<img
|
||||
src={data.imageUrl}
|
||||
alt={data.name}
|
||||
className="h-12 w-12 flex-none rounded-full border border-slate-200 bg-slate-800/40 object-cover dark:border-slate-800/40 dark:bg-slate-200"
|
||||
className="h-12 w-12 flex-none rounded-full border border-zinc-200 bg-zinc-800/40 object-cover dark:border-zinc-800/40 dark:bg-zinc-200"
|
||||
loading="lazy"
|
||||
/>
|
||||
<div className="flex-auto">
|
||||
<div className="font-semibold text-slate-500 dark:text-slate-300">
|
||||
<div className="font-semibold text-zinc-500 dark:text-zinc-300">
|
||||
<a target="_blank" rel="noreferrer" href={data.contact[0].link}>
|
||||
<span className="absolute inset-0"></span>
|
||||
{data.name}
|
||||
</a>
|
||||
</div>
|
||||
<div className="mt-0.5 text-xs text-slate-400 dark:text-slate-500">
|
||||
<div className="mt-0.5 text-xs text-zinc-400 dark:text-zinc-500">
|
||||
<MapIcon className="inline h-4 w-4" /> {data.location}
|
||||
</div>
|
||||
</div>
|
||||
</figcaption>
|
||||
<p className="mt-4">{data.expertise}</p>
|
||||
<div className="ml mt-4 inline text-xs text-slate-400 dark:text-slate-500">
|
||||
<div className="ml mt-4 inline text-xs text-zinc-400 dark:text-zinc-500">
|
||||
<ChatBubbleLeftIcon className="inline h-4 w-4" />{' '}
|
||||
{data.contact[0].label}
|
||||
</div>
|
||||
|
||||
@@ -28,7 +28,7 @@ export function ChampionPerks(): JSX.Element {
|
||||
return (
|
||||
<article
|
||||
id="making-of-champion"
|
||||
className="relative bg-slate-50 py-28 dark:bg-slate-800/40"
|
||||
className="relative bg-zinc-50 py-28 dark:bg-zinc-800/40"
|
||||
>
|
||||
<div className="mx-auto max-w-7xl px-4 sm:grid sm:grid-cols-2 sm:gap-8 sm:px-6 lg:px-8">
|
||||
<div>
|
||||
@@ -46,7 +46,7 @@ export function ChampionPerks(): JSX.Element {
|
||||
</SectionHeading>
|
||||
</header>
|
||||
<div className="mt-8 flex gap-16 font-normal">
|
||||
<p className="max-w-xl text-lg text-slate-700 dark:text-slate-400">
|
||||
<p className="max-w-xl text-lg text-zinc-700 dark:text-zinc-400">
|
||||
If you love Nx and want other people to love Nx too, you may have
|
||||
the makings of an Nx Champion.
|
||||
</p>
|
||||
@@ -59,7 +59,7 @@ export function ChampionPerks(): JSX.Element {
|
||||
<dt>
|
||||
<div className="relative flex h-12 w-12">
|
||||
<CheckBadgeIcon
|
||||
className="h-8 w-8 text-blue-500 dark:text-sky-500"
|
||||
className="h-8 w-8 text-blue-500 dark:text-blue-500"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<HeartIcon
|
||||
@@ -71,12 +71,12 @@ export function ChampionPerks(): JSX.Element {
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
<p className="relative mt-4 text-base font-medium leading-6 text-slate-900 dark:text-slate-100">
|
||||
<span className="absolute -left-4 h-full w-0.5 bg-blue-500 dark:bg-sky-500"></span>
|
||||
<p className="relative mt-4 text-base font-medium leading-6 text-zinc-900 dark:text-zinc-100">
|
||||
<span className="absolute -left-4 h-full w-0.5 bg-blue-500 dark:bg-blue-500"></span>
|
||||
Recognition as a Leader
|
||||
</p>
|
||||
</dt>
|
||||
<dd className="mt-2 text-base text-slate-500 dark:text-slate-400">
|
||||
<dd className="mt-2 text-base text-zinc-500 dark:text-zinc-400">
|
||||
You'll be listed in the Nx Champion directory above, receive
|
||||
branded swag for yourself and Nx stickers to give away.
|
||||
</dd>
|
||||
@@ -85,7 +85,7 @@ export function ChampionPerks(): JSX.Element {
|
||||
<dt>
|
||||
<div className="relative flex h-12 w-12">
|
||||
<NewspaperIcon
|
||||
className="h-8 w-8 text-blue-500 dark:text-sky-500"
|
||||
className="h-8 w-8 text-blue-500 dark:text-blue-500"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<VideoCameraIcon
|
||||
@@ -97,12 +97,12 @@ export function ChampionPerks(): JSX.Element {
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
<p className="relative mt-4 text-base font-medium leading-6 text-slate-900 dark:text-slate-100">
|
||||
<span className="absolute -left-4 h-full w-0.5 bg-blue-500 dark:bg-sky-500"></span>
|
||||
<p className="relative mt-4 text-base font-medium leading-6 text-zinc-900 dark:text-zinc-100">
|
||||
<span className="absolute -left-4 h-full w-0.5 bg-blue-500 dark:bg-blue-500"></span>
|
||||
Content Promotion
|
||||
</p>
|
||||
</dt>
|
||||
<dd className="mt-2 text-base text-slate-500 dark:text-slate-400">
|
||||
<dd className="mt-2 text-base text-zinc-500 dark:text-zinc-400">
|
||||
You can collaborate with other Nx Champions to improve your blog
|
||||
posts and videos. Nx will promote your content on our social media
|
||||
channels.
|
||||
@@ -112,7 +112,7 @@ export function ChampionPerks(): JSX.Element {
|
||||
<dt>
|
||||
<div className="relative flex h-12 w-12">
|
||||
<KeyIcon
|
||||
className="h-8 w-8 text-blue-500 dark:text-sky-500"
|
||||
className="h-8 w-8 text-blue-500 dark:text-blue-500"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<LightBulbIcon
|
||||
@@ -124,12 +124,12 @@ export function ChampionPerks(): JSX.Element {
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
<p className="relative mt-4 text-base font-medium leading-6 text-slate-900 dark:text-slate-100">
|
||||
<span className="absolute -left-4 h-full w-0.5 bg-blue-500 dark:bg-sky-500"></span>
|
||||
<p className="relative mt-4 text-base font-medium leading-6 text-zinc-900 dark:text-zinc-100">
|
||||
<span className="absolute -left-4 h-full w-0.5 bg-blue-500 dark:bg-blue-500"></span>
|
||||
Special Access
|
||||
</p>
|
||||
</dt>
|
||||
<dd className="mt-2 text-base text-slate-500 dark:text-slate-400">
|
||||
<dd className="mt-2 text-base text-zinc-500 dark:text-zinc-400">
|
||||
You'll have a dedicated Discord channel with the Nx team and
|
||||
monthly video calls with Nx team members to share feedback and
|
||||
brainstorm content ideas.
|
||||
@@ -139,7 +139,7 @@ export function ChampionPerks(): JSX.Element {
|
||||
<dt>
|
||||
<div className="relative flex h-12 w-12">
|
||||
<UserGroupIcon
|
||||
className="h-8 w-8 text-blue-500 dark:text-sky-500"
|
||||
className="h-8 w-8 text-blue-500 dark:text-blue-500"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<UsersIcon
|
||||
@@ -151,15 +151,15 @@ export function ChampionPerks(): JSX.Element {
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
<p className="relative mt-4 text-base font-medium leading-6 text-slate-900 dark:text-slate-100">
|
||||
<span className="absolute -left-4 h-full w-0.5 bg-blue-500 dark:bg-sky-500"></span>
|
||||
<p className="relative mt-4 text-base font-medium leading-6 text-zinc-900 dark:text-zinc-100">
|
||||
<span className="absolute -left-4 h-full w-0.5 bg-blue-500 dark:bg-blue-500"></span>
|
||||
Join the Program
|
||||
</p>
|
||||
</dt>
|
||||
<dd className="mt-2 text-base text-slate-500 dark:text-slate-400">
|
||||
<dd className="mt-2 text-base text-zinc-500 dark:text-zinc-400">
|
||||
When you're ready to join, fill out the{' '}
|
||||
<a
|
||||
className="text-slate-900 underline dark:text-slate-100"
|
||||
className="text-zinc-900 underline dark:text-zinc-100"
|
||||
href="https://forms.gle/wYd9mC3ka64ki96G7"
|
||||
>
|
||||
application form
|
||||
|
||||
@@ -17,7 +17,7 @@ export function CourseVideo({
|
||||
}: CourseVideoProps): JSX.Element {
|
||||
return (
|
||||
<div className="not-prose mx-auto max-w-4xl pt-4">
|
||||
<div className="overflow-hidden rounded-xl bg-slate-50 shadow-sm ring-1 ring-slate-900/5 dark:bg-slate-800/50 dark:ring-slate-700/50">
|
||||
<div className="overflow-hidden rounded-xl bg-zinc-50 shadow-sm ring-1 ring-zinc-900/5 dark:bg-zinc-800/50 dark:ring-zinc-700/50">
|
||||
<div className="aspect-video w-full">
|
||||
<YouTube
|
||||
src={videoUrl}
|
||||
@@ -28,12 +28,12 @@ export function CourseVideo({
|
||||
</div>
|
||||
<div className="px-6 py-4">
|
||||
<div className="flex flex-col items-center gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<h3 className="text-center text-xl font-medium text-slate-900 sm:text-left dark:text-white">
|
||||
<h3 className="text-center text-xl font-medium text-zinc-900 sm:text-left dark:text-white">
|
||||
{courseTitle}
|
||||
</h3>
|
||||
<ButtonLink
|
||||
href={courseUrl}
|
||||
variant="primary"
|
||||
variant="contrast"
|
||||
size="small"
|
||||
title={`Watch the full "${courseTitle}" course`}
|
||||
className="whitespace-nowrap"
|
||||
|
||||
@@ -25,7 +25,7 @@ export function DefaultLayout({
|
||||
useWindowScrollDepth();
|
||||
|
||||
return (
|
||||
<div className="w-full dark:bg-slate-950">
|
||||
<div className="w-full dark:bg-zinc-950">
|
||||
{!hideHeader && (
|
||||
<Header
|
||||
ctaButtons={headerCTAConfig}
|
||||
|
||||
@@ -45,15 +45,15 @@ export function FlipCard({
|
||||
>
|
||||
<div
|
||||
className={cx(
|
||||
'preserve-3d relative h-full w-full content-center rounded-lg border-2 bg-white/60 shadow-sm transition duration-200 focus-within:ring-offset-2 dark:bg-slate-800/90',
|
||||
'preserve-3d relative h-full w-full content-center rounded-lg border-2 bg-white/60 shadow-sm transition duration-200 focus-within:ring-offset-2 dark:bg-zinc-800/90',
|
||||
isFlippable && isFlipped
|
||||
? 'my-rotate-y-180 bg-white dark:bg-slate-800'
|
||||
? 'my-rotate-y-180 bg-white dark:bg-zinc-800'
|
||||
: '',
|
||||
isFlippable
|
||||
? isFlipped
|
||||
? 'border-blue-400 dark:border-slate-800'
|
||||
: 'border-blue-400 hover:[transform:rotateY(10deg)] dark:border-slate-800'
|
||||
: 'border-1 border-slate-300 dark:border-slate-800'
|
||||
? 'border-blue-400 dark:border-zinc-800'
|
||||
: 'border-blue-400 hover:[transform:rotateY(10deg)] dark:border-zinc-800'
|
||||
: 'border-1 border-zinc-300 dark:border-zinc-800'
|
||||
)}
|
||||
>
|
||||
<FlipCardFront>{fullDate}</FlipCardFront>
|
||||
@@ -76,7 +76,7 @@ export function FlipCardBack({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<FlipCardContext.Consumer>
|
||||
{() => (
|
||||
<div className="my-rotate-y-180 backface-hidden h-full w-full overflow-hidden rounded-md bg-white text-3xl text-slate-900 dark:bg-slate-800 dark:text-slate-100">
|
||||
<div className="my-rotate-y-180 backface-hidden h-full w-full overflow-hidden rounded-md bg-white text-3xl text-zinc-900 dark:bg-zinc-800 dark:text-zinc-100">
|
||||
<div className="p-4 text-sm sm:text-sm md:text-sm lg:text-lg">
|
||||
{children}
|
||||
</div>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user