feat(nx-dev): powerpack landing page (#27963)

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #
This commit is contained in:
Juri Strumpflohner 2024-09-26 01:24:54 +02:00 committed by GitHub
parent 7f4c39ead4
commit 529ab9455c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
49 changed files with 1503 additions and 27 deletions

View File

@ -119,4 +119,4 @@ In addition, we are actively exploring ways to provide advanced analytics for yo
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](https://go.nx.dev/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Speed up your CI](https://nx.app/)
- [Speed up your CI](/nx-cloud)

View File

@ -335,4 +335,4 @@ If the prettier UI and better performance havent convinced you, this surely w
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](https://go.nx.dev/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Speed up your CI](https://nx.app/)
- [Speed up your CI](/nx-cloud)

View File

@ -608,4 +608,4 @@ This journey through Qwik and Nx demonstrates how thoughtful architecture and th
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](https://go.nx.dev/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Speed up your CI](https://nx.app/)
- [Speed up your CI](/nx-cloud)

View File

@ -18,4 +18,4 @@ Victor and I are excited to announce that Nx has raised another $16M in a Series
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](https://go.nx.dev/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Speed up your CI](https://nx.app/)
- [Speed up your CI](/nx-cloud)

View File

@ -495,4 +495,4 @@ If you enjoyed these, [subscribe to our YouTube channel](https://www.youtube.com
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](https://go.nx.dev/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Speed up your CI](https://nx.app/)
- [Speed up your CI](/nx-cloud)

View File

@ -284,4 +284,4 @@ Thats all for now folks! Were just starting up a new iteration of developm
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](https://go.nx.dev/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Speed up your CI](https://nx.app/)
- [Speed up your CI](/nx-cloud)

View File

@ -621,4 +621,4 @@ Nx is a powerful monorepo tool. Together with Nx and these 2 state management to
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](https://go.nx.dev/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Speed up your CI](https://nx.app/)
- [Speed up your CI](/nx-cloud)

View File

@ -312,4 +312,4 @@ This role, in the context of OpenAIs chat models, is the response of the AI.
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Speed up your CI](https://nx.app/)
- [Speed up your CI](/nx-cloud)

View File

@ -212,4 +212,4 @@ Thats all for now folks! Were just starting up a new iteration of developm
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](https://go.nx.dev/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Speed up your CI](https://nx.app/)
- [Speed up your CI](/nx-cloud)

View File

@ -389,4 +389,4 @@ Exciting stuff! So keep an eye on our channels, and subscribe if you havent a
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](https://go.nx.dev/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Speed up your CI](https://nx.app/)
- [Speed up your CI](/nx-cloud)

View File

@ -185,4 +185,4 @@ We just released Project Crystal, so this is just the beginning of it. While we
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](https://go.nx.dev/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Speed up your CI](https://nx.app/)
- [Speed up your CI](/nx-cloud)

View File

@ -124,4 +124,4 @@ If you have a task that cant be run on Nx Agents for some reason, you can eas
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](https://go.nx.dev/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Speed up your CI](https://nx.app/)
- [Speed up your CI](/nx-cloud)

View File

@ -319,4 +319,4 @@ Here are some example repositories already leveraging Nx release:
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](https://go.nx.dev/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Speed up your CI](https://nx.app/)
- [Speed up your CI](/nx-cloud)

View File

@ -145,4 +145,4 @@ Thats all for now folks! Were just starting up a new iteration of developm
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](https://go.nx.dev/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Speed up your CI](https://nx.app/)
- [Speed up your CI](/nx-cloud)

View File

@ -215,4 +215,4 @@ Here is how to set up Nx with the Gradle workspace. Hopefully, this gives you a
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](https://go.nx.dev/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Speed up your CI](https://nx.app/)
- [Speed up your CI](/nx-cloud)

View File

@ -235,4 +235,4 @@ Zack
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](https://go.nx.dev/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Speed up your CI](https://nx.app/)
- [Speed up your CI](/nx-cloud)

View File

@ -56,4 +56,4 @@ This is just the first of a series of AI-powered features that we're going to be
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](https://go.nx.dev/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Speed up your CI](https://nx.app/)
- [Speed up your CI](/nx-cloud)

View File

@ -292,4 +292,4 @@ The [Monorepo World conference](https://monorepo.world) is coming up soon on Oct
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](https://go.nx.dev/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Speed up your CI](https://nx.app/)
- [Speed up your CI](/nx-cloud)

View File

@ -91,4 +91,4 @@ can [find more details in our docs](/ci/recipes/security/personal-access-tokens)
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](https://go.nx.dev/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Speed up your CI](https://nx.app/)
- [Speed up your CI](/nx-cloud)

View File

@ -110,4 +110,4 @@ The [Monorepo World conference](https://monorepo.world) is coming up soon on Oct
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](https://go.nx.dev/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Speed up your CI](https://nx.app/)
- [Speed up your CI](/nx-cloud)

View File

@ -0,0 +1,54 @@
---
title: Evolving Nx
slug: evolving-nx
authors: [Jeff Cross]
tags: [nx, release]
cover_image: /blog/images/evolving-nx/thumbnail.png
---
Over the years, Nx has grown from a small 20% side project of our consulting business into a tool that empowers millions of developers worldwide and helps Fortune 500 companies ship high-quality software faster. In the last two years, we successfully transformed our consulting business into a product company, where our team can fully focus on evolving Nx and building Nx Cloud to extend Nxs capabilities beyond local development.
This success is in large part thanks to:
- Our commitment to building Nx as MIT-licensed open-source software, supported by the incredible contributions from our vibrant Nx community.
- Close collaboration with our customers, allowing us to understand their needs and continuously improve Nx and Nx Cloud to address their demanding and complex challenges.
When we have new ideas to make Nx better, weve always had two options: it could be in the open source build system, or it could be in the paid cloud product, [Nx Cloud](/nx-cloud). But sometimes, there are important things we want to offer that can solve some gnarly problems for teams but dont require them to spend months convincing their IT department to incorporate yet another cloud service. So, we decided to create a collection of non-cloud-dependent Nx add-ons in a new package called **Nx Powerpack**, which will require paid licenses to use.
## Introducing Nx Powerpack
**[Nx Powerpack](/powerpack)** — our newest product designed to elevate the Nx CLI experience for enterprise environments. Powerpack offers advanced features like self-hosted remote cache storage, code ownership for monorepos, and workspace conformance, seamlessly integrating into sealed systems with strict security requirements. Its also designed for ease of implementation, helping enterprises bypass lengthy procurement processes and quickly access the tools they need.
> If you want to get into the technical details, we wrote a separate blog post diving deeper into the technical details: [Introducing Nx Powerpack](/blog/introducing-nx-powerpack).
Everything in Powerpack is new functionality, not previously free features that were now putting behind a paywall. However, this change coincides with some Nx improvements that will eventually interfere with users who were relying on our original filesystem-based implementation of local caching. Weve completely rewritten Nx's local caching to be faster and more secure, partly by using a local database instead of checking the filesystem for artifact metadata. With this rewrite, any custom remote caches that rely on metadata reflected in the filesystem will not work as of Nx 21. This is why we decided to build an API into Powerpack to be able to connect Nxs cache to different clouds and data sources. Now with Powerpack, teams can use an officially-supported implementation of remote caching, without needing to use Nx Cloud.
Theres a Steve Jobs quote that I think rings true with all of us at Nx:
> "I think money is a wonderful thing because it enables you to do things. It enables you to invest in ideas that don't have a short-term payback." - Steve Jobs
As Nx has grown, weve hired more people to make the product better. Naturally, those people want to do good work and be paid. We all show up for work to build things were passionate about, and solve real pains for the millions of developers using Nx every day. Money is what enables us to keep doing what we love. So as much as Victor Savkin and I want to just build things and give them away for free, we need to balance our personal passion with whats the best long-term decisions for Nx — the project, the community, and the company.
Like many open source projects, one of the bigger challenges to sustainability in recent years has been larger cloud products who wait for projects to become successful, and then try to capitalize on that success at the expense of the maintainers. I call these companies “parasite vendors” since they benefit from the host, but give no value back. To battle this, many open source projects have decided to make their open source licensing more restrictive, or introduce dual licenses, forcing those parasite vendors to work with the maintainers on a fair arrangement. We think weve come up with a better solution for the community by introducing a new package, Powerpack, with a new commercial license, with only new functionality. **Nx itself still has one license: the MIT license.**
![Nx products and their licenses](/blog/images/evolving-nx/nx-products-licenses.avif)
## How to Get Nx Powerpack
Powerpack is automatically included for all existing enterprise customers. If youre looking to purchase a new license, you can easily [do so on this page](/powerpack).
Are you a startup? If these features make sense for your team but the cost is a concern, reach out to our support team, and well work with you to find a solution that fits.
## Got Questions?
If youre curious to learn more about these changes for Nx and how to get started, [check out our docs](/features/powerpack).
## Learn more
- [Nx Powerpack](/powerpack)
- [Blog: Introducing Nx Powerpack](/blog/introducing-nx-powerpack)
- [Docs: Powerpack features](/getting-started/intro)
- [X/Twitter](https://twitter.com/nxdevtools) -- [LinkedIn](https://www.linkedin.com/company/nrwl/)
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](https://go.nx.dev/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)

View File

@ -0,0 +1,252 @@
---
title: Introducing Nx Powerpack
slug: introducing-nx-powerpack
authors: [Juri Strumpflohner]
tags: [nx, release]
cover_image: /blog/images/introducing-powerpack/thumbnail.png
youtubeUrl: https://youtu.be/KZ0nh2lj8zE
---
Today we're introducing our latest product, **Nx Powerpack**, a suite of paid extensions for Nx, specifically designed around common enterprise needs. Now, before anyone draws the wrong conclusions:
- No, were **not going to restrict Nxs license**, lock you in, and then harvest. Nx remains MIT licensed and fully open source.
- No, were **not placing existing features behind a paywall**. Nx Powerpack introduces new features on top of Nx (more about that below).
- Yes, we still **strongly believe in OSS and our community**, and we will keep improving Nx more than ever; if anything, Powerpack will help us fund our OSS work on Nx core and ensure its long-term sustainability.
So this leaves us with:
![Nx products and their licenses](/blog/images/evolving-nx/nx-products-licenses.avif)
> But why do we release Nx Powerpack under a commercial license? Read all about our strategy, the reasoning behind Powerpack and OSS funding in the **blog post from our CEO, Jeff Cross**: [Evolving Nx](/blog/evolving-nx).
But now to the fun, technical part! Nx Powerpack is a bundle that - in this very first release - comes with three major features:
- [Codeowners for monorepos](#codeowners-for-monorepos)
- [Self-hosted cache storage](#selfhosted-cache-storage)
- [Workspace conformance (beta)](#workspace-conformance-beta)
Lets dive in!
## Getting an Nx Powerpack license
All Powerpack features require a dedicated commercial license. You can get one here: [Nx Powerpack](/powerpack).
Once you have your license, run the following command
```shell
npx nx activate-powerpack <your-license>
```
## Codeowners for monorepos
Setting up Codeowners is highly recommended when designing a monorepo. If youre not closely familiar, Codeowners is a common feature of VCS providers (such as GitHub, GitLab, Bitbucket, etc.), allowing you to enforce specific code reviewers to approve PRs. This functionality is especially important in a monorepo, where you manage multiple projects with multiple teams. You want to ensure the right people are reviewing the code being submitted.
Heres a simple example of a [GitHub CODEOWNERS definition](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners):
```plain {% fileName=".github/CODEOWNERS" %}
/docs/ @doc-owner
/apps/orders @orders-team
/apps/products @products-team
/libs/orders/** @orders-team
/libs/products/** @products-team
/libs/shared/** @infra-team
```
One of the downsides of how codeowners works on today's VCS providers is that **they are folder-based**. That requires you to map your project paths to your codeowner files and keep maintaining that as you change your monorepo structure. And **this is exactly what we're going to automate**.
In a monorepo you reason based on projects. That's what you pass to your [Nx run commands](/features/run-tasks), what you see on the [project graph](/features/explore-graph) and also where owners should be defined. To get started install the Codeowners Powerpack plugin:
```shell
npx nx add @nx/powerpack-owners
```
This will allow you to define an owners section in your `nx.json` where you can define owners at the project level or even leveraging project tags. Here's a small example:
```json {% fileName="nx.json" %}
{
...
"owners": {
"format": "github",
"patterns": [
{
"description": "CI configuration",
"owners": ["@devops"],
"files": [".github/workflows/**"]
},
{
"description": "Order team",
"owners": ["@team-orders"],
"projects": ["tag:scope:orders"]
},
{
"description": "Product team",
"owners": ["@team-products"],
"projects": ["tag:scope:products"]
},
{
"description": "Design team",
"owners": ["@team-design"],
"projects": ["tag:scope:design-system"]
}
]
},
...
}
```
A dedicated `nx sync` command automatically synchronizes such definition to a `CODEOWNERS` that matches your VCS provider:
```{% fileName=".github/CODEOWNERS" %}
# CI configuration
.github/workflows/** @devops
# Design team
/libs/shared/ui/angular/form-controls/ @team-design
# Design team
/libs/shared/ui/react/form-controls/ @team-design
# Product team
/libs/products/feat-product-detail/ @team-products
# Order team
/libs/orders/feat-current-orders/ @team-orders
...
```
Read all about how to [configure Codeowners for your project on our docs](/features/powerpack/owners).
## Self-hosted cache storage
A continuous effort on our Nx core is to improve speed. Last year, we began **rewriting performance-critical parts of Nx into Rust**, and more core components are being rewritten. As part of this effort, we also changed how we manage local cache, moving from a **file-based to a database-based approach**. In addition to small performance gains from reduced I/O, this opens up many opportunities for improving local cache handling, such as keeping only relevant cache based on usage, more easily controlling maximum cache size, and optimizing task orchestration by running failed tasks earlier.
As part of this new approach we're also going to [deprecate custom `taskRunners`](/deprecated/custom-task-runners) in Nx 20. I bring this up because it might affect users that relied on 3rd party tools that hooked into the task runners API.
To fill in on the custom task runner API we're providing a new Powerpack plugin that allows you to use S3 or a network drive as your storing mechanism for your Nx cache.
Here's an example on how to get started with AWS S3 based remote caching. First add the powerpack plugin:
```shell
npx nx add @nx/powerpack-s3-cache
```
This will update your `nx.json` to add the new `cache` section.
```json {% fileName="nx.json" %}
{
...
"s3": {
"bucket": "your-s3-bucket-name",
"region": "us-east-1"
}
}
```
To then leverage the S3 powered remote cache on CI, [follow the official AWS documentation](https://github.com/aws-actions/configure-aws-credentials). Here's a short example snippet using OIDC to authenticate with AWS on GitHub Actions:
```yaml {% fileName=".github/workflows/ci.yml" %}
name: CI
...
permissions:
id-token: write
...
env:
NX_DB_CACHE: true
jobs:
main:
runs-on: ubuntu-latest
steps:
...
- name: 'Configure AWS Credentials'
uses: aws-actions/configure-aws-credentials@v4.0.2
with:
role-to-assume: arn:aws:iam::123456789123:role/GhAIBucketUserRole
aws-region: us-east-1
...
- run: pnpm exec nx affected -t lint test build
```
Similarly you can **set up network file based caching** using the `nx add @nx/powerpack-shared-fs-cache` package and by setting the `cacheDirectory` path in your `nx.json`.
Read all about how to [set up S3 or network drive based caching for your Nx workspace on our docs](/features/powerpack/custom-caching).
## Workspace conformance (Beta)
We're releasing the `@nx/powerpack-conformance` plugin in an early preview. This new package focuses specifically on the maintainability of your monorepo. It allows you to encode your organization's standards so they can be enforced automatically. In this first version, the workspace conformance package ships with:
- [Enforce Module Boundaries](/nx-api/powerpack-conformance#enforce-module-boundaries): Similar to the Nx ESLint [Enforce Module Boundaries rule](https://nx-dev-git-docs-powerpack-nrwl.vercel.app/features/enforce-module-boundaries), but enforces boundaries on every project dependency, not just those created from TypeScript imports or `package.json` dependencies.
- [Ensure Owners](/nx-api/powerpack-conformance#ensure-owners): Requires every project to have an owner defined for the `@nx/powerpack-owners` plugin.
To get started, install the following package:
```shell
npx nx add @nx/powerpack-conformance
```
This allows you to define conformance rules in your `nx.json`. Here is an example:
```json {% fileName="nx.json" %}
{
...
"conformance": {
"rules": [
{
"rule": "@nx/powerpack-conformance/enforce-module-boundaries",
"projects": ["!remix-app-e2e"],
"options": {}
},
{
"rule": "@nx/powerpack-conformance/ensure-owners",
"projects": ["!remix-app-e2e"]
},
{
"rule": "./tools/local-conformance-rule.ts"
}
]
}
}
```
You can also define rules locally, as shown in the example above, which are simple TypeScript files:
```ts
import { createConformanceRule } from '@nx/powerpack-conformance';
const rule = createConformanceRule({
name: 'local-conformance-rule-example',
category: 'security',
reporter: 'project-reporter',
implementation: async (context) => {
return {
severity: 'low',
details: {
violations: [],
},
};
},
});
export default rule;
```
You can then run `nx conformance` to execute the conformance checks:
![Screenshot of the conformance check output](/blog/images/introducing-powerpack/conformance-check.avif)
In this first preview release, you'll only be able to run workspace conformance rules on a single workspace. In future iterations, you **will be able to connect it to your existing Nx Cloud organization**, allowing you to upload conformance rules and run them across connected workspaces.
Read all the details on how to [get started with workspace conformance rules in our docs](/features/powerpack/conformance).
## Learn more
- [Nx Docs](/getting-started/intro)
- [X/Twitter](https://twitter.com/nxdevtools) -- [LinkedIn](https://www.linkedin.com/company/nrwl/)
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](https://go.nx.dev/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 519 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 KiB

View File

@ -0,0 +1,52 @@
import { DefaultLayout } from '@nx/nx-dev/ui-common';
import {
CallToAction,
GetStarted,
Hero,
PowerpackFeatures,
} from '@nx/nx-dev/ui-powerpack';
import type { Metadata } from 'next';
export const metadata: Metadata = {
title: 'Nx PowerPack',
description:
'Nx Powerpack is a suite of paid extensions for the Nx CLI specifically designed for enterprises.',
openGraph: {
url: 'https://nx.dev/powerpack',
title: 'Nx PowerPack',
description:
'Nx Powerpack is a suite of paid extensions for the Nx CLI specifically designed for enterprises.',
images: [
{
url: 'https://nx.dev/socials/nx-powerpack-media.png',
width: 800,
height: 421,
alt: 'Nx PowerPack: Advanced tools for enterprises',
type: 'image/jpeg',
},
],
siteName: 'NxDev',
type: 'website',
},
};
export default function NxPowerPackPage(): JSX.Element {
return (
<DefaultLayout>
<Hero />
<div className="mt-32 scroll-mt-32 lg:mt-56" id="features">
<PowerpackFeatures />
</div>
<div className="mt-32 scroll-mt-32 lg:mt-56">
<GetStarted />
</div>
<div className="mt-32 lg:mt-56">
<CallToAction />
</div>
</DefaultLayout>
);
}

View File

@ -1,3 +1,4 @@
export * from './lib/animated-beam';
export * from './lib/animate-value';
export * from './lib/blur-fade';
export * from './lib/fit-text';

View File

@ -0,0 +1,371 @@
'use client';
import { FC, RefObject, useEffect, useId, useState } from 'react';
import { motion, TargetAndTransition } from 'framer-motion';
import { cx } from '@nx/nx-dev/ui-primitives';
export interface AnimatedCurvedBeamProps {
className?: string;
containerRef: RefObject<HTMLElement>; // Container ref
fromRef: RefObject<HTMLElement>;
toRef: RefObject<HTMLElement>;
curvature?: number;
reverse?: boolean;
pathColor?: string;
pathWidth?: number;
pathOpacity?: number;
gradientStartColor?: string;
gradientStopColor?: string;
delay?: number;
duration?: number;
startXOffset?: number;
startYOffset?: number;
endXOffset?: number;
endYOffset?: number;
bidirectional?: boolean;
}
type BeamAnimation = {
x1: [string, string];
x2: [string, string];
y1: [string, string];
y2: [string, string];
};
export const AnimatedCurvedBeam: FC<AnimatedCurvedBeamProps> = ({
className,
containerRef,
fromRef,
toRef,
curvature = 0,
reverse = false, // Include the reverse prop
duration = Math.random() * 3 + 8,
delay = 0,
pathColor = 'gray',
pathWidth = 2,
pathOpacity = 0.2,
gradientStartColor = '#ffaa40',
gradientStopColor = '#9c40ff',
startXOffset = 0,
startYOffset = 0,
endXOffset = 0,
endYOffset = 0,
bidirectional = false,
}) => {
const id = useId();
const [pathD, setPathD] = useState('');
const [svgDimensions, setSvgDimensions] = useState({ width: 0, height: 0 });
// Calculate the gradient coordinates based on the reverse prop
const forwardAnimation: BeamAnimation = {
x1: reverse ? ['90%', '-10%'] : ['10%', '110%'],
x2: reverse ? ['100%', '0%'] : ['0%', '100%'],
y1: ['0%', '0%'],
y2: ['0%', '0%'],
};
const backwardAnimation: BeamAnimation = {
x1: reverse ? ['-10%', '90%'] : ['110%', '10%'],
x2: reverse ? ['0%', '100%'] : ['100%', '0%'],
y1: ['0%', '0%'],
y2: ['0%', '0%'],
};
const animateValue: TargetAndTransition = bidirectional
? {
x1: [
forwardAnimation.x1[0],
forwardAnimation.x1[1],
backwardAnimation.x1[1],
backwardAnimation.x1[0],
],
x2: [
forwardAnimation.x2[0],
forwardAnimation.x2[1],
backwardAnimation.x2[1],
backwardAnimation.x2[0],
],
y1: ['0%', '0%', '0%', '0%'],
y2: ['0%', '0%', '0%', '0%'],
}
: forwardAnimation;
useEffect(() => {
const updatePath = () => {
if (containerRef.current && fromRef.current && toRef.current) {
const containerRect = containerRef.current.getBoundingClientRect();
const rectA = fromRef.current.getBoundingClientRect();
const rectB = toRef.current.getBoundingClientRect();
const svgWidth = containerRect.width;
const svgHeight = containerRect.height;
setSvgDimensions({ width: svgWidth, height: svgHeight });
const startX =
rectA.left - containerRect.left + rectA.width / 2 + startXOffset;
const startY =
rectA.top - containerRect.top + rectA.height / 2 + startYOffset;
const endX =
rectB.left - containerRect.left + rectB.width / 2 + endXOffset;
const endY =
rectB.top - containerRect.top + rectB.height / 2 + endYOffset;
const controlY = startY - curvature;
const d = `M ${startX},${startY} Q ${
(startX + endX) / 2
},${controlY} ${endX},${endY}`;
setPathD(d);
}
};
// Initialize ResizeObserver
const resizeObserver = new ResizeObserver((entries) => {
// For all entries, recalculate the path
for (let entry of entries) {
updatePath();
}
});
// Observe the container element
if (containerRef.current) {
resizeObserver.observe(containerRef.current);
}
// Call the updatePath initially to set the initial path
updatePath();
// Clean up the observer on component unmount
return () => {
resizeObserver.disconnect();
};
}, [
containerRef,
fromRef,
toRef,
curvature,
startXOffset,
startYOffset,
endXOffset,
endYOffset,
]);
return (
<svg
fill="none"
width={svgDimensions.width}
height={svgDimensions.height}
xmlns="http://www.w3.org/2000/svg"
className={cx(
'pointer-events-none absolute left-0 top-0 transform-gpu stroke-2',
className
)}
viewBox={`0 0 ${svgDimensions.width} ${svgDimensions.height}`}
>
<path
d={pathD}
stroke={pathColor}
strokeWidth={pathWidth}
strokeOpacity={pathOpacity}
strokeLinecap="round"
/>
<path
d={pathD}
strokeWidth={pathWidth}
stroke={`url(#${id})`}
strokeOpacity="1"
strokeLinecap="round"
/>
<defs>
<motion.linearGradient
className="transform-gpu"
id={id}
gradientUnits={'userSpaceOnUse'}
initial={{
x1: '0%',
x2: '0%',
y1: '0%',
y2: '0%',
}}
animate={animateValue}
transition={{
delay,
duration,
ease: [0.16, 1, 0.3, 1], // https://easings.net/#easeOutExpo
repeat: Infinity,
repeatDelay: 0,
}}
>
<stop stopColor={gradientStartColor} stopOpacity="0"></stop>
<stop stopColor={gradientStartColor}></stop>
<stop offset="32.5%" stopColor={gradientStopColor}></stop>
<stop
offset="100%"
stopColor={gradientStopColor}
stopOpacity="0"
></stop>
</motion.linearGradient>
</defs>
</svg>
);
};
export interface AnimatedAngledBeamProps {
className?: string;
containerRef: RefObject<HTMLElement>;
fromRef: RefObject<HTMLElement>;
toRef: RefObject<HTMLElement>;
reverse?: boolean;
pathColor?: string;
pathWidth?: number;
pathOpacity?: number;
gradientStartColor?: string;
gradientStopColor?: string;
delay?: number;
duration?: number;
startXOffset?: number;
startYOffset?: number;
endXOffset?: number;
endYOffset?: number;
bidirectional?: boolean;
}
export const AnimatedAngledBeam: FC<AnimatedAngledBeamProps> = ({
className,
containerRef,
fromRef,
toRef,
reverse = false,
duration = Math.random() * 3 + 8,
delay = 0,
pathColor = '#cbd5e1',
pathWidth = 2,
pathOpacity = 1,
gradientStartColor = '#ffaa40',
gradientStopColor = '#9c40ff',
startXOffset = 0,
startYOffset = 0,
endXOffset = 0,
endYOffset = 0,
bidirectional = false,
}) => {
const id = useId();
const [pathD, setPathD] = useState('');
const [svgDimensions, setSvgDimensions] = useState({ width: 0, height: 0 });
const [totalLength, setTotalLength] = useState(0);
useEffect(() => {
const updatePath = () => {
if (containerRef.current && fromRef.current && toRef.current) {
const containerRect = containerRef.current.getBoundingClientRect();
const fromRect = fromRef.current.getBoundingClientRect();
const toRect = toRef.current.getBoundingClientRect();
const svgWidth = containerRect.width;
const svgHeight = containerRect.height;
setSvgDimensions({ width: svgWidth, height: svgHeight });
const startX =
fromRect.left -
containerRect.left +
fromRect.width / 2 +
startXOffset;
const startY =
fromRect.top - containerRect.top + fromRect.height / 2 + startYOffset;
const endX =
toRect.left - containerRect.left + toRect.width / 2 + endXOffset;
const endY =
toRect.top - containerRect.top + toRect.height / 2 + endYOffset;
// Create a path with 90-degree angles
const midY = (startY + endY) / 2;
const d = `M ${startX},${startY} V ${midY} H ${endX} V ${endY}`;
setPathD(d);
// Calculate total length of the path
const tempPath = document.createElementNS(
'http://www.w3.org/2000/svg',
'path'
);
tempPath.setAttribute('d', d);
setTotalLength(tempPath.getTotalLength());
}
};
const resizeObserver = new ResizeObserver((entries) => {
for (let entry of entries) {
updatePath();
}
});
if (containerRef.current) {
resizeObserver.observe(containerRef.current);
}
updatePath();
return () => {
resizeObserver.disconnect();
};
}, [
containerRef,
fromRef,
toRef,
startXOffset,
startYOffset,
endXOffset,
endYOffset,
]);
return (
<svg
fill="none"
width={svgDimensions.width}
height={svgDimensions.height}
xmlns="http://www.w3.org/2000/svg"
className={cx(
'pointer-events-none absolute left-0 top-0 transform-gpu stroke-2',
className
)}
viewBox={`0 0 ${svgDimensions.width} ${svgDimensions.height}`}
>
<path
d={pathD}
stroke={pathColor}
strokeWidth={pathWidth}
strokeOpacity={pathOpacity}
strokeLinecap="round"
/>
<path
d={pathD}
strokeWidth={pathWidth}
stroke={`url(#${id})`}
strokeOpacity="1"
strokeLinecap="round"
strokeDasharray={totalLength}
strokeDashoffset="0"
>
<animate
attributeName="stroke-dashoffset"
values={
bidirectional
? `${reverse ? -totalLength : totalLength};${
reverse ? totalLength : -totalLength
};${reverse ? -totalLength : totalLength}`
: `${reverse ? -totalLength : totalLength};${
reverse ? totalLength : -totalLength
}`
}
dur={`${bidirectional ? duration * 2 : duration}s`}
repeatCount="indefinite"
/>
</path>
<defs>
<linearGradient id={id} gradientUnits="userSpaceOnUse">
<stop stopColor={gradientStartColor} stopOpacity="0" offset="0%" />
<stop stopColor={gradientStartColor} offset="10%"></stop>
<stop stopColor={gradientStopColor} offset="90%"></stop>
<stop stopColor={gradientStopColor} stopOpacity="0" offset="100%" />
</linearGradient>
</defs>
</svg>
);
};

View File

@ -27,7 +27,7 @@ export { resourceMenuItems } from './lib/headers/menu-items';
export { solutionsMenuItems } from './lib/headers/menu-items';
export { eventItems } from './lib/headers/menu-items';
export { learnItems } from './lib/headers/menu-items';
export { plans } from './lib/headers/menu-items';
export { solutions as plans } from './lib/headers/menu-items';
export { featuresItems } from './lib/headers/menu-items';
export { DefaultMenuItem } from './lib/headers/default-menu-item';
export { MobileMenuItem } from './lib/headers/mobile-menu-item';

View File

@ -8,7 +8,7 @@ export function DefaultLayout({
children,
}: { isHome?: boolean } & PropsWithChildren): JSX.Element {
return (
<div className="dark:bg-slate-950">
<div className="w-full overflow-hidden dark:bg-slate-950">
<Header />
<div className="relative isolate">
<div

View File

@ -14,7 +14,7 @@ import {
eventItems,
featuresItems,
learnItems,
plans,
solutions,
resourceMenuItems,
solutionsMenuItems,
} from './menu-items';
@ -431,7 +431,7 @@ export function Header(): JSX.Element {
/>
</Disclosure.Button>
<Disclosure.Panel as="ul" className="space-y-1">
{plans.map((item) => (
{solutions.map((item) => (
<MobileMenuItem
key={item.name}
item={item}

View File

@ -120,7 +120,7 @@ export const featuresItems: MenuItem[] = [
isHighlight: true,
},
];
export const plans: MenuItem[] = [
export const solutions: MenuItem[] = [
{
name: 'Nx Cloud',
description:
@ -130,6 +130,15 @@ export const plans: MenuItem[] = [
isNew: false,
isHighlight: false,
},
{
name: 'Nx Powerpack',
description:
'A suite of paid extensions for the Nx CLI specifically designed for enterprises.',
href: '/powerpack',
icon: null,
isNew: false,
isHighlight: false,
},
{
name: 'Nx Enterprise',
description:
@ -278,7 +287,7 @@ export const companyItems: MenuItem[] = [
},
];
export const solutionsMenuItems = {
'Helping you grow': plans,
'Helping you grow': solutions,
// 'Use cases': useCaseItems
};
export const resourceMenuItems = {

View File

@ -76,6 +76,7 @@ export * from './lib/editors/visual-studio-code';
// OTHERS
export * from './lib/monorepo-world';
export * from './lib/others/amazon-s3';
// PODCASTS
export * from './lib/podcasts/amazon-music';

View File

@ -0,0 +1,17 @@
import { FC, SVGProps } from 'react';
/**
* Use `#569A31` for a colored version.
*/
export const AmazonS3Icon: FC<SVGProps<SVGSVGElement>> = (props) => (
<svg
role="img"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
{...props}
>
<title>Amazon S3</title>
<path d="M20.913 13.147l.12-.895c.947.576 1.258.922 1.354 1.071-.16.031-.562.046-1.474-.176zm-2.174 7.988a.547.547 0 0 0-.005.073c0 .084-.207.405-1.124.768a10.28 10.28 0 0 1-1.438.432c-1.405.325-3.128.504-4.853.504-4.612 0-7.412-1.184-7.412-1.704a.547.547 0 0 0-.005-.073L1.81 5.602c.135.078.28.154.432.227.042.02.086.038.128.057.134.062.272.122.417.18l.179.069c.154.058.314.114.478.168.043.013.084.029.13.043.207.065.423.127.646.187l.176.044c.175.044.353.087.534.127a23.414 23.414 0 0 0 .843.17l.121.023c.252.045.508.085.768.122.071.011.144.02.216.03.2.027.4.053.604.077l.24.027c.245.026.49.05.74.07l.081.009c.275.022.552.04.83.056l.233.012c.21.01.422.018.633.025a33.088 33.088 0 0 0 2.795-.026l.232-.011c.278-.016.555-.034.83-.056l.08-.008c.25-.02.497-.045.742-.072l.238-.026c.205-.024.408-.05.609-.077.07-.01.141-.019.211-.03.261-.037.519-.078.772-.122l.111-.02c.215-.04.427-.082.634-.125l.212-.047c.186-.041.368-.085.546-.13l.166-.042c.225-.06.444-.122.654-.189.04-.012.077-.026.115-.038a10.6 10.6 0 0 0 .493-.173c.058-.021.114-.044.17-.066.15-.06.293-.12.43-.185.038-.017.079-.034.116-.052.153-.073.3-.15.436-.228l-.976 7.245c-2.488-.78-5.805-2.292-7.311-3a1.09 1.09 0 0 0-1.088-1.085c-.6 0-1.088.489-1.088 1.088 0 .6.488 1.089 1.088 1.089.196 0 .378-.056.537-.148 1.72.812 5.144 2.367 7.715 3.15zm-7.42-20.047c5.677 0 9.676 1.759 9.75 2.736l-.014.113c-.01.033-.031.067-.048.101-.015.028-.026.057-.047.087-.024.033-.058.068-.09.102-.028.03-.051.06-.084.09-.038.035-.087.07-.133.105-.04.03-.074.06-.119.091-.053.036-.116.071-.177.107-.05.03-.095.06-.15.09-.068.036-.147.073-.222.11-.059.028-.114.057-.177.085-.084.038-.177.074-.268.111-.068.027-.13.054-.203.082-.097.036-.205.072-.31.107-.075.026-.148.053-.228.079-.111.035-.233.069-.35.103-.085.024-.165.05-.253.073-.124.034-.258.065-.389.098-.093.022-.181.046-.278.068-.139.032-.287.061-.433.091-.098.02-.191.041-.293.06-.155.03-.32.057-.482.084-.1.018-.198.036-.302.052-.166.026-.342.048-.515.072-.11.014-.213.03-.325.044-.181.023-.372.041-.56.06-.11.012-.218.025-.332.036-.188.016-.386.029-.58.043-.122.009-.24.02-.364.028-.207.012-.422.02-.635.028-.12.005-.234.012-.354.016a35.605 35.605 0 0 1-2.069 0c-.12-.004-.234-.011-.352-.016-.214-.008-.43-.016-.637-.028-.122-.008-.238-.02-.36-.027-.195-.015-.394-.028-.584-.044-.11-.01-.215-.024-.324-.035-.19-.02-.384-.038-.568-.06l-.315-.044c-.176-.024-.355-.046-.525-.073-.1-.015-.192-.033-.29-.05-.167-.028-.335-.055-.494-.086-.096-.018-.183-.038-.276-.056-.151-.032-.305-.062-.45-.095-.09-.02-.173-.043-.26-.064-.138-.034-.277-.067-.407-.102-.082-.022-.157-.046-.235-.069a11.75 11.75 0 0 1-.368-.108c-.075-.024-.141-.049-.213-.073-.11-.037-.223-.075-.325-.113-.067-.025-.125-.051-.188-.077-.096-.038-.195-.076-.282-.115-.06-.027-.11-.054-.166-.08-.08-.039-.162-.077-.233-.116-.052-.028-.094-.055-.142-.084-.063-.038-.13-.075-.185-.113-.043-.029-.075-.058-.113-.086-.048-.037-.098-.073-.139-.11-.032-.029-.054-.057-.08-.087-.033-.035-.069-.07-.093-.104-.02-.03-.031-.058-.046-.086-.018-.035-.039-.068-.049-.102l-.015-.113c.076-.977 4.074-2.736 9.748-2.736zm12.182 12.124c-.118-.628-.84-1.291-2.31-2.128l.963-7.16a.531.531 0 0 0 .005-.073C22.16 1.581 16.447 0 11.32 0 6.194 0 .482 1.581.482 3.851a.58.58 0 0 0 .005.072L2.819 21.25c.071 2.002 5.236 2.75 8.5 2.75 1.805 0 3.615-.188 5.098-.531.598-.138 1.133-.3 1.592-.48 1.18-.467 1.789-1.053 1.813-1.739l.945-7.018c.557.131 1.016.197 1.389.197.54 0 .902-.137 1.134-.413a.956.956 0 0 0 .21-.804Z" />
</svg>
);

View File

@ -0,0 +1,18 @@
{
"extends": ["plugin:@nx/react", "../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}

View File

@ -0,0 +1,7 @@
# ui-powerpack
This library was generated with [Nx](https://nx.dev).
## Running unit tests
Run `nx test ui-powerpack` to execute the unit tests via [Jest](https://jestjs.io).

View File

@ -0,0 +1,9 @@
{
"name": "ui-powerpack",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "nx-dev/ui-powerpack/src",
"projectType": "library",
"tags": [],
"// targets": "to see all targets run: nx show project ui-powerpack --web",
"targets": {}
}

View File

@ -0,0 +1,7 @@
// Use this file to export React client components (e.g. those with 'use client' directive) or other non-server utilities
export * from './lib/hero';
export * from './lib/powerpack-features';
export * from './lib/get-started';
export * from './lib/powerpack-pricing';
export * from './lib/call-to-action';

View File

@ -0,0 +1,85 @@
import Link from 'next/link';
import { ReactElement } from 'react';
export function CallToAction(): ReactElement {
return (
<section className="relative isolate px-6 py-32 sm:py-40 lg:px-8">
<svg
className="absolute inset-0 -z-10 h-full w-full stroke-black/10 [mask-image:radial-gradient(100%_100%_at_top_right,white,transparent)] dark:stroke-white/10"
aria-hidden="true"
>
<defs>
<pattern
id="1d4240dd-898f-445f-932d-e2872fd12de3"
width={200}
height={200}
x="50%"
y={0}
patternUnits="userSpaceOnUse"
>
<path d="M.5 200V.5H200" fill="none" />
</pattern>
</defs>
<svg
x="50%"
y={0}
className="overflow-visible fill-slate-200/20 dark:fill-slate-800/20"
>
<path
d="M-200 0h201v201h-201Z M600 0h201v201h-201Z M-400 600h201v201h-201Z M200 800h201v201h-201Z"
strokeWidth={0}
/>
</svg>
<rect
width="100%"
height="100%"
strokeWidth={0}
fill="url(#1d4240dd-898f-445f-932d-e2872fd12de3)"
/>
</svg>
<div
className="pointer-events-none absolute inset-x-0 top-10 -z-10 flex transform-gpu justify-center overflow-hidden blur-3xl"
aria-hidden="true"
>
<div
className="aspect-[1108/632] w-[69.25rem] flex-none bg-gradient-to-r from-[#80caff] to-[#4f46e5] opacity-20"
style={{
clipPath:
'polygon(73.6% 51.7%, 91.7% 11.8%, 100% 46.4%, 97.4% 82.2%, 92.5% 84.9%, 75.7% 64%, 55.3% 47.5%, 46.5% 49.4%, 45% 62.9%, 50.3% 87.2%, 21.3% 64.1%, 0.1% 100%, 5.4% 51.1%, 21.4% 63.9%, 58.9% 0.2%, 73.6% 51.7%)',
}}
/>
</div>
<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"
>
Ready to enhance your CLI?
</h2>
<div className="mt-10 flex items-center justify-center gap-x-6">
<a
href="https://cloud.nx.app/powerpack/purchase"
title="Get your Nx Powerapp license"
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"
>
Get Nx Powerpack
</a>
<Link
href="/contact"
title="Get in touch"
prefetch={false}
className="group text-sm font-semibold leading-6 text-slate-950 dark:text-white"
>
Contact us{' '}
<span
aria-hidden="true"
className="inline-block transition group-hover:translate-x-1"
>
</span>
</Link>
</div>
</div>
</section>
);
}

View File

@ -0,0 +1,172 @@
import { SectionHeading, TextLink } from '@nx/nx-dev/ui-common';
import { ReactElement } from 'react';
import { TerminalOutput } from '@nx/nx-dev/ui-fence';
import { PowerpackPricing } from './powerpack-pricing';
export function GetStarted(): ReactElement {
return (
<section id="get-started">
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto max-w-3xl text-center">
<SectionHeading as="h2" variant="title">
Premium features, <br /> carefully crafted DX
</SectionHeading>
<SectionHeading as="p" variant="subtitle" className="text mt-6">
Expand you capabilities with Nx Powerpack, <br /> a suite of
advanced tools designed for enterprises.
</SectionHeading>
</div>
<div className="relative mx-auto mt-16 max-w-2xl space-y-12">
<svg
className="absolute left-0 top-0 -z-10 -ml-20 hidden -translate-x-full -translate-y-1/2 transform lg:block"
width={200}
height={400}
fill="none"
viewBox="0 0 200 400"
aria-hidden="true"
>
<defs>
<pattern
id="de316486-4a29-4312-bdfc-fbce2132a2c1"
x={0}
y={0}
width={20}
height={20}
patternUnits="userSpaceOnUse"
>
<rect
x={0}
y={0}
width={4}
height={4}
className="text-slate-100 dark:text-slate-800/60"
fill="currentColor"
/>
</pattern>
</defs>
<rect
width={200}
height={400}
fill="url(#de316486-4a29-4312-bdfc-fbce2132a2c1)"
/>
</svg>
<svg
className="absolute bottom-0 right-0 -z-10 -mr-20 hidden translate-x-full translate-y-1/2 transform lg:block"
width={200}
height={400}
fill="none"
viewBox="0 0 200 400"
aria-hidden="true"
>
<defs>
<pattern
id="de316486-4a29-4312-bdfc-fbce2132a2c1"
x={0}
y={0}
width={20}
height={20}
patternUnits="userSpaceOnUse"
>
<rect
x={0}
y={0}
width={4}
height={4}
className="text-slate-100 dark:text-slate-800/60"
fill="currentColor"
/>
</pattern>
</defs>
<rect
width={200}
height={400}
fill="url(#de316486-4a29-4312-bdfc-fbce2132a2c1)"
/>
</svg>
<div className="space-y-6 lg:space-y-12">
<div className="flex items-start gap-6">
<div className="relative flex size-10 place-items-center rounded-full p-4 shadow-sm ring-1 ring-slate-200 dark:ring-slate-800/60">
<span className="text-lg text-slate-900 dark:text-slate-100">
1
</span>
</div>
<div>
<h4 className="relative text-base font-medium leading-6 text-slate-900 dark:text-slate-100">
Buy an Nx Powerpack license
</h4>
<p className="mt-2">
Select between monthly payments or a one-time annual fee for
your license.
</p>
<div className="mx-auto mt-4 max-w-md">
<PowerpackPricing />
</div>
</div>
</div>
<div className="flex items-start gap-6">
<div className="relative flex size-10 place-items-center rounded-full p-4 shadow-sm ring-1 ring-slate-200 dark:ring-slate-800/60">
<span className="text-lg text-slate-900 dark:text-slate-100">
2
</span>
</div>
<div>
<h4 className="relative text-base font-medium leading-6 text-slate-900 dark:text-slate-100">
Activate Nx Powerpack right from your terminal
</h4>
<p className="mt-2">
In your Nx workspace, run the following command to activate
your new license.
</p>
<div className="mt-4">
<TerminalOutput
command="nx activate-powerpack {YOUR_LICENSE_KEY}"
path="~/my-workspace"
title=""
content=""
/>
</div>
</div>
</div>
<div className="flex items-start gap-6">
<div className="relative flex size-10 place-items-center rounded-full p-4 shadow-sm ring-1 ring-slate-200 dark:ring-slate-800/60">
<span className="text-lg text-slate-900 dark:text-slate-100">
3
</span>
</div>
<div>
<h4 className="relative text-base font-medium leading-6 text-slate-900 dark:text-slate-100">
Install Powerpack plugins
</h4>
<p className="mt-2">
Install Powerpack plugins such as{' '}
<TextLink
href="/features/powerpack/custom-caching"
title="Self-hosted cache storage"
>
Self-hosted cache storage
</TextLink>
,{' '}
<TextLink
href="/features/powerpack/conformance"
title="Workspace conformance"
>
workspace conformance
</TextLink>
, and{' '}
<TextLink
href="/features/powerpack/owners"
title="Codeowners for monorepos"
>
Codeowners for monorepos
</TextLink>
.
</p>
</div>
</div>
</div>
</div>
</div>
</section>
);
}

View File

@ -0,0 +1,29 @@
'use client';
import { ButtonLink, SectionHeading, Strong } from '@nx/nx-dev/ui-common';
import { ReactElement } from 'react';
export function Hero(): ReactElement {
return (
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto max-w-2xl text-center">
<SectionHeading as="h1" variant="display">
Nx Powerpack
</SectionHeading>
<SectionHeading as="p" variant="subtitle" className="mt-6 text-center">
A suite of paid extensions for the Nx CLI specifically designed for
enterprises, <Strong>built and supported by the Nx core team</Strong>.
</SectionHeading>
<div className="mt-10 text-center">
<ButtonLink
href="https://cloud.nx.app/powerpack/purchase?utm_source=nx.dev&utm_medium=referral&utm_campaign=nx-powerpackurl"
title="Talk to the engineering team"
variant="primary"
size="default"
>
Get Powerpack
</ButtonLink>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,262 @@
'use client';
import { forwardRef, ReactElement, ReactNode, useRef } from 'react';
import { ButtonLink, SectionHeading, Strong } from '@nx/nx-dev/ui-common';
import { cx } from '@nx/nx-dev/ui-primitives';
import { AnimatedAngledBeam } from '@nx/nx-dev/ui-animations';
import {
CalendarDaysIcon,
CircleStackIcon,
ServerIcon,
} from '@heroicons/react/24/outline';
import { NxIcon } from '@nx/nx-dev/ui-icons';
export function PowerpackFeatures(): ReactElement {
return (
<section className="relative isolate">
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="grid grid-cols-1 gap-8 lg:grid-cols-2">
<div className="col-span-full flex max-w-full flex-col gap-16 bg-white/50 px-6 py-16 ring-1 ring-slate-200 sm:rounded-3xl sm:p-8 lg:mx-0 lg:max-w-full lg:flex-row lg:items-center lg:py-16 xl:px-16 dark:bg-white/5 dark:ring-white/10">
<div className="xl:max-w-xl">
<SectionHeading
as="h2"
variant="title"
id="self-hosted-cache-storage"
className="scroll-mt-48"
>
Self-hosted cache storage
</SectionHeading>
<p className="mt-6 text-pretty text-lg">
Nx Powerpack enables you to use <Strong>AWS S3</Strong> or a{' '}
<Strong>shared network drive</Strong> as your remote cache
storage, offering a flexible, self-managed solution for faster
builds.
</p>
<div className="mt-16">
<ButtonLink
href="/features/powerpack/custom-caching"
title="Learn more about self-hosted cache storage"
variant="secondary"
size="default"
>
Learn more about self-hosted cache storage
</ButtonLink>
</div>
</div>
<div className="hidden w-full lg:block">
<CustomRemoteCacheAnimation />
</div>
</div>
<div className="flex flex-col gap-16 bg-white/50 px-6 py-16 ring-1 ring-slate-200 sm:rounded-3xl sm:p-8 lg:mx-0 lg:max-w-none lg:justify-between lg:py-16 xl:px-16 dark:bg-white/5 dark:ring-white/10">
<div className="max-w-2xl">
<SectionHeading
as="h2"
variant="title"
id="codeowners-for-monorepos"
className="scroll-mt-48"
>
Codeowners for monorepos
</SectionHeading>
<p className="mt-6 text-pretty text-lg">
Common VCS providers require folder-based ownership definitions.
Now, define and manage ownership where it matters
<Strong>at the project level</Strong>
</p>
<p className="mt-6 text-pretty text-lg">
Nx Powerpack codeowners bridges this gap by{' '}
<Strong>
automatically tracking changes and syncing ownership data
</Strong>{' '}
with GitHub, GitLab, or Bitbucket-specific CODEOWNERS files.
This ensures clear responsibilities and enables efficient
collaboration across large-scale projects.
</p>
</div>
<div className="flex">
<ButtonLink
href="/features/powerpack/owners"
title="Learn more about codeowners"
variant="secondary"
size="default"
>
Learn more about codeowners
</ButtonLink>
</div>
</div>
<div className="flex flex-col gap-16 bg-white/50 px-6 py-16 ring-1 ring-slate-200 sm:rounded-3xl sm:p-8 lg:mx-0 lg:max-w-none lg:justify-between lg:py-16 xl:px-16 dark:bg-white/5 dark:ring-white/10">
<div className="max-w-2xl">
<SectionHeading
as="h2"
variant="title"
id="workspace-conformance"
className="scroll-mt-48"
>
Workspace conformance
</SectionHeading>
<p className="mt-6 text-pretty text-lg">
Ensuring consistent code quality and long-term maintainability
across large teams is critical. Nx Powerpack allows you to{' '}
<Strong>
define and run conformance rules throughout your workspace
</Strong>
, leverage built-in rules or{' '}
<Strong>
create your own to ensure compliance with organizational
standards.
</Strong>
</p>
<p className="mt-6 text-pretty text-lg">
With Nx Cloud Enterprise Edition, you can{' '}
<Strong>
upload your custom rules to your Nx Cloud organization
</Strong>{' '}
and automatically enforce them across multiple repositories and
workspaces, regardless of your tech stack.
</p>
</div>
<div className="flex">
<ButtonLink
href="/features/powerpack/conformance"
title="Learn how to set up conformance rules"
variant="secondary"
size="default"
>
Learn how to use conformance rules
</ButtonLink>
</div>
</div>
</div>
</div>
<div
className="absolute inset-x-0 top-16 -z-10 flex transform-gpu justify-center overflow-hidden blur-3xl"
aria-hidden="true"
>
<div
className="aspect-[1318/752] w-[82.375rem] flex-none bg-gradient-to-r from-[#80caff] to-[#4f46e5] opacity-25"
style={{
clipPath:
'polygon(73.6% 51.7%, 91.7% 11.8%, 100% 46.4%, 97.4% 82.2%, 92.5% 84.9%, 75.7% 64%, 55.3% 47.5%, 46.5% 49.4%, 45% 62.9%, 50.3% 87.2%, 21.3% 64.1%, 0.1% 100%, 5.4% 51.1%, 21.4% 63.9%, 58.9% 0.2%, 73.6% 51.7%)',
}}
/>
</div>
</section>
);
}
const Card = forwardRef<
HTMLDivElement,
{ className?: string; children?: ReactNode }
>(({ className, children }, ref) => {
return (
<div
ref={ref}
className={cx(
'z-10 flex flex-col items-center justify-between rounded-lg border border-slate-200 bg-white p-4 shadow-sm dark:border-white/10 dark:bg-slate-950',
className
)}
>
{children}
</div>
);
});
Card.displayName = 'Card';
export function CustomRemoteCacheAnimation(): ReactElement {
const containerRef = useRef<HTMLDivElement>(null);
const gitHubRef = useRef<HTMLDivElement>(null);
const gitlabRef = useRef<HTMLDivElement>(null);
const nxRef = useRef<HTMLDivElement>(null);
const computerRef = useRef<HTMLDivElement>(null);
return (
<div className="relative flex h-full w-full" ref={containerRef}>
<div className="flex w-full flex-col items-center justify-center gap-24">
<div className="flex w-full justify-center">
<Card ref={nxRef} className="size-18 relative">
<NxIcon
aria-hidden="true"
className="size-10 text-slate-900 dark:text-white"
/>
<CircleStackIcon
aria-hidden="true"
className="absolute bottom-1 right-1 size-5 text-slate-900 dark:text-white"
/>
</Card>
</div>
<div className="grid w-full grid-cols-3 items-stretch gap-4">
<Card ref={gitlabRef}>
<div className="text-center text-sm text-slate-900 dark:text-white">
AWS
</div>
<div className="mt-2 text-center text-2xl font-semibold">S3</div>
<ButtonLink
href="/nx-api/powerpack-s3-cache"
title="Learn how to configure AWS S3 caching"
variant="secondary"
size="small"
className="mt-4"
>
Get started
</ButtonLink>
</Card>
<Card ref={computerRef}>
<div className="text-center text-sm text-slate-900 dark:text-white">
Network drive
</div>
<ServerIcon aria-hidden="true" className="size-6" />
<ButtonLink
href="/nx-api/powerpack-shared-fs-cache"
title="Learn how to configure network drive caching"
variant="secondary"
size="small"
className="mt-4"
>
Get started
</ButtonLink>
</Card>
<Card ref={gitHubRef}>
<div className="text-center text-sm text-slate-900 dark:text-white">
More soon!
</div>
<CalendarDaysIcon aria-hidden="true" className="size-6" />
<div className="mt-4 size-8" />
</Card>
</div>
</div>
<AnimatedAngledBeam
containerRef={containerRef}
fromRef={gitlabRef}
toRef={nxRef}
endYOffset={0}
bidirectional={true}
duration={3}
/>
<AnimatedAngledBeam
containerRef={containerRef}
fromRef={computerRef}
toRef={nxRef}
startYOffset={0}
endYOffset={0}
startXOffset={0}
endXOffset={0}
bidirectional={true}
duration={3}
delay={1}
/>
<AnimatedAngledBeam
containerRef={containerRef}
fromRef={gitHubRef}
toRef={nxRef}
endYOffset={0}
bidirectional={true}
duration={3}
delay={2}
/>
</div>
);
}

View File

@ -0,0 +1,74 @@
'use client';
import { ArrowRightIcon } from '@heroicons/react/24/outline';
import { ButtonLink } from '@nx/nx-dev/ui-common';
export function PowerpackPricing() {
return (
<aside>
{/*<h4 className="text-lg font-medium leading-6 text-slate-900 dark:text-slate-100">*/}
{/* Nx Powerpack license subscription*/}
{/*</h4>*/}
<div className="flex flex-col gap-2">
<div className="group relative flex w-full items-center justify-between gap-8 rounded-md border border-slate-200 bg-white px-6 py-4 transition hover:bg-white/90 hover:shadow dark:border-slate-800/60 dark:bg-slate-900/60 dark:hover:bg-slate-900/100">
<a
href="https://cloud.nx.app/powerpack/purchase?utm_source=nx.dev&utm_medium=referral&utm_campaign=nx-powerpackurl"
title="Buy your license"
className="flex items-center gap-2"
>
<span className="absolute inset-0" />
<ArrowRightIcon aria-hidden="true" className="size-4" />
<span className="text-sm font-medium leading-none text-slate-900 dark:text-slate-50">
Billed annually
</span>
<span className="inline-flex items-center gap-x-1 whitespace-nowrap rounded-md bg-blue-50 px-2 py-1 text-xs font-medium text-blue-900 ring-1 ring-inset ring-blue-500/30 dark:bg-blue-400/10 dark:text-blue-400 dark:ring-blue-400/30">
Save 20%
</span>
</a>
<p className="text-base">
<span className="font-semibold text-slate-950 dark:text-white">
$250
</span>
<span className="text-xs text-slate-500 dark:text-slate-400">
/seat
</span>
</p>
</div>
</div>
<div className="mt-4 flex flex-col gap-2">
<div className="group relative flex w-full items-center justify-between gap-8 rounded-md border border-slate-200 bg-white px-6 py-4 transition hover:bg-white/90 hover:shadow dark:border-slate-800/60 dark:bg-slate-900/60 dark:hover:bg-slate-900/100">
<a
href="https://cloud.nx.app/powerpack/purchase?utm_source=nx.dev&utm_medium=referral&utm_campaign=nx-powerpackurl"
title="Buy your license"
className="flex items-center gap-2"
>
<span className="absolute inset-0" />
<ArrowRightIcon aria-hidden="true" className="size-4" />
<span className="text-sm font-medium leading-none text-slate-900 dark:text-slate-50">
Billed monthly
</span>
</a>
<p className="text-base">
<span className="font-semibold text-slate-950 dark:text-white">
$26
</span>
<span className="text-xs text-slate-500 dark:text-slate-400">
/seat
</span>
</p>
</div>
</div>
<div className="mt-4 flex flex-col gap-2">
<ButtonLink
href="https://cloud.nx.app/powerpack/purchase?utm_source=nx.dev&utm_medium=referral&utm_campaign=nx-powerpackurl"
title="Talk to the engineering team"
variant="primary"
size="default"
>
Buy your Nx Powerpack license
</ButtonLink>
</div>
</aside>
);
}

View File

@ -0,0 +1 @@
// Use this file to export React server components

View File

@ -0,0 +1,17 @@
{
"compilerOptions": {
"jsx": "react-jsx",
"allowJs": false,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
}
],
"extends": "../../tsconfig.base.json"
}

View File

@ -0,0 +1,23 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"types": [
"node",
"@nx/react/typings/cssmodule.d.ts",
"@nx/react/typings/image.d.ts"
]
},
"exclude": [
"jest.config.ts",
"src/**/*.spec.ts",
"src/**/*.test.ts",
"src/**/*.spec.tsx",
"src/**/*.test.tsx",
"src/**/*.spec.js",
"src/**/*.test.js",
"src/**/*.spec.jsx",
"src/**/*.test.jsx"
],
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
}

16
nx.json
View File

@ -234,6 +234,15 @@
"targetName": "e2e-macos-local",
"ciTargetName": "e2e-macos-ci"
}
},
{
"plugin": "@nx/next/plugin",
"options": {
"startTargetName": "next:start",
"buildTargetName": "next:build",
"devTargetName": "dev",
"serveStaticTargetName": "serve-static"
}
}
],
"nxCloudId": "62d013ea0852fe0a2df74438",
@ -241,5 +250,10 @@
"parallel": 1,
"cacheDirectory": "/tmp/nx-cache",
"bust": 8,
"defaultBase": "master"
"defaultBase": "master",
"generators": {
"@nx/react": {
"library": {}
}
}
}

View File

@ -108,6 +108,7 @@
"@nx/nx-dev/ui-markdoc": ["nx-dev/ui-markdoc/src/index.ts"],
"@nx/nx-dev/ui-member-card": ["nx-dev/ui-member-card/src/index.ts"],
"@nx/nx-dev/ui-podcast": ["nx-dev/ui-podcast/src/index.ts"],
"@nx/nx-dev/ui-powerpack": ["nx-dev/ui-powerpack/src/index.ts"],
"@nx/nx-dev/ui-pricing": ["nx-dev/ui-pricing/src/index.ts"],
"@nx/nx-dev/ui-primitives": ["nx-dev/ui-primitives/src/index.ts"],
"@nx/nx-dev/ui-references": ["nx-dev/ui-references/src/index.ts"],