docs(nxdev): home updates (#7567)
@ -1,14 +1,20 @@
|
||||
# Mental Model
|
||||
|
||||
Nx is a VSCode of build tools, with a powerful core, driven by metadata, and extensible through plugins. Nx works with a few concepts to drive your monorepo efficiently, and effectively. This guide covers the mental model around how Nx works with project graphs, task graphs, affected commands, computation hashing and caching.
|
||||
Nx is a VSCode of build tools, with a powerful core, driven by metadata, and extensible through plugins. Nx works with a
|
||||
few concepts to drive your monorepo efficiently, and effectively. This guide covers the mental model around how Nx works
|
||||
with project graphs, task graphs, affected commands, computation hashing and caching.
|
||||
|
||||
## The project graph
|
||||
|
||||
A project graph is used to reflect the source code in your repository and all the external dependencies that aren’t authored in your repository, such as Webpack, React, Angular, and so forth.
|
||||
A project graph is used to reflect the source code in your repository and all the external dependencies that aren’t
|
||||
authored in your repository, such as Webpack, React, Angular, and so forth.
|
||||
|
||||

|
||||
|
||||
With Nx, nodes in the project graph are defined in `workspace.json`. You can manually define dependencies between the nodes, but you don’t have to do it very often. Nx analyzes files’ source code, your installed dependencies, TypeScript files, and others figuring out these dependencies for you. Nx also stores the cached project graph, so it only reanalyzes the files you have changed.
|
||||
With Nx, nodes in the project graph are defined in `workspace.json`. You can manually define dependencies between the
|
||||
nodes, but you don’t have to do it very often. Nx analyzes files’ source code, your installed dependencies, TypeScript
|
||||
files, and others figuring out these dependencies for you. Nx also stores the cached project graph, so it only
|
||||
reanalyzes the files you have changed.
|
||||
|
||||

|
||||
|
||||
@ -16,7 +22,8 @@ Nx provides an updated graph after each analysis is done.
|
||||
|
||||
## Metadata-driven
|
||||
|
||||
Everything in Nx comes with metadata to enable toolability. The default values, validations, autocompletion work, and more are all defined in a schema, instead of in code.
|
||||
Everything in Nx comes with metadata to enable toolability. The default values, validations, autocompletion work, and
|
||||
more are all defined in a schema, instead of in code.
|
||||
|
||||
The following sample schema shows inputs, prompts, and validations for adding a new application.
|
||||
|
||||
@ -52,7 +59,10 @@ The following sample schema shows inputs, prompts, and validations for adding a
|
||||
"message": "Which stylesheet format would you like to use?",
|
||||
"type": "list",
|
||||
"items": [
|
||||
{ "value": "css", "label": "CSS" },
|
||||
{
|
||||
"value": "css",
|
||||
"label": "CSS"
|
||||
},
|
||||
{
|
||||
"value": "scss",
|
||||
"label": "SASS(.scss) [ http://sass-lang.com ]"
|
||||
@ -116,7 +126,8 @@ The following sample schema shows inputs, prompts, and validations for adding a
|
||||
}
|
||||
```
|
||||
|
||||
This metadata is used by Nx itself, by VSCode and WebStorm integrations, by GitHub integration, and by third-party tools.
|
||||
This metadata is used by Nx itself, by VSCode and WebStorm integrations, by GitHub integration, and by third-party
|
||||
tools.
|
||||
|
||||

|
||||
|
||||
@ -124,7 +135,8 @@ These tools are able to implement richer experiences with Nx using this metadata
|
||||
|
||||
## The task graph
|
||||
|
||||
Nx uses the project graph to create a task graph. Any time you run anything, Nx creates a task graph from the project graph and then executes the tasks in that graph.
|
||||
Nx uses the project graph to create a task graph. Any time you run anything, Nx creates a task graph from the project
|
||||
graph and then executes the tasks in that graph.
|
||||
|
||||
For instance `nx test lib` creates a task graph with a single node:
|
||||
|
||||
@ -132,11 +144,14 @@ For instance `nx test lib` creates a task graph with a single node:
|
||||
|
||||
A task is an invocation of a target. If you invoke the same target twice, you create two tasks.
|
||||
|
||||
Nx uses the [project graph](#the-project-graph), but the task graph and project graph aren’t isomorphic, meaning they aren’t directly connected. In the case above, app1 and app2 depend on lib, but running `nx run-many --target=test --projects=app1,app2,lib`, the created task graph will look like this:
|
||||
Nx uses the [project graph](#the-project-graph), but the task graph and project graph aren’t isomorphic, meaning they
|
||||
aren’t directly connected. In the case above, app1 and app2 depend on lib, but
|
||||
running `nx run-many --target=test --projects=app1,app2,lib`, the created task graph will look like this:
|
||||
|
||||

|
||||
|
||||
Even though the apps depend on lib, testing `app1` doesn’t depend on the testing lib. This means that the two tasks can run in parallel.
|
||||
Even though the apps depend on lib, testing `app1` doesn’t depend on the testing lib. This means that the two tasks can
|
||||
run in parallel.
|
||||
|
||||
Let’s look at the test target relying on its dependencies.
|
||||
|
||||
@ -145,7 +160,12 @@ Let’s look at the test target relying on its dependencies.
|
||||
"test": {
|
||||
"executor": "@nrwl/jest:jest",
|
||||
"outputs": ["coverage/apps/app1"],
|
||||
"dependsOn": [{ "target": "test", "projects": "dependencies" }],
|
||||
"dependsOn": [
|
||||
{
|
||||
"target": "test",
|
||||
"projects": "dependencies"
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"jestConfig": "apps/app1/jest.config.js",
|
||||
"passWithNoTests": true
|
||||
@ -158,35 +178,46 @@ With this, running the same test command creates the following task graph:
|
||||
|
||||

|
||||
|
||||
This often makes more sense for builds, where to build app1, you want to build lib first. You can also define similar relationships between targets of the same project, including a test target that depends on the build.
|
||||
This often makes more sense for builds, where to build app1, you want to build lib first. You can also define similar
|
||||
relationships between targets of the same project, including a test target that depends on the build.
|
||||
|
||||
A task graph can contain different targets, and those can run in parallel. For instance, as Nx is building `app2`, it can be testing `app1` at the same time. Learn more about configuring targets in the [configuration guide](/{{framework}}/core-concepts/configuration)
|
||||
A task graph can contain different targets, and those can run in parallel. For instance, as Nx is building `app2`, it
|
||||
can be testing `app1` at the same time. Learn more about configuring targets in
|
||||
the [configuration guide](/{{framework}}/core-concepts/configuration)
|
||||
|
||||

|
||||
|
||||
Nx also runs the tasks in the task graph in the right order. Nx executing tasks being executed speeds up your overall execution time.
|
||||
Nx also runs the tasks in the task graph in the right order. Nx executing tasks being executed speeds up your overall
|
||||
execution time.
|
||||
|
||||
## Affected commands
|
||||
|
||||
When you run `nx test app1`, you are telling Nx to run the app1:test task plus all the tasks it depends on.
|
||||
|
||||
When you run `nx run-many --target=test --projects=app1,lib`, you are telling Nx to do the same for two tasks app1:test and lib:test.
|
||||
When you run `nx run-many --target=test --projects=app1,lib`, you are telling Nx to do the same for two tasks app1:test
|
||||
and lib:test.
|
||||
|
||||
When you run `nx run-many --target=test --all`, you are telling Nx to do this for all the projects.
|
||||
|
||||
As your workspace grows, retesting all projects becomes too slow. To address this Nx implements code change analysis to get the min set of projects that need to be retested. How does it work?
|
||||
As your workspace grows, retesting all projects becomes too slow. To address this Nx implements code change analysis to
|
||||
get the min set of projects that need to be retested. How does it work?
|
||||
|
||||
When you run `nx affected --target=test`, Nx looks at the files you changed in your PR, it will look at the nature of change (what exactly did you update in those files), and it uses this to figure the list of projects in the workspace that can be affected by this change. It then runs the `run-many` command with that list.
|
||||
When you run `nx affected --target=test`, Nx looks at the files you changed in your PR, it will look at the nature of
|
||||
change (what exactly did you update in those files), and it uses this to figure the list of projects in the workspace
|
||||
that can be affected by this change. It then runs the `run-many` command with that list.
|
||||
|
||||
For instance, if my PR changes `lib`, and I then run `nx affected --target=test`, Nx figures out that `app1` and `app2` depend on `lib`, so it will invoke `nx run-many --target=test --projects=app1,app2,lib`.
|
||||
For instance, if my PR changes `lib`, and I then run `nx affected --target=test`, Nx figures out that `app1` and `app2`
|
||||
depend on `lib`, so it will invoke `nx run-many --target=test --projects=app1,app2,lib`.
|
||||
|
||||

|
||||
|
||||
Nx analyzes the nature of the changes. For example, if you change the version of Next.js in the package.json, Nx knows that `app2` cannot be affected by it, so it only retests `app1`.
|
||||
Nx analyzes the nature of the changes. For example, if you change the version of Next.js in the package.json, Nx knows
|
||||
that `app2` cannot be affected by it, so it only retests `app1`.
|
||||
|
||||
## Computation hashing and caching
|
||||
|
||||
Nx runs the tasks in the task graph in the right order. Before running the task, Nx computes its computation hash. As long as the computation hash is the same, the output of running the task is the same.
|
||||
Nx runs the tasks in the task graph in the right order. Before running the task, Nx computes its computation hash. As
|
||||
long as the computation hash is the same, the output of running the task is the same.
|
||||
|
||||
How does Nx do it?
|
||||
|
||||
@ -200,36 +231,70 @@ By default, the computation hash for say `nx test app1` includes:
|
||||
|
||||

|
||||
|
||||
This behavior is customizable. For instance, lint checks may only depend on the source code of the project and global configs. Builds can depend on the dts files of the compiled libs instead of their source.
|
||||
This behavior is customizable. For instance, lint checks may only depend on the source code of the project and global
|
||||
configs. Builds can depend on the dts files of the compiled libs instead of their source.
|
||||
|
||||
After Nx computes the hash for a task, it then checks if it ran this exact computation before. First, it checks locally, and then if it is missing, and if a remote cache is configured, it checks remotely.
|
||||
After Nx computes the hash for a task, it then checks if it ran this exact computation before. First, it checks locally,
|
||||
and then if it is missing, and if a remote cache is configured, it checks remotely.
|
||||
|
||||
If Nx finds the computation, Nx retrieves it and replay it. Nx places the right files in the right folders and prints the terminal output. So from the user’s point of view, the command ran the same, just a lot faster.
|
||||
If Nx finds the computation, Nx retrieves it and replay it. Nx places the right files in the right folders and prints
|
||||
the terminal output. So from the user’s point of view, the command ran the same, just a lot faster.
|
||||
|
||||

|
||||
|
||||
If Nx doesn’t find this computation, Nx runs the task, and after it completes, it takes the outputs and the terminal output and stores it locally (and if configured remotely). All of this happens transparently, so you don’t have to worry about it.
|
||||
If Nx doesn’t find this computation, Nx runs the task, and after it completes, it takes the outputs and the terminal
|
||||
output and stores it locally (and if configured remotely). All of this happens transparently, so you don’t have to worry
|
||||
about it.
|
||||
|
||||
Although conceptually this is fairly straightforward, Nx optimizes this to make this experience good for you. For instance, Nx:
|
||||
Although conceptually this is fairly straightforward, Nx optimizes this to make this experience good for you. For
|
||||
instance, Nx:
|
||||
|
||||
- Captures stdout and stderr to make sure the replayed output looks the same, including on Windows.
|
||||
- Minimizes the IO by remembering what files are replayed where.
|
||||
- Only shows relevant output when processing a large task graph.
|
||||
- Provides affordances for troubleshooting cache misses.
|
||||
And many other optimizations.
|
||||
- Provides affordances for troubleshooting cache misses. And many other optimizations.
|
||||
|
||||
As your workspace grows, the task graph looks more like this:
|
||||
|
||||

|
||||
|
||||
All of these optimizations are crucial for making Nx usable for any non-trivial workspace. Only the minimum amount of work happens. The rest is either left as is or restored from the cache.
|
||||
All of these optimizations are crucial for making Nx usable for any non-trivial workspace. Only the minimum amount of
|
||||
work happens. The rest is either left as is or restored from the cache.
|
||||
|
||||
In summary:
|
||||
## Distributed task execution
|
||||
|
||||
Nx supports running commands across multiple machines. You can either set it up by hand (
|
||||
see [here](/ci/distributed-builds)) or use Nx
|
||||
CLoud. [Read the comparison of the two approaches.](https://blog.nrwl.io/distributing-ci-binning-and-distributed-task-execution-632fe31a8953?source=friends_link&sk=5120b7ff982730854ed22becfe7a640a)
|
||||
|
||||
Nx Cloud is a cloud companion for Nx (which is free and MIT-licensed). Most features of Nx Cloud are free, but some are
|
||||
paid. One of them is the distributed computation cache, which allows you to share cache with your team members and CI
|
||||
agents.
|
||||
|
||||
Another one is config-free distributed task execution (DTE). When using the distributed task execution, Nx is able to
|
||||
run any task graph on a many agents instead of locally.
|
||||
|
||||
When using this, `nx affected --build`, won't run the build locally (which for large workspace can take hours). Instead,
|
||||
it will send the Task Graph to Nx Cloud. Nx Cloud Agents will then pick up the task they can run and execute them.
|
||||
|
||||
Note this happens transparently. If an agent builds `app1`, it will fetch the outputs for `lib` if it doesn't have it
|
||||
already.
|
||||
|
||||
As agents complete tasks, the main job where you invoked `nx affected --build` will start receiving created files and
|
||||
terminal outputs.
|
||||
|
||||
After `nx affected --build` completes, the machine will have the build files and all the terminal outputs as if it ran
|
||||
it locally.
|
||||
|
||||

|
||||
|
||||
## In summary
|
||||
|
||||
- Nx is able to analyze your source code to create a Project Graph.
|
||||
- Nx can use the project graph and information about projects’ targets to create a Task Graph.
|
||||
- Nx is able to perform code-change analysis to create the smallest task graph for your PR.
|
||||
- Nx supports computation caching to never execute the same computation twice. This computation cache is pluggable and can be distributed.
|
||||
- Nx supports computation caching to never execute the same computation twice. This computation cache is pluggable and
|
||||
can be distributed.
|
||||
|
||||
## Learn more:
|
||||
|
||||
|
||||
BIN
docs/shared/mental-model/dte.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
@ -3,14 +3,10 @@ import { useRouter } from 'next/router';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import Head from 'next/head';
|
||||
import {
|
||||
Footer,
|
||||
Header,
|
||||
InlineCommand,
|
||||
NxUsersShowcase,
|
||||
} from '@nrwl/nx-dev/ui/common';
|
||||
import { Footer, Header, NxUsersShowcase } from '@nrwl/nx-dev/ui/common';
|
||||
import { sendCustomEvent } from '@nrwl/nx-dev/feature-analytics';
|
||||
import { useStorage } from '@nrwl/nx-dev/feature-storage';
|
||||
import { InlineCommand } from '@nrwl/nx-dev/ui-commands';
|
||||
|
||||
export function AngularPage() {
|
||||
const router = useRouter();
|
||||
|
||||
@ -2,15 +2,11 @@ import React from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import {
|
||||
Footer,
|
||||
Header,
|
||||
InlineCommand,
|
||||
NxUsersShowcase,
|
||||
} from '@nrwl/nx-dev/ui/common';
|
||||
import { Footer, Header, NxUsersShowcase } from '@nrwl/nx-dev/ui/common';
|
||||
import { sendCustomEvent } from '@nrwl/nx-dev/feature-analytics';
|
||||
import { useStorage } from '@nrwl/nx-dev/feature-storage';
|
||||
import Head from 'next/head';
|
||||
import { InlineCommand } from '@nrwl/nx-dev/ui-commands';
|
||||
|
||||
export function Node() {
|
||||
const sectionItemList = [
|
||||
|
||||
@ -3,14 +3,10 @@ import { useRouter } from 'next/router';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import Head from 'next/head';
|
||||
import {
|
||||
Footer,
|
||||
Header,
|
||||
InlineCommand,
|
||||
NxUsersShowcase,
|
||||
} from '@nrwl/nx-dev/ui/common';
|
||||
import { Footer, Header, NxUsersShowcase } from '@nrwl/nx-dev/ui/common';
|
||||
import { sendCustomEvent } from '@nrwl/nx-dev/feature-analytics';
|
||||
import { useStorage } from '@nrwl/nx-dev/feature-storage';
|
||||
import { InlineCommand } from '@nrwl/nx-dev/ui-commands';
|
||||
|
||||
export function ReactPage() {
|
||||
const router = useRouter();
|
||||
|
||||
@ -1,14 +1,20 @@
|
||||
# Mental Model
|
||||
|
||||
Nx is a VSCode of build tools, with a powerful core, driven by metadata, and extensible through plugins. Nx works with a few concepts to drive your monorepo efficiently, and effectively. This guide covers the mental model around how Nx works with project graphs, task graphs, affected commands, computation hashing and caching.
|
||||
Nx is a VSCode of build tools, with a powerful core, driven by metadata, and extensible through plugins. Nx works with a
|
||||
few concepts to drive your monorepo efficiently, and effectively. This guide covers the mental model around how Nx works
|
||||
with project graphs, task graphs, affected commands, computation hashing and caching.
|
||||
|
||||
## The project graph
|
||||
|
||||
A project graph is used to reflect the source code in your repository and all the external dependencies that aren’t authored in your repository, such as Webpack, React, Angular, and so forth.
|
||||
A project graph is used to reflect the source code in your repository and all the external dependencies that aren’t
|
||||
authored in your repository, such as Webpack, React, Angular, and so forth.
|
||||
|
||||

|
||||
|
||||
With Nx, nodes in the project graph are defined in `workspace.json`. You can manually define dependencies between the nodes, but you don’t have to do it very often. Nx analyzes files’ source code, your installed dependencies, TypeScript files, and others figuring out these dependencies for you. Nx also stores the cached project graph, so it only reanalyzes the files you have changed.
|
||||
With Nx, nodes in the project graph are defined in `workspace.json`. You can manually define dependencies between the
|
||||
nodes, but you don’t have to do it very often. Nx analyzes files’ source code, your installed dependencies, TypeScript
|
||||
files, and others figuring out these dependencies for you. Nx also stores the cached project graph, so it only
|
||||
reanalyzes the files you have changed.
|
||||
|
||||

|
||||
|
||||
@ -16,7 +22,8 @@ Nx provides an updated graph after each analysis is done.
|
||||
|
||||
## Metadata-driven
|
||||
|
||||
Everything in Nx comes with metadata to enable toolability. The default values, validations, autocompletion work, and more are all defined in a schema, instead of in code.
|
||||
Everything in Nx comes with metadata to enable toolability. The default values, validations, autocompletion work, and
|
||||
more are all defined in a schema, instead of in code.
|
||||
|
||||
The following sample schema shows inputs, prompts, and validations for adding a new application.
|
||||
|
||||
@ -52,7 +59,10 @@ The following sample schema shows inputs, prompts, and validations for adding a
|
||||
"message": "Which stylesheet format would you like to use?",
|
||||
"type": "list",
|
||||
"items": [
|
||||
{ "value": "css", "label": "CSS" },
|
||||
{
|
||||
"value": "css",
|
||||
"label": "CSS"
|
||||
},
|
||||
{
|
||||
"value": "scss",
|
||||
"label": "SASS(.scss) [ http://sass-lang.com ]"
|
||||
@ -116,7 +126,8 @@ The following sample schema shows inputs, prompts, and validations for adding a
|
||||
}
|
||||
```
|
||||
|
||||
This metadata is used by Nx itself, by VSCode and WebStorm integrations, by GitHub integration, and by third-party tools.
|
||||
This metadata is used by Nx itself, by VSCode and WebStorm integrations, by GitHub integration, and by third-party
|
||||
tools.
|
||||
|
||||

|
||||
|
||||
@ -124,7 +135,8 @@ These tools are able to implement richer experiences with Nx using this metadata
|
||||
|
||||
## The task graph
|
||||
|
||||
Nx uses the project graph to create a task graph. Any time you run anything, Nx creates a task graph from the project graph and then executes the tasks in that graph.
|
||||
Nx uses the project graph to create a task graph. Any time you run anything, Nx creates a task graph from the project
|
||||
graph and then executes the tasks in that graph.
|
||||
|
||||
For instance `nx test lib` creates a task graph with a single node:
|
||||
|
||||
@ -132,11 +144,14 @@ For instance `nx test lib` creates a task graph with a single node:
|
||||
|
||||
A task is an invocation of a target. If you invoke the same target twice, you create two tasks.
|
||||
|
||||
Nx uses the [project graph](#the-project-graph), but the task graph and project graph aren’t isomorphic, meaning they aren’t directly connected. In the case above, app1 and app2 depend on lib, but running `nx run-many --target=test --projects=app1,app2,lib`, the created task graph will look like this:
|
||||
Nx uses the [project graph](#the-project-graph), but the task graph and project graph aren’t isomorphic, meaning they
|
||||
aren’t directly connected. In the case above, app1 and app2 depend on lib, but
|
||||
running `nx run-many --target=test --projects=app1,app2,lib`, the created task graph will look like this:
|
||||
|
||||

|
||||
|
||||
Even though the apps depend on lib, testing `app1` doesn’t depend on the testing lib. This means that the two tasks can run in parallel.
|
||||
Even though the apps depend on lib, testing `app1` doesn’t depend on the testing lib. This means that the two tasks can
|
||||
run in parallel.
|
||||
|
||||
Let’s look at the test target relying on its dependencies.
|
||||
|
||||
@ -145,7 +160,12 @@ Let’s look at the test target relying on its dependencies.
|
||||
"test": {
|
||||
"executor": "@nrwl/jest:jest",
|
||||
"outputs": ["coverage/apps/app1"],
|
||||
"dependsOn": [{ "target": "test", "projects": "dependencies" }],
|
||||
"dependsOn": [
|
||||
{
|
||||
"target": "test",
|
||||
"projects": "dependencies"
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"jestConfig": "apps/app1/jest.config.js",
|
||||
"passWithNoTests": true
|
||||
@ -158,35 +178,46 @@ With this, running the same test command creates the following task graph:
|
||||
|
||||

|
||||
|
||||
This often makes more sense for builds, where to build app1, you want to build lib first. You can also define similar relationships between targets of the same project, including a test target that depends on the build.
|
||||
This often makes more sense for builds, where to build app1, you want to build lib first. You can also define similar
|
||||
relationships between targets of the same project, including a test target that depends on the build.
|
||||
|
||||
A task graph can contain different targets, and those can run in parallel. For instance, as Nx is building `app2`, it can be testing `app1` at the same time. Learn more about configuring targets in the [configuration guide](/{{framework}}/core-concepts/configuration)
|
||||
A task graph can contain different targets, and those can run in parallel. For instance, as Nx is building `app2`, it
|
||||
can be testing `app1` at the same time. Learn more about configuring targets in
|
||||
the [configuration guide](/{{framework}}/core-concepts/configuration)
|
||||
|
||||

|
||||
|
||||
Nx also runs the tasks in the task graph in the right order. Nx executing tasks being executed speeds up your overall execution time.
|
||||
Nx also runs the tasks in the task graph in the right order. Nx executing tasks being executed speeds up your overall
|
||||
execution time.
|
||||
|
||||
## Affected commands
|
||||
|
||||
When you run `nx test app1`, you are telling Nx to run the app1:test task plus all the tasks it depends on.
|
||||
|
||||
When you run `nx run-many --target=test --projects=app1,lib`, you are telling Nx to do the same for two tasks app1:test and lib:test.
|
||||
When you run `nx run-many --target=test --projects=app1,lib`, you are telling Nx to do the same for two tasks app1:test
|
||||
and lib:test.
|
||||
|
||||
When you run `nx run-many --target=test --all`, you are telling Nx to do this for all the projects.
|
||||
|
||||
As your workspace grows, retesting all projects becomes too slow. To address this Nx implements code change analysis to get the min set of projects that need to be retested. How does it work?
|
||||
As your workspace grows, retesting all projects becomes too slow. To address this Nx implements code change analysis to
|
||||
get the min set of projects that need to be retested. How does it work?
|
||||
|
||||
When you run `nx affected --target=test`, Nx looks at the files you changed in your PR, it will look at the nature of change (what exactly did you update in those files), and it uses this to figure the list of projects in the workspace that can be affected by this change. It then runs the `run-many` command with that list.
|
||||
When you run `nx affected --target=test`, Nx looks at the files you changed in your PR, it will look at the nature of
|
||||
change (what exactly did you update in those files), and it uses this to figure the list of projects in the workspace
|
||||
that can be affected by this change. It then runs the `run-many` command with that list.
|
||||
|
||||
For instance, if my PR changes `lib`, and I then run `nx affected --target=test`, Nx figures out that `app1` and `app2` depend on `lib`, so it will invoke `nx run-many --target=test --projects=app1,app2,lib`.
|
||||
For instance, if my PR changes `lib`, and I then run `nx affected --target=test`, Nx figures out that `app1` and `app2`
|
||||
depend on `lib`, so it will invoke `nx run-many --target=test --projects=app1,app2,lib`.
|
||||
|
||||

|
||||
|
||||
Nx analyzes the nature of the changes. For example, if you change the version of Next.js in the package.json, Nx knows that `app2` cannot be affected by it, so it only retests `app1`.
|
||||
Nx analyzes the nature of the changes. For example, if you change the version of Next.js in the package.json, Nx knows
|
||||
that `app2` cannot be affected by it, so it only retests `app1`.
|
||||
|
||||
## Computation hashing and caching
|
||||
|
||||
Nx runs the tasks in the task graph in the right order. Before running the task, Nx computes its computation hash. As long as the computation hash is the same, the output of running the task is the same.
|
||||
Nx runs the tasks in the task graph in the right order. Before running the task, Nx computes its computation hash. As
|
||||
long as the computation hash is the same, the output of running the task is the same.
|
||||
|
||||
How does Nx do it?
|
||||
|
||||
@ -200,36 +231,70 @@ By default, the computation hash for say `nx test app1` includes:
|
||||
|
||||

|
||||
|
||||
This behavior is customizable. For instance, lint checks may only depend on the source code of the project and global configs. Builds can depend on the dts files of the compiled libs instead of their source.
|
||||
This behavior is customizable. For instance, lint checks may only depend on the source code of the project and global
|
||||
configs. Builds can depend on the dts files of the compiled libs instead of their source.
|
||||
|
||||
After Nx computes the hash for a task, it then checks if it ran this exact computation before. First, it checks locally, and then if it is missing, and if a remote cache is configured, it checks remotely.
|
||||
After Nx computes the hash for a task, it then checks if it ran this exact computation before. First, it checks locally,
|
||||
and then if it is missing, and if a remote cache is configured, it checks remotely.
|
||||
|
||||
If Nx finds the computation, Nx retrieves it and replay it. Nx places the right files in the right folders and prints the terminal output. So from the user’s point of view, the command ran the same, just a lot faster.
|
||||
If Nx finds the computation, Nx retrieves it and replay it. Nx places the right files in the right folders and prints
|
||||
the terminal output. So from the user’s point of view, the command ran the same, just a lot faster.
|
||||
|
||||

|
||||
|
||||
If Nx doesn’t find this computation, Nx runs the task, and after it completes, it takes the outputs and the terminal output and stores it locally (and if configured remotely). All of this happens transparently, so you don’t have to worry about it.
|
||||
If Nx doesn’t find this computation, Nx runs the task, and after it completes, it takes the outputs and the terminal
|
||||
output and stores it locally (and if configured remotely). All of this happens transparently, so you don’t have to worry
|
||||
about it.
|
||||
|
||||
Although conceptually this is fairly straightforward, Nx optimizes this to make this experience good for you. For instance, Nx:
|
||||
Although conceptually this is fairly straightforward, Nx optimizes this to make this experience good for you. For
|
||||
instance, Nx:
|
||||
|
||||
- Captures stdout and stderr to make sure the replayed output looks the same, including on Windows.
|
||||
- Minimizes the IO by remembering what files are replayed where.
|
||||
- Only shows relevant output when processing a large task graph.
|
||||
- Provides affordances for troubleshooting cache misses.
|
||||
And many other optimizations.
|
||||
- Provides affordances for troubleshooting cache misses. And many other optimizations.
|
||||
|
||||
As your workspace grows, the task graph looks more like this:
|
||||
|
||||

|
||||
|
||||
All of these optimizations are crucial for making Nx usable for any non-trivial workspace. Only the minimum amount of work happens. The rest is either left as is or restored from the cache.
|
||||
All of these optimizations are crucial for making Nx usable for any non-trivial workspace. Only the minimum amount of
|
||||
work happens. The rest is either left as is or restored from the cache.
|
||||
|
||||
In summary:
|
||||
## Distributed task execution
|
||||
|
||||
Nx supports running commands across multiple machines. You can either set it up by hand (
|
||||
see [here](/ci/distributed-builds)) or use Nx
|
||||
CLoud. [Read the comparison of the two approaches.](https://blog.nrwl.io/distributing-ci-binning-and-distributed-task-execution-632fe31a8953?source=friends_link&sk=5120b7ff982730854ed22becfe7a640a)
|
||||
|
||||
Nx Cloud is a cloud companion for Nx (which is free and MIT-licensed). Most features of Nx Cloud are free, but some are
|
||||
paid. One of them is the distributed computation cache, which allows you to share cache with your team members and CI
|
||||
agents.
|
||||
|
||||
Another one is config-free distributed task execution (DTE). When using the distributed task execution, Nx is able to
|
||||
run any task graph on a many agents instead of locally.
|
||||
|
||||
When using this, `nx affected --build`, won't run the build locally (which for large workspace can take hours). Instead,
|
||||
it will send the Task Graph to Nx Cloud. Nx Cloud Agents will then pick up the task they can run and execute them.
|
||||
|
||||
Note this happens transparently. If an agent builds `app1`, it will fetch the outputs for `lib` if it doesn't have it
|
||||
already.
|
||||
|
||||
As agents complete tasks, the main job where you invoked `nx affected --build` will start receiving created files and
|
||||
terminal outputs.
|
||||
|
||||
After `nx affected --build` completes, the machine will have the build files and all the terminal outputs as if it ran
|
||||
it locally.
|
||||
|
||||

|
||||
|
||||
## In summary
|
||||
|
||||
- Nx is able to analyze your source code to create a Project Graph.
|
||||
- Nx can use the project graph and information about projects’ targets to create a Task Graph.
|
||||
- Nx is able to perform code-change analysis to create the smallest task graph for your PR.
|
||||
- Nx supports computation caching to never execute the same computation twice. This computation cache is pluggable and can be distributed.
|
||||
- Nx supports computation caching to never execute the same computation twice. This computation cache is pluggable and
|
||||
can be distributed.
|
||||
|
||||
## Learn more:
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 31 KiB |
14
nx-dev/nx-dev/public/images/background/hero-bg-large-2.svg
Normal file
@ -0,0 +1,14 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
style="margin:auto;background:transparent;display:block;z-index:1;position:relative" width="1832" height="561"
|
||||
preserveAspectRatio="xMidYMid" viewBox="0 0 1832 561">
|
||||
<g transform="translate(916,280.5) scale(1,1) translate(-916,-280.5)"><linearGradient id="lg-0.528164912376315" x1="0" x2="1" y1="0" y2="0">
|
||||
<stop stop-color="#143157" offset="0"></stop>
|
||||
<stop stop-color="#47bc99" offset="1"></stop>
|
||||
</linearGradient><path d="" fill="url(#lg-0.528164912376315)" opacity="0.8">
|
||||
<animate attributeName="d" dur="100s" repeatCount="indefinite" keyTimes="0;0.333;0.667;1" calcmod="spline" keySplines="0.2 0 0.2 1;0.2 0 0.2 1;0.2 0 0.2 1" begin="0s" values="M0 0M 0 432.9996746566259Q 130.85714285714286 397.2067357007969 261.7142857142857 395.173318618411T 523.4285714285714 390.7645077574754T 785.1428571428571 378.3791066893883T 1046.857142857143 360.84302102906196T 1308.5714285714287 367.4929808801331T 1570.2857142857142 333.5380500888636T 1832 339.8146572257562L 1832 214.57124841444804Q 1701.142857142857 189.42735437228626 1570.2857142857142 183.35178023766852T 1308.5714285714287 187.0414237465033T 1046.857142857143 195.04086028107434T 785.1428571428571 192.1037448846938T 523.4285714285714 149.46963901669247T 261.7142857142857 140.45701242290562T 0 144.38270544545014Z;M0 0M 0 429.2348705511414Q 130.85714285714286 436.124711502668 261.7142857142857 433.22031983070013T 523.4285714285714 381.97742517964866T 785.1428571428571 364.8580207638289T 1046.857142857143 369.13842634676956T 1308.5714285714287 381.1363433613364T 1570.2857142857142 341.60776835670697T 1832 355.579215341957L 1832 219.63519882598638Q 1701.142857142857 226.063481712133 1570.2857142857142 220.6515542803069T 1308.5714285714287 195.57365760523913T 1046.857142857143 204.1531694286217T 785.1428571428571 176.9360554201261T 523.4285714285714 178.2047094027357T 261.7142857142857 138.78977155613063T 0 161.987021263053Z;M0 0M 0 402.2420673524864Q 130.85714285714286 409.02476005216073 261.7142857142857 404.6551076076222T 523.4285714285714 392.66782142129676T 785.1428571428571 398.16651065310566T 1046.857142857143 356.40488028449005T 1308.5714285714287 351.2298203027453T 1570.2857142857142 362.8845450388782T 1832 367.06643178047784L 1832 209.93017572658937Q 1701.142857142857 198.18974434393766 1570.2857142857142 188.52940726555036T 1308.5714285714287 191.76191567180462T 1046.857142857143 188.41609139293539T 785.1428571428571 161.0221775715417T 523.4285714285714 139.57921075552485T 261.7142857142857 153.84884553166927T 0 151.6697107683906Z;M0 0M 0 432.9996746566259Q 130.85714285714286 397.2067357007969 261.7142857142857 395.173318618411T 523.4285714285714 390.7645077574754T 785.1428571428571 378.3791066893883T 1046.857142857143 360.84302102906196T 1308.5714285714287 367.4929808801331T 1570.2857142857142 333.5380500888636T 1832 339.8146572257562L 1832 214.57124841444804Q 1701.142857142857 189.42735437228626 1570.2857142857142 183.35178023766852T 1308.5714285714287 187.0414237465033T 1046.857142857143 195.04086028107434T 785.1428571428571 192.1037448846938T 523.4285714285714 149.46963901669247T 261.7142857142857 140.45701242290562T 0 144.38270544545014Z"></animate>
|
||||
</path><path d="" fill="url(#lg-0.528164912376315)" opacity="0.8">
|
||||
<animate attributeName="d" dur="100s" repeatCount="indefinite" keyTimes="0;0.333;0.667;1" calcmod="spline" keySplines="0.2 0 0.2 1;0.2 0 0.2 1;0.2 0 0.2 1" begin="-33.333333333333336s" values="M0 0M 0 428.80237628317263Q 130.85714285714286 439.3251226172385 261.7142857142857 437.12723033373123T 523.4285714285714 399.9787548849892T 785.1428571428571 410.96925486984424T 1046.857142857143 361.0686975406831T 1308.5714285714287 345.5207047461948T 1570.2857142857142 376.19697345845873T 1832 329.52126679831207L 1832 215.3506112412552Q 1701.142857142857 187.091237981758 1570.2857142857142 184.6850979747796T 1308.5714285714287 186.2754997164372T 1046.857142857143 169.59616905200156T 785.1428571428571 185.3806133291849T 523.4285714285714 170.06789336077557T 261.7142857142857 168.36959866651478T 0 132.36348465842514Z;M0 0M 0 399.4166187079941Q 130.85714285714286 401.25194616257556 261.7142857142857 393.18264311372127T 523.4285714285714 415.16240347709794T 785.1428571428571 385.39370846523195T 1046.857142857143 381.7341567045573T 1308.5714285714287 368.8653553134472T 1570.2857142857142 368.40421190094355T 1832 352.6401628181238L 1832 218.86781139264158Q 1701.142857142857 228.5625761587542 1570.2857142857142 222.8490923507087T 1308.5714285714287 168.97068773283522T 1046.857142857143 161.23711605526182T 785.1428571428571 156.4827424955311T 523.4285714285714 137.11461167133606T 261.7142857142857 139.1464466498793T 0 154.60574463707803Z;M0 0M 0 423.3710239572292Q 130.85714285714286 402.1489963518153 261.7142857142857 395.0470504705449T 523.4285714285714 424.3263864102355T 785.1428571428571 398.6270248245237T 1046.857142857143 402.93475235752334T 1308.5714285714287 343.5110333713713T 1570.2857142857142 338.968793205178T 1832 329.7046000746595L 1832 211.47239317464357Q 1701.142857142857 212.0941925316165 1570.2857142857142 210.6671293686635T 1308.5714285714287 216.20253114044075T 1046.857142857143 205.48973436562605T 785.1428571428571 159.37590957795243T 523.4285714285714 152.3139843731376T 261.7142857142857 148.37188410396783T 0 141.8289200339807Z;M0 0M 0 428.80237628317263Q 130.85714285714286 439.3251226172385 261.7142857142857 437.12723033373123T 523.4285714285714 399.9787548849892T 785.1428571428571 410.96925486984424T 1046.857142857143 361.0686975406831T 1308.5714285714287 345.5207047461948T 1570.2857142857142 376.19697345845873T 1832 329.52126679831207L 1832 215.3506112412552Q 1701.142857142857 187.091237981758 1570.2857142857142 184.6850979747796T 1308.5714285714287 186.2754997164372T 1046.857142857143 169.59616905200156T 785.1428571428571 185.3806133291849T 523.4285714285714 170.06789336077557T 261.7142857142857 168.36959866651478T 0 132.36348465842514Z"></animate>
|
||||
</path><path d="" fill="url(#lg-0.528164912376315)" opacity="0.8">
|
||||
<animate attributeName="d" dur="100s" repeatCount="indefinite" keyTimes="0;0.333;0.667;1" calcmod="spline" keySplines="0.2 0 0.2 1;0.2 0 0.2 1;0.2 0 0.2 1" begin="-66.66666666666667s" values="M0 0M 0 440.46705128089224Q 130.85714285714286 396.2838511545641 261.7142857142857 388.1219815464019T 523.4285714285714 399.1647612981167T 785.1428571428571 397.46734721231365T 1046.857142857143 373.11461412117086T 1308.5714285714287 380.1572479533137T 1570.2857142857142 340.9689149616171T 1832 355.96951739963185L 1832 210.7663280390093Q 1701.142857142857 229.18154706517117 1570.2857142857142 228.36962302863165T 1308.5714285714287 172.1412404998527T 1046.857142857143 207.0397618969865T 785.1428571428571 190.3265933037408T 523.4285714285714 147.8780633392022T 261.7142857142857 167.47640070939275T 0 119.65810795084623Z;M0 0M 0 399.1529847030912Q 130.85714285714286 428.49636332639375 261.7142857142857 423.00244680582193T 523.4285714285714 421.4020996826405T 785.1428571428571 404.9938971664101T 1046.857142857143 369.7900032851582T 1308.5714285714287 379.54256432122054T 1570.2857142857142 379.50745221656257T 1832 326.1251109871048L 1832 218.81615223768026Q 1701.142857142857 184.48977099606734 1570.2857142857142 179.77639619152325T 1308.5714285714287 184.0490946806665T 1046.857142857143 195.30240657109684T 785.1428571428571 154.39102164820144T 523.4285714285714 152.97130840108275T 261.7142857142857 156.55439770727588T 0 114.00174745953093Z;M0 0M 0 413.2337963141122Q 130.85714285714286 415.4776891549644 261.7142857142857 413.7406822636123T 523.4285714285714 379.37278015728947T 785.1428571428571 375.92172065443617T 1046.857142857143 397.40543623917944T 1308.5714285714287 358.90233730195035T 1570.2857142857142 365.26548721054985T 1832 346.4998580162213L 1832 202.10148475578868Q 1701.142857142857 211.0845319543284 1570.2857142857142 210.08062413929792T 1308.5714285714287 206.29948635745382T 1046.857142857143 192.7719902951013T 785.1428571428571 161.9339577853944T 523.4285714285714 163.3561027449572T 261.7142857142857 160.70488818550444T 0 145.8023454143502Z;M0 0M 0 440.46705128089224Q 130.85714285714286 396.2838511545641 261.7142857142857 388.1219815464019T 523.4285714285714 399.1647612981167T 785.1428571428571 397.46734721231365T 1046.857142857143 373.11461412117086T 1308.5714285714287 380.1572479533137T 1570.2857142857142 340.9689149616171T 1832 355.96951739963185L 1832 210.7663280390093Q 1701.142857142857 229.18154706517117 1570.2857142857142 228.36962302863165T 1308.5714285714287 172.1412404998527T 1046.857142857143 207.0397618969865T 785.1428571428571 190.3265933037408T 523.4285714285714 147.8780633392022T 261.7142857142857 167.47640070939275T 0 119.65810795084623Z"></animate>
|
||||
</path></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.6 KiB |
14
nx-dev/nx-dev/public/images/background/hero-bg-large-3.svg
Normal file
@ -0,0 +1,14 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
style="margin:auto;background:transparent;display:block;z-index:1;position:relative" width="1832" height="561"
|
||||
preserveAspectRatio="xMidYMid" viewBox="0 0 1832 561">
|
||||
<g transform="translate(916,280.5) scale(-1,1) translate(-916,-280.5)"><linearGradient id="lg-0.297187046438917" x1="0" x2="1" y1="0" y2="0">
|
||||
<stop stop-color="#143157" offset="0"></stop>
|
||||
<stop stop-color="#8154e8" offset="1"></stop>
|
||||
</linearGradient><path d="" fill="url(#lg-0.297187046438917)" opacity="0.8">
|
||||
<animate attributeName="d" dur="100s" repeatCount="indefinite" keyTimes="0;0.333;0.667;1" calcmod="spline" keySplines="0.2 0 0.2 1;0.2 0 0.2 1;0.2 0 0.2 1" begin="0s" values="M0 0M 0 444.9535928221149Q 130.85714285714286 415.6139908102967 261.7142857142857 411.48348296696395T 523.4285714285714 397.87584797529956T 785.1428571428571 399.4117660254747T 1046.857142857143 386.36594505910193T 1308.5714285714287 380.91254256213574T 1570.2857142857142 342.85062032621124T 1832 346.86249108929235L 1832 234.20215425097223Q 1701.142857142857 207.5704063856184 1570.2857142857142 205.84697138788746T 1308.5714285714287 185.22644856964803T 1046.857142857143 159.3236875686275T 785.1428571428571 157.09152114158098T 523.4285714285714 167.19354323705016T 261.7142857142857 150.0336029629138T 0 114.18603150842667Z;M0 0M 0 433.31408805238294Q 130.85714285714286 419.8458054070206 261.7142857142857 414.7932512391911T 523.4285714285714 411.02709583473273T 785.1428571428571 409.5719186406739T 1046.857142857143 371.29382208843634T 1308.5714285714287 381.56510600748595T 1570.2857142857142 334.5199005638777T 1832 335.905799991303L 1832 222.0024354894402Q 1701.142857142857 218.3639674601821 1570.2857142857142 213.682536091545T 1308.5714285714287 168.939277864601T 1046.857142857143 157.63766483972643T 785.1428571428571 165.5604240095318T 523.4285714285714 181.13828813390393T 261.7142857142857 123.59959305145127T 0 155.81750179965724Z;M0 0M 0 408.45688469860704Q 130.85714285714286 397.2221964214714 261.7142857142857 390.3755346345357T 523.4285714285714 395.0680260702676T 785.1428571428571 408.86568033757067T 1046.857142857143 394.2897006213841T 1308.5714285714287 389.5785283088386T 1570.2857142857142 341.8357917681043T 1832 329.8651278097975L 1832 228.69074839805728Q 1701.142857142857 215.16370366603172 1570.2857142857142 205.77398335507138T 1308.5714285714287 174.17849629877452T 1046.857142857143 182.11553149332784T 785.1428571428571 194.71830083625483T 523.4285714285714 177.20731162199044T 261.7142857142857 158.8503205437118T 0 113.34112088557161Z;M0 0M 0 444.9535928221149Q 130.85714285714286 415.6139908102967 261.7142857142857 411.48348296696395T 523.4285714285714 397.87584797529956T 785.1428571428571 399.4117660254747T 1046.857142857143 386.36594505910193T 1308.5714285714287 380.91254256213574T 1570.2857142857142 342.85062032621124T 1832 346.86249108929235L 1832 234.20215425097223Q 1701.142857142857 207.5704063856184 1570.2857142857142 205.84697138788746T 1308.5714285714287 185.22644856964803T 1046.857142857143 159.3236875686275T 785.1428571428571 157.09152114158098T 523.4285714285714 167.19354323705016T 261.7142857142857 150.0336029629138T 0 114.18603150842667Z"></animate>
|
||||
</path><path d="" fill="url(#lg-0.297187046438917)" opacity="0.8">
|
||||
<animate attributeName="d" dur="100s" repeatCount="indefinite" keyTimes="0;0.333;0.667;1" calcmod="spline" keySplines="0.2 0 0.2 1;0.2 0 0.2 1;0.2 0 0.2 1" begin="-33.333333333333336s" values="M0 0M 0 406.2534267893012Q 130.85714285714286 428.19078456040586 261.7142857142857 419.3687577028348T 523.4285714285714 418.3684756416337T 785.1428571428571 382.6717725882118T 1046.857142857143 376.9348849735424T 1308.5714285714287 379.15753299419225T 1570.2857142857142 379.6888568506997T 1832 331.1669528001735L 1832 201.82347046579508Q 1701.142857142857 236.90908000280564 1570.2857142857142 227.79232350245744T 1308.5714285714287 186.00622249738768T 1046.857142857143 181.48803243112656T 785.1428571428571 185.62176737441177T 523.4285714285714 143.1250997922817T 261.7142857142857 138.25541164766167T 0 150.18973821976363Z;M0 0M 0 437.84908049085186Q 130.85714285714286 405.08061961262064 261.7142857142857 397.7572978428973T 523.4285714285714 399.41928357777107T 785.1428571428571 369.5951811298659T 1046.857142857143 378.42879670436105T 1308.5714285714287 360.9174758964918T 1570.2857142857142 356.5072606379753T 1832 328.9629729017643L 1832 204.64891301593372Q 1701.142857142857 221.22975115083858 1570.2857142857142 220.13839659414754T 1308.5714285714287 191.83535826208717T 1046.857142857143 174.59959796724704T 785.1428571428571 147.562783681762T 523.4285714285714 145.2871888861977T 261.7142857142857 130.00683093097803T 0 130.09379371247127Z;M0 0M 0 433.0324359562456Q 130.85714285714286 408.3488699344921 261.7142857142857 402.5499048019126T 523.4285714285714 404.6576104825942T 785.1428571428571 370.8182034370839T 1046.857142857143 359.3163759392481T 1308.5714285714287 345.50958645863255T 1570.2857142857142 371.92240545863194T 1832 335.63504295679695L 1832 209.25140478830843Q 1701.142857142857 217.54277274377858 1570.2857142857142 214.20804456618734T 1308.5714285714287 195.2497599714813T 1046.857142857143 200.42978618369523T 785.1428571428571 160.72074792554503T 523.4285714285714 135.89954866760726T 261.7142857142857 162.3907114330085T 0 149.16450505462342Z;M0 0M 0 406.2534267893012Q 130.85714285714286 428.19078456040586 261.7142857142857 419.3687577028348T 523.4285714285714 418.3684756416337T 785.1428571428571 382.6717725882118T 1046.857142857143 376.9348849735424T 1308.5714285714287 379.15753299419225T 1570.2857142857142 379.6888568506997T 1832 331.1669528001735L 1832 201.82347046579508Q 1701.142857142857 236.90908000280564 1570.2857142857142 227.79232350245744T 1308.5714285714287 186.00622249738768T 1046.857142857143 181.48803243112656T 785.1428571428571 185.62176737441177T 523.4285714285714 143.1250997922817T 261.7142857142857 138.25541164766167T 0 150.18973821976363Z"></animate>
|
||||
</path><path d="" fill="url(#lg-0.297187046438917)" opacity="0.8">
|
||||
<animate attributeName="d" dur="100s" repeatCount="indefinite" keyTimes="0;0.333;0.667;1" calcmod="spline" keySplines="0.2 0 0.2 1;0.2 0 0.2 1;0.2 0 0.2 1" begin="-66.66666666666667s" values="M0 0M 0 438.18103148067496Q 130.85714285714286 427.1569475736252 261.7142857142857 421.4892265225297T 523.4285714285714 385.8167543540844T 785.1428571428571 383.50562945378636T 1046.857142857143 377.2958060996686T 1308.5714285714287 390.3791667497189T 1570.2857142857142 363.88285401882854T 1832 351.4245258630772L 1832 222.29837545621803Q 1701.142857142857 197.68152926012792 1570.2857142857142 191.82433975616505T 1308.5714285714287 202.20201100931928T 1046.857142857143 164.735529086756T 785.1428571428571 163.63534910833314T 523.4285714285714 180.51553275469672T 261.7142857142857 138.49354270310806T 0 155.91987403262175Z;M0 0M 0 405.1479286101409Q 130.85714285714286 410.9791585370133 261.7142857142857 402.8006064426083T 523.4285714285714 401.0947337139699T 785.1428571428571 386.2568290226825T 1046.857142857143 386.9347046189968T 1308.5714285714287 348.9733843940245T 1570.2857142857142 374.10337366489955T 1832 358.8974237262071L 1832 198.93175682195513Q 1701.142857142857 231.08917029775935 1570.2857142857142 228.7051371258751T 1308.5714285714287 184.14716405321093T 1046.857142857143 179.89132031023254T 785.1428571428571 152.5071041415685T 523.4285714285714 170.2988942492526T 261.7142857142857 166.90054172899784T 0 130.58535744887058Z;M0 0M 0 435.7792754954172Q 130.85714285714286 412.59212369055905 261.7142857142857 407.1900252143601T 523.4285714285714 397.40974023860633T 785.1428571428571 394.732023811615T 1046.857142857143 400.02819284320145T 1308.5714285714287 371.8018211979163T 1570.2857142857142 369.6266159097247T 1832 357.63233788548615L 1832 238.63172510779253Q 1701.142857142857 231.07054794591406 1570.2857142857142 228.82583633206778T 1308.5714285714287 191.0523440578789T 1046.857142857143 177.49502047305262T 785.1428571428571 170.73011520593963T 523.4285714285714 169.4495689032402T 261.7142857142857 166.8735976762278T 0 118.18587543558353Z;M0 0M 0 438.18103148067496Q 130.85714285714286 427.1569475736252 261.7142857142857 421.4892265225297T 523.4285714285714 385.8167543540844T 785.1428571428571 383.50562945378636T 1046.857142857143 377.2958060996686T 1308.5714285714287 390.3791667497189T 1570.2857142857142 363.88285401882854T 1832 351.4245258630772L 1832 222.29837545621803Q 1701.142857142857 197.68152926012792 1570.2857142857142 191.82433975616505T 1308.5714285714287 202.20201100931928T 1046.857142857143 164.735529086756T 785.1428571428571 163.63534910833314T 523.4285714285714 180.51553275469672T 261.7142857142857 138.49354270310806T 0 155.91987403262175Z"></animate>
|
||||
</path></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.6 KiB |
@ -1,4 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin:auto;background:transparent;display:block;z-index:1;position:relative" width="2480" height="841" preserveAspectRatio="xMidYMid" viewBox="0 0 2480 841">
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
style="margin:auto;background:transparent;display:block;z-index:1;position:relative" width="2480" height="841"
|
||||
preserveAspectRatio="xMidYMid" viewBox="0 0 2480 841">
|
||||
<g transform="translate(1240,420.5) scale(1,1) translate(-1240,-420.5)"><linearGradient id="lg-0.2519962050414528" x1="0" x2="1" y1="0" y2="0">
|
||||
<stop stop-color="#8154e8" offset="0"></stop>
|
||||
<stop stop-color="#47bc99" offset="1"></stop>
|
||||
|
||||
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
@ -1,4 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin:auto;background:transparent;display:block;z-index:1;position:relative" width="1000" height="456" preserveAspectRatio="xMidYMid" viewBox="0 0 1000 456">
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
style="margin:auto;background:transparent;display:block;z-index:1;position:relative" width="1000" height="456"
|
||||
preserveAspectRatio="xMidYMid" viewBox="0 0 1000 456">
|
||||
<g transform="translate(500,228) scale(1,1) translate(-500,-228)"><linearGradient id="lg-0.592943636771361" x1="0" x2="1" y1="0" y2="0">
|
||||
<stop stop-color="#8154e8" offset="0"></stop>
|
||||
<stop stop-color="#47bc99" offset="1"></stop>
|
||||
|
||||
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.6 KiB |
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="858px" height="384px" viewBox="0 0 858 384" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<svg width="858px" height="384px" viewBox="0 0 858 384" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Generator: Sketch 57.1 (83088) - https://sketch.com -->
|
||||
<title>Brainly - Logo</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
@ -10,8 +10,9 @@
|
||||
<!ENTITY ns_custom "http://ns.adobe.com/GenericCustomNamespace/1.0/">
|
||||
<!ENTITY ns_adobe_xpath "http://ns.adobe.com/XPath/1.0/">
|
||||
]>
|
||||
<svg version="1.1" xmlns:x="&ns_extend;" xmlns:i="&ns_ai;" xmlns:graph="&ns_graphs;"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 643.9 186.48"
|
||||
<svg version="1.1" xmlns:i="&ns_ai;"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 643.9 186.48"
|
||||
style="enable-background:new 0 0 643.9 186.48;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
|
||||
|
Before Width: | Height: | Size: 393 KiB After Width: | Height: | Size: 393 KiB |
@ -1,6 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 1600 547" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<svg width="100%" height="100%" viewBox="0 0 1600 547" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||
xml:space="preserve"
|
||||
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(19.3222,0,0,19.3222,12.912,5.31857)">
|
||||
<path d="M78.1,16.555C77.717,17.585 76.76,18.157 75.58,18.157C75.561,18.157 75.542,18.158 75.524,18.158C73.782,18.158 72.35,16.725 72.35,14.983C72.35,13.242 73.782,11.81 75.524,11.81L75.58,11.81C76.76,11.81 77.687,12.314 78.1,13.413L81.337,13.413C80.801,10.597 78.459,8.789 75.579,8.789C75.542,8.788 75.505,8.788 75.468,8.788C72.069,8.788 69.272,11.585 69.272,14.984C69.272,18.383 72.069,21.18 75.468,21.18C75.505,21.18 75.542,21.18 75.579,21.179C78.459,21.179 80.948,19.156 81.337,16.555L78.1,16.555ZM64.767,9.1L68.138,9.1L68.138,20.96L64.768,20.96L64.768,9.1L64.767,9.1ZM68.477,6.234L68.477,6.279C68.477,7.395 67.559,8.314 66.443,8.314C65.326,8.314 64.408,7.395 64.408,6.279L64.408,6.234C64.408,5.118 65.327,4.199 66.443,4.199C67.559,4.199 68.478,5.118 68.478,6.234L68.477,6.234ZM55.112,10.552C55.678,9.532 56.962,8.835 58.812,8.835C61.802,8.835 63.385,10.738 63.385,13.563L63.385,20.959L60.015,20.959L60.015,13.916C60.015,12.533 59.398,11.581 57.908,11.581C56.274,11.581 55.369,12.582 55.369,14.161L55.369,20.949L52,20.949L52,9.099L55.113,9.099L55.113,10.552L55.112,10.552Z" style="fill:white;fill-rule:nonzero;"/>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
|
||||
viewBox="0 0 1000 723.6" style="enable-background:new 0 0 1000 723.6;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:url(#SVGID_1_);}
|
||||
|
||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
BIN
nx-dev/nx-dev/public/images/github-app.webp
Normal file
|
After Width: | Height: | Size: 116 KiB |
1
nx-dev/nx-dev/public/images/lerna-logo.svg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
nx-dev/nx-dev/public/images/nrwlio-channel.webp
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
nx-dev/nx-dev/public/images/nx-affected-dep-graph.webp
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
nx-dev/nx-dev/public/images/nx-affected.webp
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
nx-dev/nx-dev/public/images/nx-cloud.webp
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
nx-dev/nx-dev/public/images/nx-console.webp
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
nx-dev/nx-dev/public/images/nx-dep-graph.webp
Normal file
|
After Width: | Height: | Size: 255 KiB |
BIN
nx-dev/nx-dev/public/images/nx-egghead-course.webp
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
nx-dev/nx-dev/public/images/nx-playbook.webp
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
nx-dev/nx-dev/public/videos/nx-dep-graph.mp4
Normal file
BIN
nx-dev/nx-dev/public/videos/nx-dep-graph.webm
Normal file
@ -1,10 +1,11 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import { mockAllIsIntersecting } from 'react-intersection-observer/test-utils';
|
||||
import Index from '../pages/index';
|
||||
|
||||
describe('Index', () => {
|
||||
it('should render successfully', () => {
|
||||
mockAllIsIntersecting(true);
|
||||
const { baseElement } = render(<Index />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
|
||||
@ -123,3 +123,25 @@ iframe[src*='youtube'] {
|
||||
background-size: cover !important;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sponsor carousel
|
||||
*/
|
||||
#sponsors-carousel {
|
||||
animation: scroll 80s linear infinite;
|
||||
width: calc(192px * 18);
|
||||
}
|
||||
#sponsors-carousel div {
|
||||
margin: 0 24px;
|
||||
min-width: 144px;
|
||||
width: 144px;
|
||||
}
|
||||
|
||||
@keyframes scroll {
|
||||
0% {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
100% {
|
||||
transform: translate3d(calc(-192px * 18), 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,6 +19,9 @@ module.exports = {
|
||||
green: {
|
||||
'nx-base': 'hsla(162, 47%, 50%, 1)',
|
||||
},
|
||||
purple: {
|
||||
'nx-base': 'hsla(258, 76%, 62%, 1)',
|
||||
},
|
||||
},
|
||||
typography: {
|
||||
DEFAULT: {
|
||||
@ -43,5 +46,9 @@ module.exports = {
|
||||
variants: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [require('@tailwindcss/typography')],
|
||||
plugins: [
|
||||
require('@tailwindcss/aspect-ratio'),
|
||||
require('@tailwindcss/typography'),
|
||||
require('@tailwindcss/forms'),
|
||||
],
|
||||
};
|
||||
|
||||
12
nx-dev/ui-commands/.babelrc
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@nrwl/react/babel",
|
||||
{
|
||||
"runtime": "automatic",
|
||||
"useBuiltIns": "usage"
|
||||
}
|
||||
]
|
||||
],
|
||||
"plugins": []
|
||||
}
|
||||
18
nx-dev/ui-commands/.eslintrc.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
7
nx-dev/ui-commands/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# nx-dev-ui-commands
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `nx test nx-dev-ui-commands` to execute the unit tests via [Jest](https://jestjs.io).
|
||||
9
nx-dev/ui-commands/jest.config.js
Normal file
@ -0,0 +1,9 @@
|
||||
module.exports = {
|
||||
displayName: 'nx-dev-ui-commands',
|
||||
preset: '../../jest.preset.js',
|
||||
transform: {
|
||||
'^.+\\.[tj]sx?$': 'babel-jest',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||
coverageDirectory: '../../coverage//nx-dev/ui-commands',
|
||||
};
|
||||
23
nx-dev/ui-commands/project.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"root": "nx-dev/ui-commands",
|
||||
"sourceRoot": "nx-dev/ui-commands/src",
|
||||
"projectType": "library",
|
||||
"tags": ["scope:nx-dev", "type:ui"],
|
||||
"targets": {
|
||||
"lint": {
|
||||
"executor": "@nrwl/linter:eslint",
|
||||
"outputs": ["{options.outputFile}"],
|
||||
"options": {
|
||||
"lintFilePatterns": ["nx-dev/ui-commands/**/*.{ts,tsx,js,jsx}"]
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/jest:jest",
|
||||
"outputs": ["coverage/nx-dev/ui-commands"],
|
||||
"options": {
|
||||
"jestConfig": "nx-dev/ui-commands/jest.config.js",
|
||||
"passWithNoTests": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1
nx-dev/ui-commands/src/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './lib/inline-command';
|
||||
@ -37,9 +37,9 @@ export function InlineCommand({
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className="sm:max-w-full w-full text-sm flex-none bg-white text-gray-400 hover:text-gray-900 font-input-mono leading-6 py-1 sm:px-3 border border-blue-nx-dark rounded-md flex items-center justify-center space-x-2 sm:space-x-4 focus:ring-2 focus:ring-offset-2 focus:ring-offset-white focus:ring-gray-300 focus:outline-none transition-colors duration-180"
|
||||
className="sm:max-w-full w-full text-sm flex-none bg-white text-gray-400 hover:text-gray-800 font-input-mono leading-6 py-1 sm:px-3 border border-gray-300 rounded-md flex items-center justify-center space-x-2 sm:space-x-4 focus:ring-2 focus:ring-offset-2 focus:ring-offset-white focus:ring-gray-300 focus:outline-none transition-colors duration-180"
|
||||
>
|
||||
<span className="overflow-auto flex items-center text-gray-900">
|
||||
<span className="overflow-auto flex items-center text-gray-800">
|
||||
<span className="hidden sm:inline text-gray-500" aria-hidden="true">
|
||||
$
|
||||
</span>
|
||||
23
nx-dev/ui-commands/tsconfig.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"allowJs": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
13
nx-dev/ui-commands/tsconfig.lib.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"types": ["node"]
|
||||
},
|
||||
"files": [
|
||||
"../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
|
||||
"../../node_modules/@nrwl/react/typings/image.d.ts"
|
||||
],
|
||||
"exclude": ["**/*.spec.ts", "**/*.spec.tsx"],
|
||||
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
|
||||
}
|
||||
15
nx-dev/ui-commands/tsconfig.spec.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"types": ["jest", "node"]
|
||||
},
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.spec.tsx",
|
||||
"**/*.spec.js",
|
||||
"**/*.spec.jsx",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
||||
12
nx-dev/ui-home/.babelrc
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@nrwl/react/babel",
|
||||
{
|
||||
"runtime": "automatic",
|
||||
"useBuiltIns": "usage"
|
||||
}
|
||||
]
|
||||
],
|
||||
"plugins": []
|
||||
}
|
||||
18
nx-dev/ui-home/.eslintrc.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
7
nx-dev/ui-home/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# nx-dev-ui-home
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `nx test nx-dev-ui-home` to execute the unit tests via [Jest](https://jestjs.io).
|
||||
9
nx-dev/ui-home/jest.config.js
Normal file
@ -0,0 +1,9 @@
|
||||
module.exports = {
|
||||
displayName: 'nx-dev-ui-home',
|
||||
preset: '../../jest.preset.js',
|
||||
transform: {
|
||||
'^.+\\.[tj]sx?$': 'babel-jest',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||
coverageDirectory: '../../coverage//nx-dev/ui-home',
|
||||
};
|
||||
23
nx-dev/ui-home/project.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"root": "nx-dev/ui-home",
|
||||
"sourceRoot": "nx-dev/ui-home/src",
|
||||
"projectType": "library",
|
||||
"tags": ["scope:nx-dev", "type:ui"],
|
||||
"targets": {
|
||||
"lint": {
|
||||
"executor": "@nrwl/linter:eslint",
|
||||
"outputs": ["{options.outputFile}"],
|
||||
"options": {
|
||||
"lintFilePatterns": ["nx-dev/ui-home/**/*.{ts,tsx,js,jsx}"]
|
||||
}
|
||||
},
|
||||
"xtest": {
|
||||
"executor": "@nrwl/jest:jest",
|
||||
"outputs": ["coverage/nx-dev/ui-home"],
|
||||
"options": {
|
||||
"jestConfig": "nx-dev/ui-home/jest.config.js",
|
||||
"passWithNoTests": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
14
nx-dev/ui-home/src/index.ts
Normal file
@ -0,0 +1,14 @@
|
||||
export * from './lib/affected-command';
|
||||
export * from './lib/cloud-support';
|
||||
export * from './lib/dependency-graph';
|
||||
export * from './lib/ecosystem-features';
|
||||
export * from './lib/egghead-courses';
|
||||
export * from './lib/experience-features';
|
||||
export * from './lib/getting-started';
|
||||
export * from './lib/monorepo-features';
|
||||
export * from './lib/nx-playbook';
|
||||
export * from './lib/open-platform';
|
||||
export * from './lib/open-source-projects';
|
||||
export * from './lib/performance';
|
||||
export * from './lib/vscode-plugin';
|
||||
export * from './lib/youtube-channel';
|
||||
11
nx-dev/ui-home/src/lib/affected-command.spec.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { mockAllIsIntersecting } from 'react-intersection-observer/test-utils';
|
||||
import AffectedCommand from './affected-command';
|
||||
|
||||
describe('AffectedCommand', () => {
|
||||
it('should render successfully', () => {
|
||||
mockAllIsIntersecting(true);
|
||||
const { baseElement } = render(<AffectedCommand />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
159
nx-dev/ui-home/src/lib/affected-command.tsx
Normal file
@ -0,0 +1,159 @@
|
||||
import React, { ReactComponentElement, useEffect } from 'react';
|
||||
import Link from 'next/link';
|
||||
import Image from 'next/image';
|
||||
import { motion, useAnimation } from 'framer-motion';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
|
||||
export function AffectedCommand(): ReactComponentElement<any> {
|
||||
const opacityTranslateXVariant = {
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
x: -46,
|
||||
},
|
||||
visible: (delay: number = 0) => ({
|
||||
opacity: 1,
|
||||
x: 0,
|
||||
transition: { delay, duration: 0.32 },
|
||||
}),
|
||||
};
|
||||
const opacityVariant = {
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
},
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: { duration: 0.32, ease: 'easeOut' },
|
||||
},
|
||||
};
|
||||
const controls = useAnimation();
|
||||
const [ref, inView] = useInView({ threshold: 0.5, triggerOnce: true });
|
||||
|
||||
useEffect(() => {
|
||||
if (!inView) return;
|
||||
controls.start('visible');
|
||||
}, [controls, inView]);
|
||||
|
||||
return (
|
||||
<div id="nx-affected" className="mt-16 md:mt-32">
|
||||
<motion.div
|
||||
ref={ref}
|
||||
animate={controls}
|
||||
initial="hidden"
|
||||
variants={{
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
when: 'beforeChildren',
|
||||
staggerChildren: 0.12,
|
||||
ease: 'linear',
|
||||
duration: 0.24,
|
||||
type: 'tween',
|
||||
},
|
||||
},
|
||||
}}
|
||||
className="lg:mx-auto lg:max-w-7xl lg:px-8 lg:grid lg:grid-cols-2 lg:grid-flow-col-dense lg:gap-24"
|
||||
>
|
||||
<div className="px-4 max-w-xl mx-auto sm:px-6 lg:py-32 lg:max-w-none lg:mx-0 lg:px-0 lg:col-start-2">
|
||||
<div>
|
||||
<div className="mt-6">
|
||||
<motion.h2
|
||||
variants={opacityVariant}
|
||||
className="text-3xl font-extrabold tracking-tight text-gray-900"
|
||||
>
|
||||
Build and Test Only What is Affected
|
||||
</motion.h2>
|
||||
<motion.p
|
||||
variants={opacityVariant}
|
||||
className="mt-4 text-lg text-gray-500"
|
||||
>
|
||||
Nx is smart. It analyzes your workspace and figures out what can
|
||||
be affected by every code change. That's why Nx doesn't rebuild
|
||||
and retest everything on every commit - it only rebuilds what is
|
||||
necessary.
|
||||
</motion.p>
|
||||
<motion.div variants={opacityVariant} className="mt-6">
|
||||
<Link href="/core-extended/affected">
|
||||
<a className="inline-flex px-4 py-2 border border-transparent text-base font-medium rounded-md shadow-sm text-white bg-blue-nx-base hover:bg-blue-nx-dark transition">
|
||||
Learn about "nx affected"
|
||||
</a>
|
||||
</Link>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-12 sm:mt-16 lg:mt-0 lg:col-start-1">
|
||||
<div className="relative px-4 sm:pr-6 md:-ml-16 lg:px-0 lg:m-0 lg:relative lg:h-full">
|
||||
<motion.div
|
||||
variants={opacityTranslateXVariant}
|
||||
className="-mt-8 w-full max-w-screen-sm rounded-xl shadow-xl border border-gray-300 lg:absolute lg:right-0 lg:h-full lg:w-auto lg:max-w-none overflow-hidden"
|
||||
>
|
||||
<Image
|
||||
src="/images/nx-affected.webp"
|
||||
alt="Nx affected dep-graph"
|
||||
layout={'fixed'}
|
||||
width={727}
|
||||
height={482}
|
||||
/>
|
||||
</motion.div>
|
||||
<motion.div
|
||||
variants={opacityTranslateXVariant}
|
||||
custom={0.25}
|
||||
className="hidden md:flex absolute -bottom-8 right-8 bg-gray-500 rounded-xl shadow-xl"
|
||||
>
|
||||
<div
|
||||
className="coding inverse-toggle px-5 pt-4 shadow-lg text-gray-200 text-xs font-mono subpixel-antialiased
|
||||
bg-gray-800 pb-6 pt-4 rounded-lg leading-normal overflow-hidden"
|
||||
>
|
||||
<div className="top mb-2 flex">
|
||||
<div className="h-3 w-3 bg-red-500 rounded-full" />
|
||||
<div className="ml-2 h-3 w-3 bg-yellow-300 rounded-full" />
|
||||
<div className="ml-2 h-3 w-3 bg-green-500 rounded-full" />
|
||||
</div>
|
||||
<div className="mt-4 flex">
|
||||
<span className="text-green-400">/workspace ➜</span>
|
||||
<p className="flex-1 typing items-center pl-2">
|
||||
nx affected:test --parallel
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-2 flex">
|
||||
<p className="flex-1 typing items-center pl-2">
|
||||
<span className="text-green-400">{'>'}</span>{' '}
|
||||
<span className="px-1 py-0.5 bg-blue-nx-base">NX</span>
|
||||
<span className="ml-1 px-1 py-0.5 bg-yellow-500">
|
||||
NOTE
|
||||
</span>{' '}
|
||||
Affected criteria defaulted to --base=master --head=HEAD
|
||||
<br />
|
||||
<br />
|
||||
<span className="text-green-400">{'>'}</span>{' '}
|
||||
<span className="px-1 py-0.5 bg-blue-nx-base mr-1">NX</span>{' '}
|
||||
Running target test for 3 project(s):
|
||||
<br />
|
||||
- nx-dev <br />
|
||||
- nx-dev-ui-common <br />- nx-dev-feature-doc-viewer
|
||||
<br />
|
||||
———————————————————————————————————————————————
|
||||
<br />
|
||||
<span className="text-green-400">{'>'}</span> nx run
|
||||
nx-dev:test RUNS nx-dev
|
||||
<br />
|
||||
<span className="px-1 py-0.5 bg-green-nx-base">
|
||||
RUNS
|
||||
</span>{' '}
|
||||
<span className="px-1 py-0.5 bg-gray-200 text-gray-700">
|
||||
nx-dev
|
||||
</span>{' '}
|
||||
nx-dev/nx-dev/specs/index.spec.tsx
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AffectedCommand;
|
||||
11
nx-dev/ui-home/src/lib/cloud-support.spec.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import CloudSupport from './cloud-support';
|
||||
import { mockAllIsIntersecting } from 'react-intersection-observer/test-utils';
|
||||
|
||||
describe('CloudSupport', () => {
|
||||
it('should render successfully', () => {
|
||||
mockAllIsIntersecting(true);
|
||||
// const { baseElement } = render(<CloudSupport />);
|
||||
// expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
118
nx-dev/ui-home/src/lib/cloud-support.tsx
Normal file
@ -0,0 +1,118 @@
|
||||
import React, { ReactComponentElement, useEffect } from 'react';
|
||||
import Link from 'next/link';
|
||||
import Image from 'next/image';
|
||||
import { motion, useAnimation } from 'framer-motion';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
|
||||
export function CloudSupport(): ReactComponentElement<any> {
|
||||
const opacityTranslateXVariant = {
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
x: 46,
|
||||
},
|
||||
visible: (delay: number = 0) => ({
|
||||
opacity: 1,
|
||||
x: 0,
|
||||
transition: { delay, duration: 0.32 },
|
||||
}),
|
||||
};
|
||||
const opacityVariant = {
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
},
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: { duration: 0.32, ease: 'easeOut' },
|
||||
},
|
||||
};
|
||||
const controls = useAnimation();
|
||||
const [ref, inView] = useInView({ threshold: 0.5, triggerOnce: true });
|
||||
|
||||
useEffect(() => {
|
||||
if (!inView) return;
|
||||
controls.start('visible');
|
||||
}, [controls, inView]);
|
||||
|
||||
return (
|
||||
<div id="next-gen-cloud-support" className="mt-16 md:mt-32">
|
||||
<motion.div
|
||||
ref={ref}
|
||||
animate={controls}
|
||||
initial="hidden"
|
||||
variants={{
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
when: 'beforeChildren',
|
||||
staggerChildren: 0.12,
|
||||
ease: 'linear',
|
||||
duration: 0.24,
|
||||
type: 'tween',
|
||||
},
|
||||
},
|
||||
}}
|
||||
className="lg:mx-auto lg:max-w-7xl lg:px-8 lg:grid lg:grid-cols-2 lg:grid-flow-col-dense lg:gap-24"
|
||||
>
|
||||
<div className="px-4 max-w-xl mx-auto sm:px-6 lg:py-32 lg:max-w-none lg:mx-0 lg:px-0 lg:col-start-1">
|
||||
<div>
|
||||
<div className="mt-6">
|
||||
<motion.h2
|
||||
variants={opacityVariant}
|
||||
className="text-3xl font-extrabold tracking-tight text-gray-900"
|
||||
>
|
||||
Next Gen Cloud Support
|
||||
</motion.h2>
|
||||
<motion.p
|
||||
variants={opacityVariant}
|
||||
className="mt-4 text-lg text-gray-500"
|
||||
>
|
||||
Share links with your teammates where everyone working on a
|
||||
project can examine detailed build logs and get insights about
|
||||
how to improve your project and build.
|
||||
</motion.p>
|
||||
<motion.div variants={opacityVariant} className="mt-6">
|
||||
<Link href="https://nx.app">
|
||||
<a className="inline-flex px-4 py-2 border border-transparent text-base font-medium rounded-md shadow-sm text-white bg-blue-nx-base hover:bg-blue-nx-dark transition">
|
||||
Enable Nx Cloud
|
||||
</a>
|
||||
</Link>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-12 sm:mt-16 lg:mt-0 lg:col-start-2">
|
||||
<div className="relative px-4 sm:pr-6 lg:px-0 lg:h-full">
|
||||
<motion.div
|
||||
variants={opacityTranslateXVariant}
|
||||
className="w-full mx-auto max-w-screen-sm rounded-xl shadow-xl border border-gray-300 lg:absolute lg:left-16 lg:-top-28 lg:h-full lg:w-auto lg:max-w-none overflow-hidden"
|
||||
>
|
||||
<Image
|
||||
src="/images/nx-cloud.webp"
|
||||
alt="Nx Cloud app"
|
||||
layout={'fixed'}
|
||||
width={718}
|
||||
height={510}
|
||||
/>
|
||||
</motion.div>
|
||||
<motion.div
|
||||
variants={opacityTranslateXVariant}
|
||||
custom={0.25}
|
||||
className="w-full mx-auto max-w-screen-sm hidden lg:flex rounded-xl shadow-xl border border-gray-300 lg:absolute lg:-left-20 lg:-bottom-64 lg:h-full lg:w-auto lg:max-w-none overflow-hidden"
|
||||
>
|
||||
<Image
|
||||
src="/images/github-app.webp"
|
||||
alt="Nx Cloud Github app"
|
||||
layout={'fixed'}
|
||||
width={715}
|
||||
height={510}
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default CloudSupport;
|
||||
11
nx-dev/ui-home/src/lib/dependency-graph.spec.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { mockAllIsIntersecting } from 'react-intersection-observer/test-utils';
|
||||
import DependencyGraph from './dependency-graph';
|
||||
|
||||
describe('DependencyGraph', () => {
|
||||
it('should render successfully', () => {
|
||||
mockAllIsIntersecting(true);
|
||||
const { baseElement } = render(<DependencyGraph />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
104
nx-dev/ui-home/src/lib/dependency-graph.tsx
Normal file
@ -0,0 +1,104 @@
|
||||
import React, { ReactComponentElement, useEffect } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { motion, useAnimation } from 'framer-motion';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
|
||||
export function DependencyGraph(): ReactComponentElement<any> {
|
||||
const opacityTranslateXVariant = {
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
x: 46,
|
||||
},
|
||||
visible: (delay: number = 0) => ({
|
||||
opacity: 1,
|
||||
x: 0,
|
||||
transition: { delay, duration: 0.32 },
|
||||
}),
|
||||
};
|
||||
const opacityVariant = {
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
},
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: { duration: 0.32, ease: 'easeOut' },
|
||||
},
|
||||
};
|
||||
const controls = useAnimation();
|
||||
const [ref, inView] = useInView({ threshold: 0.5, triggerOnce: true });
|
||||
|
||||
useEffect(() => {
|
||||
if (!inView) return;
|
||||
controls.start('visible');
|
||||
}, [controls, inView]);
|
||||
|
||||
return (
|
||||
<div id="dependency-graph" className="mt-16 md:mt-32">
|
||||
<motion.div
|
||||
ref={ref}
|
||||
animate={controls}
|
||||
initial="hidden"
|
||||
variants={{
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
when: 'beforeChildren',
|
||||
staggerChildren: 0.12,
|
||||
ease: 'linear',
|
||||
duration: 0.24,
|
||||
type: 'tween',
|
||||
},
|
||||
},
|
||||
}}
|
||||
className="lg:mx-auto lg:max-w-7xl lg:px-8 lg:grid lg:grid-cols-2 lg:grid-flow-col-dense lg:gap-24"
|
||||
>
|
||||
<div className="px-4 max-w-xl mx-auto sm:px-6 lg:py-32 lg:max-w-none lg:mx-0 lg:px-0 lg:col-start-1">
|
||||
<div>
|
||||
<div className="mt-6">
|
||||
<motion.h2
|
||||
variants={opacityVariant}
|
||||
className="text-3xl font-extrabold tracking-tight text-gray-900"
|
||||
>
|
||||
Explore Visually
|
||||
</motion.h2>
|
||||
<motion.p
|
||||
variants={opacityVariant}
|
||||
className="mt-4 text-lg text-gray-500"
|
||||
>
|
||||
Nx comes with an interactive dependency diagram to help explore
|
||||
and understand your workspace.
|
||||
</motion.p>
|
||||
<motion.div variants={opacityVariant} className="mt-6">
|
||||
<Link href="/structure/dependency-graph">
|
||||
<a className="inline-flex px-4 py-2 border border-transparent text-base font-medium rounded-md shadow-sm text-white bg-blue-nx-base hover:bg-blue-nx-dark transition">
|
||||
Learn about "nx dep-graph"
|
||||
</a>
|
||||
</Link>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-12 sm:mt-16 lg:mt-0 lg:col-start-2">
|
||||
<motion.div
|
||||
variants={opacityTranslateXVariant}
|
||||
className="relative px-4 lg:px-0 lg:h-full"
|
||||
>
|
||||
<video
|
||||
className="-mt-8 mx-auto w-full max-w-screen-sm rounded-xl shadow-xl border border-gray-300 lg:absolute lg:left-16 lg:h-full lg:w-auto lg:max-w-none"
|
||||
autoPlay={true}
|
||||
loop
|
||||
muted
|
||||
playsInline={true}
|
||||
>
|
||||
<source src="/videos/nx-dep-graph.webm" type="video/webm" />
|
||||
<source src="/videos/nx-dep-graph.mp4" type="video/mp4" />
|
||||
</video>
|
||||
</motion.div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default DependencyGraph;
|
||||
11
nx-dev/ui-home/src/lib/ecosystem-features.spec.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { mockAllIsIntersecting } from 'react-intersection-observer/test-utils';
|
||||
import ExperienceFeatures from './experience-features';
|
||||
|
||||
describe('ExperienceFeatures', () => {
|
||||
it('should render successfully', () => {
|
||||
mockAllIsIntersecting(true);
|
||||
const { baseElement } = render(<ExperienceFeatures />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
261
nx-dev/ui-home/src/lib/ecosystem-features.tsx
Normal file
@ -0,0 +1,261 @@
|
||||
import React, { ReactComponentElement, useEffect } from 'react';
|
||||
import Link from 'next/link';
|
||||
import cx from 'classnames';
|
||||
import { motion, useAnimation } from 'framer-motion';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
|
||||
const featureItems: {
|
||||
classNames: string;
|
||||
link: string;
|
||||
subTitle: string;
|
||||
svg: ReactComponentElement<any>;
|
||||
title: string;
|
||||
}[] = [
|
||||
{
|
||||
classNames: 'bg-green-nx-base',
|
||||
link: '/core-concepts/nx-devkit',
|
||||
title: 'Plugins for everything',
|
||||
subTitle:
|
||||
'React, React Native, Angular, NativeScript, Cypress, Nest.js, Storybook, Ionic, Go among others.',
|
||||
svg: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
classNames: 'bg-pink-500',
|
||||
link: '/getting-started/nx-cli',
|
||||
title: 'Consistent DX',
|
||||
subTitle: 'Nx improves dev mobility, experimentation and collaboration.',
|
||||
svg: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
classNames: 'bg-yellow-500',
|
||||
link: '/core-concepts/updating-nx',
|
||||
title: 'Automatic upgrades.',
|
||||
subTitle:
|
||||
'Nx updates your source code to work with the newest versions of popular tools.',
|
||||
svg: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M5 3v4M3 5h4M6 17v4m-2-2h4m5-16l2.286 6.857L21 12l-5.714 2.143L13 21l-2.286-6.857L5 12l5.714-2.143L13 3z"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
classNames: 'bg-purple-nx-base',
|
||||
link: '/core-concepts/updating-nx',
|
||||
title: 'Repeatable migrations',
|
||||
subTitle: 'Nx enables large scale refactorings.',
|
||||
svg: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
classNames: 'bg-red-500',
|
||||
link: '/community',
|
||||
title: 'Large community',
|
||||
subTitle: 'A community of more than 600k developers, doubling every year.',
|
||||
svg: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
classNames: 'bg-blue-500',
|
||||
link: 'https://github.com/nrwl/nx',
|
||||
title: 'Open source',
|
||||
subTitle: 'MIT-licensed, clear roadmap and transparency.',
|
||||
svg: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M12 11c0 3.517-1.009 6.799-2.753 9.571m-3.44-2.04l.054-.09A13.916 13.916 0 008 11a4 4 0 118 0c0 1.017-.07 2.019-.203 3m-2.118 6.844A21.88 21.88 0 0015.171 17m3.839 1.132c.645-2.266.99-4.659.99-7.132A8 8 0 008 4.07M3 15.364c.64-1.319 1-2.8 1-4.364 0-1.457.39-2.823 1.07-4"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
export function EcosystemFeatures(): ReactComponentElement<any> {
|
||||
const opacityTranslateXVariant = {
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
x: 46,
|
||||
},
|
||||
visible: {
|
||||
opacity: 1,
|
||||
x: 0,
|
||||
transition: { duration: 0.32 },
|
||||
},
|
||||
};
|
||||
const opacityVariant = {
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
},
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: { duration: 0.32, ease: 'easeOut' },
|
||||
},
|
||||
};
|
||||
const controls = useAnimation();
|
||||
const [ref, inView] = useInView({ threshold: 0.5, triggerOnce: true });
|
||||
|
||||
useEffect(() => {
|
||||
if (!inView) return;
|
||||
controls.start('visible');
|
||||
}, [controls, inView]);
|
||||
|
||||
return (
|
||||
<div id="rich-plugin-ecosystem" className="relative">
|
||||
<motion.div
|
||||
ref={ref}
|
||||
animate={controls}
|
||||
initial="hidden"
|
||||
variants={{
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
when: 'beforeChildren',
|
||||
staggerChildren: 0.12,
|
||||
ease: 'linear',
|
||||
duration: 0.24,
|
||||
type: 'tween',
|
||||
},
|
||||
},
|
||||
}}
|
||||
className="lg:mx-auto lg:max-w-7xl lg:px-8 lg:grid lg:grid-cols-2 lg:grid-flow-col-dense lg:gap-24"
|
||||
>
|
||||
<div className="px-4 max-w-xl mx-auto sm:px-6 lg:py-16 lg:max-w-none lg:mx-0 lg:px-0 lg:col-start-1">
|
||||
<div>
|
||||
<div className="mt-6">
|
||||
<motion.h2
|
||||
variants={opacityVariant}
|
||||
className="text-3xl font-extrabold tracking-tight text-gray-900"
|
||||
>
|
||||
Rich Plugin Ecosystem
|
||||
</motion.h2>
|
||||
<motion.p
|
||||
variants={opacityVariant}
|
||||
className="mt-4 text-lg text-gray-500"
|
||||
>
|
||||
The core of Nx is generic, simple, and unobtrusive. Nx Plugins
|
||||
are completely optional, but they can really level up your
|
||||
productivity.
|
||||
</motion.p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="md:mt-16 lg:mt-0 lg:col-start-2">
|
||||
<div className="px-4 m-0 lg:px-0 lg:relative lg:h-full">
|
||||
<div className="h-full py-14 grid items-center grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{featureItems.map((item, index: number) => (
|
||||
<motion.div
|
||||
key={'monorepo-feature-' + index}
|
||||
variants={opacityTranslateXVariant}
|
||||
className={cx(
|
||||
'relative rounded-lg border border-gray-300 bg-white px-4 py-3 shadow-md flex items-center space-x-4 hover:bg-gray-50 transition focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-blue-nx-base',
|
||||
[2, 3].includes(index) && 'lg:left-8'
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={cx(
|
||||
'flex-shrink-0 p-2 rounded-full text-white ',
|
||||
item.classNames
|
||||
)}
|
||||
>
|
||||
{item.svg}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<Link href={item.link}>
|
||||
<a className="focus:outline-none">
|
||||
<span className="absolute inset-0" aria-hidden="true" />
|
||||
<p className="mb-0.5 text-sm font-bold text-gray-700">
|
||||
{item.title}
|
||||
</p>
|
||||
<p className="text-xs text-gray-400">{item.subTitle}</p>
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default EcosystemFeatures;
|
||||
11
nx-dev/ui-home/src/lib/egghead-courses.spec.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { mockAllIsIntersecting } from 'react-intersection-observer/test-utils';
|
||||
import EggheadCourses from './egghead-courses';
|
||||
|
||||
describe('EggheadCourses', () => {
|
||||
it('should render successfully', () => {
|
||||
mockAllIsIntersecting(true);
|
||||
const { baseElement } = render(<EggheadCourses />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
67
nx-dev/ui-home/src/lib/egghead-courses.tsx
Normal file
@ -0,0 +1,67 @@
|
||||
import React, { ReactComponentElement, useEffect } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { motion, useAnimation } from 'framer-motion';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
|
||||
export function EggheadCourses(): ReactComponentElement<any> {
|
||||
const controls = useAnimation();
|
||||
const [ref, inView] = useInView({ threshold: 0.5, triggerOnce: true });
|
||||
|
||||
useEffect(() => {
|
||||
if (!inView) return;
|
||||
controls.start('visible');
|
||||
}, [controls, inView]);
|
||||
|
||||
return (
|
||||
<div id="egghead-course" className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<motion.div
|
||||
ref={ref}
|
||||
animate={controls}
|
||||
initial="hidden"
|
||||
variants={{
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
ease: 'linear',
|
||||
duration: 0.24,
|
||||
type: 'tween',
|
||||
},
|
||||
},
|
||||
}}
|
||||
className="bg-blue-nx-base rounded-lg shadow-xl overflow-hidden lg:grid lg:grid-cols-2 lg:gap-4"
|
||||
>
|
||||
<div className="pt-10 pb-12 px-6 sm:pt-16 sm:px-16 lg:py-16 lg:pr-0 xl:py-20 xl:px-20">
|
||||
<div className="lg:self-center">
|
||||
<h2 className="text-3xl font-extrabold text-white sm:text-4xl">
|
||||
<span className="block">Scale React Development</span>
|
||||
<span className="block">with Nx</span>
|
||||
</h2>
|
||||
<p className="mt-4 text-lg leading-6 text-gray-100">
|
||||
Free course on egghead.io
|
||||
</p>
|
||||
<Link href="https://egghead.io/playlists/scale-react-development-with-nx-4038?utm_source=nx.dev">
|
||||
<a
|
||||
rel="nofollow"
|
||||
target="_blank"
|
||||
className="mt-8 bg-white border border-transparent rounded-md shadow px-5 py-3 inline-flex items-center text-base font-medium text-blue-nx-base hover:bg-gray-100"
|
||||
>
|
||||
Start learning now
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="-mt-6 aspect-w-5 aspect-h-3 md:aspect-w-2 md:aspect-h-1">
|
||||
<img
|
||||
loading="lazy"
|
||||
className="transform translate-x-6 translate-y-6 rounded-md object-cover object-left-top sm:translate-x-16 lg:translate-y-20"
|
||||
src="/images/nx-egghead-course.webp"
|
||||
alt="nx egghead course"
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default EggheadCourses;
|
||||
11
nx-dev/ui-home/src/lib/experience-features.spec.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { mockAllIsIntersecting } from 'react-intersection-observer/test-utils';
|
||||
import ExperienceFeatures from './experience-features';
|
||||
|
||||
describe('ExperienceFeatures', () => {
|
||||
it('should render successfully', () => {
|
||||
mockAllIsIntersecting(true);
|
||||
const { baseElement } = render(<ExperienceFeatures />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
256
nx-dev/ui-home/src/lib/experience-features.tsx
Normal file
@ -0,0 +1,256 @@
|
||||
import React, { ReactComponentElement, useEffect } from 'react';
|
||||
import Link from 'next/link';
|
||||
import cx from 'classnames';
|
||||
import { motion, useAnimation } from 'framer-motion';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
|
||||
const featureItems: {
|
||||
classNames: string;
|
||||
link: string;
|
||||
subTitle: string;
|
||||
svg: ReactComponentElement<any>;
|
||||
title: string;
|
||||
}[] = [
|
||||
{
|
||||
classNames: 'bg-blue-500',
|
||||
link: '/getting-started/console',
|
||||
title: 'Editor plugins',
|
||||
subTitle: 'Nx-aware autocompletion and refactoring.',
|
||||
svg: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="transparent"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path d="M17.583.063a1.5 1.5 0 00-1.032.392 1.5 1.5 0 00-.001 0A.88.88 0 0016.5.5L8.528 9.316 3.875 5.5l-.407-.35a1 1 0 00-1.024-.154 1 1 0 00-.012.005l-1.817.75a1 1 0 00-.077.036 1 1 0 00-.047.028 1 1 0 00-.038.022 1 1 0 00-.048.034 1 1 0 00-.03.024 1 1 0 00-.044.036 1 1 0 00-.036.033 1 1 0 00-.032.035 1 1 0 00-.033.038 1 1 0 00-.035.044 1 1 0 00-.024.034 1 1 0 00-.032.05 1 1 0 00-.02.035 1 1 0 00-.024.05 1 1 0 00-.02.045 1 1 0 00-.016.044 1 1 0 00-.016.047 1 1 0 00-.015.055 1 1 0 00-.01.04 1 1 0 00-.008.054 1 1 0 00-.006.05A1 1 0 000 6.668v10.666a1 1 0 00.615.917l1.817.764a1 1 0 001.035-.164l.408-.35 4.653-3.815 7.973 8.815a1.5 1.5 0 00.072.065 1.5 1.5 0 00.057.05 1.5 1.5 0 00.058.042 1.5 1.5 0 00.063.044 1.5 1.5 0 00.065.038 1.5 1.5 0 00.065.036 1.5 1.5 0 00.068.031 1.5 1.5 0 00.07.03 1.5 1.5 0 00.073.025 1.5 1.5 0 00.066.02 1.5 1.5 0 00.08.02 1.5 1.5 0 00.068.014 1.5 1.5 0 00.075.01 1.5 1.5 0 00.075.008 1.5 1.5 0 00.073.003 1.5 1.5 0 00.077 0 1.5 1.5 0 00.078-.005 1.5 1.5 0 00.067-.007 1.5 1.5 0 00.087-.015 1.5 1.5 0 00.06-.012 1.5 1.5 0 00.08-.022 1.5 1.5 0 00.068-.02 1.5 1.5 0 00.07-.028 1.5 1.5 0 00.09-.037l4.944-2.377a1.5 1.5 0 00.476-.362 1.5 1.5 0 00.09-.112 1.5 1.5 0 00.004-.007 1.5 1.5 0 00.08-.125 1.5 1.5 0 00.062-.12 1.5 1.5 0 00.009-.017 1.5 1.5 0 00.04-.108 1.5 1.5 0 00.015-.037 1.5 1.5 0 00.03-.107 1.5 1.5 0 00.009-.037 1.5 1.5 0 00.017-.1 1.5 1.5 0 00.008-.05 1.5 1.5 0 00.006-.09 1.5 1.5 0 00.004-.08V3.942a1.5 1.5 0 000-.003 1.5 1.5 0 000-.032 1.5 1.5 0 00-.01-.15 1.5 1.5 0 00-.84-1.17L18.206.21a1.5 1.5 0 00-.622-.146zM18 6.92v10.163l-6.198-5.08zM3 8.574l3.099 3.427-3.1 3.426z" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
classNames: 'bg-red-500',
|
||||
link: 'https://github.com/apps/nx-cloud',
|
||||
title: 'GitHub & CI',
|
||||
subTitle: 'Searchable and filterable CI outputs, analytics, and more.',
|
||||
svg: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
classNames: 'bg-pink-500',
|
||||
link: '/getting-started/nx-cli#modifying-code',
|
||||
title: 'Powerful code generation',
|
||||
subTitle: 'Nx automates repeatable tasks and refactorings.',
|
||||
svg: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
|
||||
/>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
classNames: 'bg-green-nx-base',
|
||||
link: '/structure/dependency-graph',
|
||||
title: 'Interactive visualizations',
|
||||
subTitle:
|
||||
'An evergreen architecture diagram to help explore and understand your workspace.',
|
||||
svg: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M15 15l-2 5L9 9l11 4-5 2zm0 0l5 5M7.188 2.239l.777 2.897M5.136 7.965l-2.898-.777M13.95 4.05l-2.122 2.122m-5.657 5.656l-2.12 2.122"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
classNames: 'bg-yellow-500',
|
||||
link: '/generators/workspace-generators',
|
||||
title: 'Workspace generators',
|
||||
subTitle: 'Nx helps enforce best practices and organizational standards.',
|
||||
svg: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
classNames: 'bg-purple-nx-base',
|
||||
link: '/core-concepts/nx-devkit',
|
||||
title: 'Nx Devkit',
|
||||
subTitle:
|
||||
'Nx enables a custom dev experience to match the needs of your organization.',
|
||||
svg: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
export function ExperienceFeatures(): ReactComponentElement<any> {
|
||||
const opacityTranslateXVariant = {
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
x: -46,
|
||||
},
|
||||
visible: {
|
||||
opacity: 1,
|
||||
x: 0,
|
||||
transition: { duration: 0.32 },
|
||||
},
|
||||
};
|
||||
const opacityVariant = {
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
},
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: { duration: 0.32, ease: 'easeOut' },
|
||||
},
|
||||
};
|
||||
const controls = useAnimation();
|
||||
const [ref, inView] = useInView({ threshold: 0.5, triggerOnce: true });
|
||||
|
||||
useEffect(() => {
|
||||
if (!inView) return;
|
||||
controls.start('visible');
|
||||
}, [controls, inView]);
|
||||
|
||||
return (
|
||||
<div id="integrated-development-experience" className="relative">
|
||||
<motion.div
|
||||
ref={ref}
|
||||
animate={controls}
|
||||
initial="hidden"
|
||||
variants={{
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
when: 'beforeChildren',
|
||||
staggerChildren: 0.12,
|
||||
ease: 'linear',
|
||||
duration: 0.24,
|
||||
type: 'tween',
|
||||
},
|
||||
},
|
||||
}}
|
||||
className="lg:mx-auto lg:max-w-7xl lg:px-8 lg:grid lg:grid-cols-2 lg:grid-flow-col-dense lg:gap-24"
|
||||
>
|
||||
<div className="px-4 max-w-xl mx-auto sm:px-6 lg:py-16 lg:max-w-none lg:mx-0 lg:px-0 lg:col-start-2">
|
||||
<div>
|
||||
<div className="mt-6">
|
||||
<motion.h2
|
||||
variants={opacityVariant}
|
||||
className="text-3xl font-extrabold tracking-tight text-gray-900"
|
||||
>
|
||||
Integrated Development Experience
|
||||
</motion.h2>
|
||||
<motion.p
|
||||
variants={opacityVariant}
|
||||
className="mt-4 text-lg text-gray-500"
|
||||
>
|
||||
Nx provides a modern integrated dev experience. It has a
|
||||
high-quality VS Code plugin, interactive visualizations, GitHub
|
||||
integration and more.
|
||||
</motion.p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="md:mt-16 lg:mt-0 lg:col-start-1">
|
||||
<div className="px-4 m-0 lg:px-0 lg:relative lg:h-full">
|
||||
<div className="h-full py-14 grid items-center grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{featureItems.map((item, index: number) => (
|
||||
<motion.div
|
||||
key={'monorepo-feature-' + index}
|
||||
variants={opacityTranslateXVariant}
|
||||
className={cx(
|
||||
'relative rounded-lg border border-gray-300 bg-white px-4 py-3 shadow-md flex items-center space-x-4 hover:bg-gray-50 transition focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-blue-nx-base',
|
||||
[2, 3].includes(index) && 'lg:left-8'
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={cx(
|
||||
'flex-shrink-0 p-2 rounded-full text-white ',
|
||||
item.classNames
|
||||
)}
|
||||
>
|
||||
{item.svg}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<Link href={item.link}>
|
||||
<a className="focus:outline-none">
|
||||
<span className="absolute inset-0" aria-hidden="true" />
|
||||
<p className="mb-0.5 text-sm font-bold text-gray-700">
|
||||
{item.title}
|
||||
</p>
|
||||
<p className="text-xs text-gray-400">{item.subTitle}</p>
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ExperienceFeatures;
|
||||
11
nx-dev/ui-home/src/lib/getting-started.spec.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { mockAllIsIntersecting } from 'react-intersection-observer/test-utils';
|
||||
import GettingStarted from './getting-started';
|
||||
|
||||
describe('GettingStarted', () => {
|
||||
it('should render successfully', () => {
|
||||
mockAllIsIntersecting(true);
|
||||
const { baseElement } = render(<GettingStarted />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
1007
nx-dev/ui-home/src/lib/getting-started.tsx
Normal file
11
nx-dev/ui-home/src/lib/monorepo-features.spec.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { mockAllIsIntersecting } from 'react-intersection-observer/test-utils';
|
||||
import MonorepoFeatures from './monorepo-features';
|
||||
|
||||
describe('MonorepoFeatures', () => {
|
||||
it('should render successfully', () => {
|
||||
mockAllIsIntersecting(true);
|
||||
const { baseElement } = render(<MonorepoFeatures />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
268
nx-dev/ui-home/src/lib/monorepo-features.tsx
Normal file
@ -0,0 +1,268 @@
|
||||
import { ReactComponentElement, useEffect } from 'react';
|
||||
import Link from 'next/link';
|
||||
import cx from 'classnames';
|
||||
import { motion, useAnimation } from 'framer-motion';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
|
||||
const featureItems: {
|
||||
classNames: string;
|
||||
link: string;
|
||||
subTitle: string;
|
||||
svg: ReactComponentElement<any>;
|
||||
title: string;
|
||||
}[] = [
|
||||
{
|
||||
classNames: 'bg-pink-500',
|
||||
link: '/core-concepts/mental-model#affected-commands',
|
||||
title: 'Smart rebuilds',
|
||||
subTitle: 'Nx only rebuilds and retests what is affected by your change.',
|
||||
svg: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
classNames: 'bg-green-nx-base',
|
||||
link: '/core-concepts/mental-model#the-project-graph',
|
||||
title: 'Project graph',
|
||||
subTitle:
|
||||
'Nx analyzes your workspace to improve performance and developer experience.',
|
||||
svg: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M6 3.5A1.5 1.5 0 0 1 7.5 2h1A1.5 1.5 0 0 1 10 3.5v1A1.5 1.5 0 0 1 8.5 6v1H14a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-1 0V8h-5v.5a.5.5 0 0 1-1 0V8h-5v.5a.5.5 0 0 1-1 0v-1A.5.5 0 0 1 2 7h5.5V6A1.5 1.5 0 0 1 6 4.5v-1zM8.5 5a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1zM0 11.5A1.5 1.5 0 0 1 1.5 10h1A1.5 1.5 0 0 1 4 11.5v1A1.5 1.5 0 0 1 2.5 14h-1A1.5 1.5 0 0 1 0 12.5v-1zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1zm4.5.5A1.5 1.5 0 0 1 7.5 10h1a1.5 1.5 0 0 1 1.5 1.5v1A1.5 1.5 0 0 1 8.5 14h-1A1.5 1.5 0 0 1 6 12.5v-1zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1zm4.5.5a1.5 1.5 0 0 1 1.5-1.5h1a1.5 1.5 0 0 1 1.5 1.5v1a1.5 1.5 0 0 1-1.5 1.5h-1a1.5 1.5 0 0 1-1.5-1.5v-1zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1z"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
classNames: 'bg-yellow-500',
|
||||
link: '/core-concepts/mental-model#distributed-task-execution',
|
||||
title: 'Distributed task execution',
|
||||
subTitle:
|
||||
'Nx distributes any command across multiple machines without any configuration.',
|
||||
svg: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
classNames: 'bg-blue-500',
|
||||
link: '/core-concepts/mental-model#computation-hashing-and-caching',
|
||||
title: 'Computation caching',
|
||||
subTitle: 'Nx never rebuilds or tests the same code twice.',
|
||||
svg: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
classNames: 'bg-purple-nx-base',
|
||||
link: '/structure/monorepo-tags',
|
||||
title: 'Easy code sharing',
|
||||
subTitle: 'Nx simplifies extracting and refactoring shared libraries.',
|
||||
svg: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
classNames: 'bg-red-500',
|
||||
link: '/structure/monorepo-tags',
|
||||
title: 'Ownership management',
|
||||
subTitle:
|
||||
'Nx statically enforces the separation of shared and app-specific code.',
|
||||
svg: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
export function MonorepoFeatures(): ReactComponentElement<any> {
|
||||
const opacityTranslateXVariant = {
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
x: 46,
|
||||
},
|
||||
visible: {
|
||||
opacity: 1,
|
||||
x: 0,
|
||||
transition: { duration: 0.32 },
|
||||
},
|
||||
};
|
||||
const opacityVariant = {
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
},
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: { duration: 0.32, ease: 'easeOut' },
|
||||
},
|
||||
};
|
||||
const controls = useAnimation();
|
||||
const [ref, inView] = useInView({ threshold: 0.5, triggerOnce: true });
|
||||
|
||||
useEffect(() => {
|
||||
if (!inView) return;
|
||||
controls.start('visible');
|
||||
}, [controls, inView]);
|
||||
|
||||
return (
|
||||
<div id="monorepo-support" className="relative">
|
||||
<motion.div
|
||||
ref={ref}
|
||||
animate={controls}
|
||||
initial="hidden"
|
||||
variants={{
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
when: 'beforeChildren',
|
||||
staggerChildren: 0.12,
|
||||
ease: 'linear',
|
||||
duration: 0.24,
|
||||
type: 'tween',
|
||||
},
|
||||
},
|
||||
}}
|
||||
className="lg:mx-auto lg:max-w-7xl lg:px-8 lg:grid lg:grid-cols-2 lg:grid-flow-col-dense lg:gap-24"
|
||||
>
|
||||
<div className="px-4 max-w-xl mx-auto sm:px-6 lg:py-16 lg:max-w-none lg:mx-0 lg:px-0">
|
||||
<div>
|
||||
<div className="mt-6">
|
||||
<motion.h2
|
||||
variants={opacityVariant}
|
||||
className="text-3xl font-extrabold tracking-tight text-gray-900"
|
||||
>
|
||||
Best-in-Class Support for Monorepos
|
||||
</motion.h2>
|
||||
<motion.p
|
||||
variants={opacityVariant}
|
||||
className="mt-4 text-lg text-gray-500"
|
||||
>
|
||||
Nx builds a project graph by analyzing your workspace, which it
|
||||
then uses to only rebuild what is necessary and to{' '}
|
||||
<strong className="font-semibold">
|
||||
never run the same computation twice
|
||||
</strong>
|
||||
. Nx also helps establish structured{' '}
|
||||
<strong className="font-semibold">code sharing</strong> and{' '}
|
||||
<strong className="font-semibold">ownership management</strong>{' '}
|
||||
to keep the workspace maintainable.
|
||||
</motion.p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mm:mt-16 lg:mt-0">
|
||||
<div className="px-4 m-0 lg:px-0 lg:relative lg:h-full">
|
||||
<div className="h-full py-14 grid items-center grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{featureItems.map((item, index: number) => (
|
||||
<motion.div
|
||||
key={'monorepo-feature-' + index}
|
||||
variants={opacityTranslateXVariant}
|
||||
className={cx(
|
||||
'relative rounded-lg border border-gray-300 bg-white px-4 py-3 shadow-md flex items-center space-x-4 hover:bg-gray-50 transition focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-blue-nx-base',
|
||||
[2, 3].includes(index) && 'lg:-left-8'
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={cx(
|
||||
'flex-shrink-0 p-2 rounded-full text-white ',
|
||||
item.classNames
|
||||
)}
|
||||
>
|
||||
{item.svg}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<Link href={item.link}>
|
||||
<a className="focus:outline-none">
|
||||
<span className="absolute inset-0" aria-hidden="true" />
|
||||
<p className="mb-0.5 text-sm font-bold text-gray-700">
|
||||
{item.title}
|
||||
</p>
|
||||
<p className="text-xs text-gray-400">{item.subTitle}</p>
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default MonorepoFeatures;
|
||||
12
nx-dev/ui-home/src/lib/nx-playbook.spec.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import NxPlaybook from './nx-playbook';
|
||||
import { mockAllIsIntersecting } from 'react-intersection-observer/test-utils';
|
||||
|
||||
describe('NxPlaybook', () => {
|
||||
it('should render successfully', () => {
|
||||
mockAllIsIntersecting(true);
|
||||
const { baseElement } = render(<NxPlaybook />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
69
nx-dev/ui-home/src/lib/nx-playbook.tsx
Normal file
@ -0,0 +1,69 @@
|
||||
import React, { ReactComponentElement, useEffect } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { motion, useAnimation } from 'framer-motion';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
|
||||
export function NxPlaybook(): ReactComponentElement<any> {
|
||||
const controls = useAnimation();
|
||||
const [ref, inView] = useInView({ threshold: 0.5, triggerOnce: true });
|
||||
|
||||
useEffect(() => {
|
||||
if (!inView) return;
|
||||
controls.start('visible');
|
||||
}, [controls, inView]);
|
||||
|
||||
return (
|
||||
<div id="nx-playbook" className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<motion.div
|
||||
ref={ref}
|
||||
animate={controls}
|
||||
initial="hidden"
|
||||
variants={{
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
ease: 'linear',
|
||||
duration: 0.24,
|
||||
type: 'tween',
|
||||
},
|
||||
},
|
||||
}}
|
||||
className="bg-blue-nx-base rounded-lg shadow-xl overflow-hidden lg:grid lg:grid-cols-2 lg:gap-4"
|
||||
>
|
||||
<div className="pt-10 pb-12 px-6 sm:pt-16 sm:px-16 lg:py-16 lg:pr-0 xl:py-20 xl:px-20">
|
||||
<div className="lg:self-center">
|
||||
<h2 className="text-3xl font-extrabold text-white sm:text-4xl">
|
||||
<span className="block">Premium courses</span>
|
||||
<span className="block">to know everything</span>
|
||||
</h2>
|
||||
<p className="mt-4 text-lg leading-6 text-gray-100">
|
||||
We recorded a complete set of courses to make sure you will be
|
||||
proficient as fast as possible. They cover all the Nx features to
|
||||
take control of your workspace.
|
||||
</p>
|
||||
<Link href="https://nxplaybook.com/?utm_source=nx.dev">
|
||||
<a
|
||||
rel="nofollow"
|
||||
target="_blank"
|
||||
className="mt-8 bg-white border border-transparent rounded-md shadow px-5 py-3 inline-flex items-center text-base font-medium text-blue-nx-base hover:bg-gray-100"
|
||||
>
|
||||
Check the courses on NxPlaybook
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="-mt-6 aspect-w-5 aspect-h-3 md:aspect-w-2 md:aspect-h-1">
|
||||
<img
|
||||
loading="lazy"
|
||||
className="transform translate-x-6 translate-y-6 rounded-md object-cover object-left-top sm:translate-x-16 lg:translate-y-20"
|
||||
src="/images/nx-playbook.webp"
|
||||
alt="nx courses on nxplaybook.com"
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default NxPlaybook;
|
||||
11
nx-dev/ui-home/src/lib/open-platform.spec.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { mockAllIsIntersecting } from 'react-intersection-observer/test-utils';
|
||||
import OpenPlatform from './open-platform';
|
||||
|
||||
describe('OpenPlatform', () => {
|
||||
it('should render successfully', () => {
|
||||
mockAllIsIntersecting(true);
|
||||
const { baseElement } = render(<OpenPlatform />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
146
nx-dev/ui-home/src/lib/open-platform.tsx
Normal file
@ -0,0 +1,146 @@
|
||||
import React, { ReactComponentElement, useEffect } from 'react';
|
||||
import { motion, useAnimation } from 'framer-motion';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
|
||||
const featureItems: ReactComponentElement<any>[] = [
|
||||
<svg
|
||||
id="typescript-logo"
|
||||
className="max-h-12 fill-current text-[#3178C6]"
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path d="M1.125 0C.502 0 0 .502 0 1.125v21.75C0 23.498.502 24 1.125 24h21.75c.623 0 1.125-.502 1.125-1.125V1.125C24 .502 23.498 0 22.875 0zm17.363 9.75c.612 0 1.154.037 1.627.111a6.38 6.38 0 0 1 1.306.34v2.458a3.95 3.95 0 0 0-.643-.361 5.093 5.093 0 0 0-.717-.26 5.453 5.453 0 0 0-1.426-.2c-.3 0-.573.028-.819.086a2.1 2.1 0 0 0-.623.242c-.17.104-.3.229-.393.374a.888.888 0 0 0-.14.49c0 .196.053.373.156.529.104.156.252.304.443.444s.423.276.696.41c.273.135.582.274.926.416.47.197.892.407 1.266.628.374.222.695.473.963.753.268.279.472.598.614.957.142.359.214.776.214 1.253 0 .657-.125 1.21-.373 1.656a3.033 3.033 0 0 1-1.012 1.085 4.38 4.38 0 0 1-1.487.596c-.566.12-1.163.18-1.79.18a9.916 9.916 0 0 1-1.84-.164 5.544 5.544 0 0 1-1.512-.493v-2.63a5.033 5.033 0 0 0 3.237 1.2c.333 0 .624-.03.872-.09.249-.06.456-.144.623-.25.166-.108.29-.234.373-.38a1.023 1.023 0 0 0-.074-1.089 2.12 2.12 0 0 0-.537-.5 5.597 5.597 0 0 0-.807-.444 27.72 27.72 0 0 0-1.007-.436c-.918-.383-1.602-.852-2.053-1.405-.45-.553-.676-1.222-.676-2.005 0-.614.123-1.141.369-1.582.246-.441.58-.804 1.004-1.089a4.494 4.494 0 0 1 1.47-.629 7.536 7.536 0 0 1 1.77-.201zm-15.113.188h9.563v2.166H9.506v9.646H6.789v-9.646H3.375z" />
|
||||
</svg>,
|
||||
<svg
|
||||
id="python-logo"
|
||||
className="max-h-12 fill-current text-yellow-500"
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path d="M14.25.18l.9.2.73.26.59.3.45.32.34.34.25.34.16.33.1.3.04.26.02.2-.01.13V8.5l-.05.63-.13.55-.21.46-.26.38-.3.31-.33.25-.35.19-.35.14-.33.1-.3.07-.26.04-.21.02H8.77l-.69.05-.59.14-.5.22-.41.27-.33.32-.27.35-.2.36-.15.37-.1.35-.07.32-.04.27-.02.21v3.06H3.17l-.21-.03-.28-.07-.32-.12-.35-.18-.36-.26-.36-.36-.35-.46-.32-.59-.28-.73-.21-.88-.14-1.05-.05-1.23.06-1.22.16-1.04.24-.87.32-.71.36-.57.4-.44.42-.33.42-.24.4-.16.36-.1.32-.05.24-.01h.16l.06.01h8.16v-.83H6.18l-.01-2.75-.02-.37.05-.34.11-.31.17-.28.25-.26.31-.23.38-.2.44-.18.51-.15.58-.12.64-.1.71-.06.77-.04.84-.02 1.27.05zm-6.3 1.98l-.23.33-.08.41.08.41.23.34.33.22.41.09.41-.09.33-.22.23-.34.08-.41-.08-.41-.23-.33-.33-.22-.41-.09-.41.09zm13.09 3.95l.28.06.32.12.35.18.36.27.36.35.35.47.32.59.28.73.21.88.14 1.04.05 1.23-.06 1.23-.16 1.04-.24.86-.32.71-.36.57-.4.45-.42.33-.42.24-.4.16-.36.09-.32.05-.24.02-.16-.01h-8.22v.82h5.84l.01 2.76.02.36-.05.34-.11.31-.17.29-.25.25-.31.24-.38.2-.44.17-.51.15-.58.13-.64.09-.71.07-.77.04-.84.01-1.27-.04-1.07-.14-.9-.2-.73-.25-.59-.3-.45-.33-.34-.34-.25-.34-.16-.33-.1-.3-.04-.25-.02-.2.01-.13v-5.34l.05-.64.13-.54.21-.46.26-.38.3-.32.33-.24.35-.2.35-.14.33-.1.3-.06.26-.04.21-.02.13-.01h5.84l.69-.05.59-.14.5-.21.41-.28.33-.32.27-.35.2-.36.15-.36.1-.35.07-.32.04-.28.02-.21V6.07h2.09l.14.01zm-6.47 14.25l-.23.33-.08.41.08.41.23.33.33.23.41.08.41-.08.33-.23.23-.33.08-.41-.08-.41-.23-.33-.33-.23-.41-.08-.41.08z" />
|
||||
</svg>,
|
||||
<svg
|
||||
id="go-logo"
|
||||
className="max-h-12 fill-current text-[#7FD5EA]"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path d="M1.811 10.231c-.047 0-.058-.023-.035-.059l.246-.315c.023-.035.081-.058.128-.058h4.172c.046 0 .058.035.035.07l-.199.303c-.023.036-.082.07-.117.07zM.047 11.306c-.047 0-.059-.023-.035-.058l.245-.316c.023-.035.082-.058.129-.058h5.328c.047 0 .07.035.058.07l-.093.28c-.012.047-.058.07-.105.07zm2.828 1.075c-.047 0-.059-.035-.035-.07l.163-.292c.023-.035.07-.07.117-.07h2.337c.047 0 .07.035.07.082l-.023.28c0 .047-.047.082-.082.082zm12.129-2.36c-.736.187-1.239.327-1.963.514-.176.046-.187.058-.34-.117-.174-.199-.303-.327-.548-.444-.737-.362-1.45-.257-2.115.175-.795.514-1.204 1.274-1.192 2.22.011.935.654 1.706 1.577 1.835.795.105 1.46-.175 1.987-.77.105-.13.198-.27.315-.434H10.47c-.245 0-.304-.152-.222-.35.152-.362.432-.97.596-1.274a.315.315 0 01.292-.187h4.253c-.023.316-.023.631-.07.947a4.983 4.983 0 01-.958 2.29c-.841 1.11-1.94 1.8-3.33 1.986-1.145.152-2.209-.07-3.143-.77-.865-.655-1.356-1.52-1.484-2.595-.152-1.274.222-2.419.993-3.424.83-1.086 1.928-1.776 3.272-2.02 1.098-.2 2.15-.07 3.096.571.62.41 1.063.97 1.356 1.648.07.105.023.164-.117.2m3.868 6.461c-1.064-.024-2.034-.328-2.852-1.029a3.665 3.665 0 01-1.262-2.255c-.21-1.32.152-2.489.947-3.529.853-1.122 1.881-1.706 3.272-1.95 1.192-.21 2.314-.095 3.33.595.923.63 1.496 1.484 1.648 2.605.198 1.578-.257 2.863-1.344 3.962-.771.783-1.718 1.273-2.805 1.495-.315.06-.63.07-.934.106zm2.78-4.72c-.011-.153-.011-.27-.034-.387-.21-1.157-1.274-1.81-2.384-1.554-1.087.245-1.788.935-2.045 2.033-.21.912.234 1.835 1.075 2.21.643.28 1.285.244 1.905-.07.923-.48 1.425-1.228 1.484-2.233z" />
|
||||
</svg>,
|
||||
<svg
|
||||
id="rust-logo"
|
||||
className="max-h-12 fill-current text-gray-800"
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path d="M23.8346 11.7033l-1.0073-.6236a13.7268 13.7268 0 00-.0283-.2936l.8656-.8069a.3483.3483 0 00-.1154-.578l-1.1066-.414a8.4958 8.4958 0 00-.087-.2856l.6904-.9587a.3462.3462 0 00-.2257-.5446l-1.1663-.1894a9.3574 9.3574 0 00-.1407-.2622l.49-1.0761a.3437.3437 0 00-.0274-.3361.3486.3486 0 00-.3006-.154l-1.1845.0416a6.7444 6.7444 0 00-.1873-.2268l.2723-1.153a.3472.3472 0 00-.417-.4172l-1.1532.2724a14.0183 14.0183 0 00-.2278-.1873l.0415-1.1845a.3442.3442 0 00-.49-.328l-1.076.491c-.0872-.0476-.1742-.0952-.2623-.1407l-.1903-1.1673A.3483.3483 0 0016.256.955l-.9597.6905a8.4867 8.4867 0 00-.2855-.086l-.414-1.1066a.3483.3483 0 00-.5781-.1154l-.8069.8666a9.2936 9.2936 0 00-.2936-.0284L12.2946.1683a.3462.3462 0 00-.5892 0l-.6236 1.0073a13.7383 13.7383 0 00-.2936.0284L9.9803.3374a.3462.3462 0 00-.578.1154l-.4141 1.1065c-.0962.0274-.1903.0567-.2855.086L7.744.955a.3483.3483 0 00-.5447.2258L7.009 2.348a9.3574 9.3574 0 00-.2622.1407l-1.0762-.491a.3462.3462 0 00-.49.328l.0416 1.1845a7.9826 7.9826 0 00-.2278.1873L3.8413 3.425a.3472.3472 0 00-.4171.4171l.2713 1.1531c-.0628.075-.1255.1509-.1863.2268l-1.1845-.0415a.3462.3462 0 00-.328.49l.491 1.0761a9.167 9.167 0 00-.1407.2622l-1.1662.1894a.3483.3483 0 00-.2258.5446l.6904.9587a13.303 13.303 0 00-.087.2855l-1.1065.414a.3483.3483 0 00-.1155.5781l.8656.807a9.2936 9.2936 0 00-.0283.2935l-1.0073.6236a.3442.3442 0 000 .5892l1.0073.6236c.008.0982.0182.1964.0283.2936l-.8656.8079a.3462.3462 0 00.1155.578l1.1065.4141c.0273.0962.0567.1914.087.2855l-.6904.9587a.3452.3452 0 00.2268.5447l1.1662.1893c.0456.088.0922.1751.1408.2622l-.491 1.0762a.3462.3462 0 00.328.49l1.1834-.0415c.0618.0769.1235.1528.1873.2277l-.2713 1.1541a.3462.3462 0 00.4171.4161l1.153-.2713c.075.0638.151.1255.2279.1863l-.0415 1.1845a.3442.3442 0 00.49.327l1.0761-.49c.087.0486.1741.0951.2622.1407l.1903 1.1662a.3483.3483 0 00.5447.2268l.9587-.6904a9.299 9.299 0 00.2855.087l.414 1.1066a.3452.3452 0 00.5781.1154l.8079-.8656c.0972.0111.1954.0203.2936.0294l.6236 1.0073a.3472.3472 0 00.5892 0l.6236-1.0073c.0982-.0091.1964-.0183.2936-.0294l.8069.8656a.3483.3483 0 00.578-.1154l.4141-1.1066a8.4626 8.4626 0 00.2855-.087l.9587.6904a.3452.3452 0 00.5447-.2268l.1903-1.1662c.088-.0456.1751-.0931.2622-.1407l1.0762.49a.3472.3472 0 00.49-.327l-.0415-1.1845a6.7267 6.7267 0 00.2267-.1863l1.1531.2713a.3472.3472 0 00.4171-.416l-.2713-1.1542c.0628-.0749.1255-.1508.1863-.2278l1.1845.0415a.3442.3442 0 00.328-.49l-.49-1.076c.0475-.0872.0951-.1742.1407-.2623l1.1662-.1893a.3483.3483 0 00.2258-.5447l-.6904-.9587.087-.2855 1.1066-.414a.3462.3462 0 00.1154-.5781l-.8656-.8079c.0101-.0972.0202-.1954.0283-.2936l1.0073-.6236a.3442.3442 0 000-.5892zm-6.7413 8.3551a.7138.7138 0 01.2986-1.396.714.714 0 11-.2997 1.396zm-.3422-2.3142a.649.649 0 00-.7715.5l-.3573 1.6685c-1.1035.501-2.3285.7795-3.6193.7795a8.7368 8.7368 0 01-3.6951-.814l-.3574-1.6684a.648.648 0 00-.7714-.499l-1.473.3158a8.7216 8.7216 0 01-.7613-.898h7.1676c.081 0 .1356-.0141.1356-.088v-2.536c0-.074-.0536-.0881-.1356-.0881h-2.0966v-1.6077h2.2677c.2065 0 1.1065.0587 1.394 1.2088.0901.3533.2875 1.5044.4232 1.8729.1346.413.6833 1.2381 1.2685 1.2381h3.5716a.7492.7492 0 00.1296-.0131 8.7874 8.7874 0 01-.8119.9526zM6.8369 20.024a.714.714 0 11-.2997-1.396.714.714 0 01.2997 1.396zM4.1177 8.9972a.7137.7137 0 11-1.304.5791.7137.7137 0 011.304-.579zm-.8352 1.9813l1.5347-.6824a.65.65 0 00.33-.8585l-.3158-.7147h1.2432v5.6025H3.5669a8.7753 8.7753 0 01-.2834-3.348zm6.7343-.5437V8.7836h2.9601c.153 0 1.0792.1772 1.0792.8697 0 .575-.7107.7815-1.2948.7815zm10.7574 1.4862c0 .2187-.008.4363-.0243.651h-.9c-.09 0-.1265.0586-.1265.1477v.413c0 .973-.5487 1.1846-1.0296 1.2382-.4576.0517-.9648-.1913-1.0275-.4717-.2704-1.5186-.7198-1.8436-1.4305-2.4034.8817-.5599 1.799-1.386 1.799-2.4915 0-1.1936-.819-1.9458-1.3769-2.3153-.7825-.5163-1.6491-.6195-1.883-.6195H5.4682a8.7651 8.7651 0 014.907-2.7699l1.0974 1.151a.648.648 0 00.9182.0213l1.227-1.1743a8.7753 8.7753 0 016.0044 4.2762l-.8403 1.8982a.652.652 0 00.33.8585l1.6178.7188c.0283.2875.0425.577.0425.8717zm-9.3006-9.5993a.7128.7128 0 11.984 1.0316.7137.7137 0 01-.984-1.0316zm8.3389 6.71a.7107.7107 0 01.9395-.3625.7137.7137 0 11-.9405.3635z" />
|
||||
</svg>,
|
||||
<svg
|
||||
id="kotlin-logo"
|
||||
className="max-h-12 fill-current text-purple-500"
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path d="M24 24H0V0h24L12 12Z" />
|
||||
</svg>,
|
||||
<svg
|
||||
id=".net-logo"
|
||||
className="max-h-12 fill-current text-gray-800"
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path d="M24 8.77h-2.468v7.565h-1.425V8.77h-2.462V7.53H24zm-6.852 7.565h-4.821V7.53h4.63v1.24h-3.205v2.494h2.953v1.234h-2.953v2.604h3.396zm-6.708 0H8.882L4.78 9.863a2.896 2.896 0 0 1-.258-.51h-.036c.032.189.048.592.048 1.21v5.772H3.157V7.53h1.659l3.965 6.32c.167.261.275.442.323.54h.024c-.04-.233-.06-.629-.06-1.185V7.529h1.372zm-8.703-.693a.868.829 0 0 1-.869.829.868.829 0 0 1-.868-.83.868.829 0 0 1 .868-.828.868.829 0 0 1 .869.829Z" />
|
||||
</svg>,
|
||||
];
|
||||
|
||||
export function OpenPlatform(): ReactComponentElement<any> {
|
||||
const opacityTranslateXVariant = {
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
x: 46,
|
||||
},
|
||||
visible: {
|
||||
opacity: 1,
|
||||
x: 0,
|
||||
transition: { duration: 0.32 },
|
||||
},
|
||||
};
|
||||
const opacityVariant = {
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
},
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: { duration: 0.32, ease: 'easeOut' },
|
||||
},
|
||||
};
|
||||
const controls = useAnimation();
|
||||
const [ref, inView] = useInView({ threshold: 0.5, triggerOnce: true });
|
||||
|
||||
useEffect(() => {
|
||||
if (!inView) return;
|
||||
controls.start('visible');
|
||||
}, [controls, inView]);
|
||||
|
||||
return (
|
||||
<div
|
||||
id="open-platform"
|
||||
className="mt-32 max-w-7xl mx-auto py-12 px-4 sm:px-6 lg:py-16 lg:px-8"
|
||||
>
|
||||
<motion.div
|
||||
ref={ref}
|
||||
animate={controls}
|
||||
initial="hidden"
|
||||
variants={{
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
when: 'beforeChildren',
|
||||
staggerChildren: 0.12,
|
||||
ease: 'linear',
|
||||
duration: 0.24,
|
||||
type: 'tween',
|
||||
},
|
||||
},
|
||||
}}
|
||||
className="lg:grid lg:grid-cols-2 lg:gap-24 lg:items-center lg:grid-flow-col-dense"
|
||||
>
|
||||
<div>
|
||||
<div className="mt-6">
|
||||
<motion.h2
|
||||
variants={opacityVariant}
|
||||
className="text-3xl font-extrabold tracking-tight text-gray-900"
|
||||
>
|
||||
Open Platform
|
||||
</motion.h2>
|
||||
<motion.p
|
||||
variants={opacityVariant}
|
||||
className="mt-4 text-lg text-gray-500"
|
||||
>
|
||||
The core of Nx is generic, simple, and unobtrusive. Nx Plugins are
|
||||
completely optional, but they can really level up your
|
||||
productivity.
|
||||
<strong>
|
||||
You can use Nx with any technology either by using Nx Core or by
|
||||
using of one of many Nx plugins.
|
||||
</strong>
|
||||
</motion.p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-8 grid grid-cols-3 gap-1 text-gray-500 lg:col-start-2">
|
||||
{featureItems.map((svg, index: number) => (
|
||||
<motion.div
|
||||
key={'open-platform-' + index}
|
||||
variants={opacityTranslateXVariant}
|
||||
className="col-span-1 flex justify-center py-8 px-8 bg-white rounded-md border border-gray-300 "
|
||||
>
|
||||
{svg}
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default OpenPlatform;
|
||||
11
nx-dev/ui-home/src/lib/open-source-projects.spec.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { mockAllIsIntersecting } from 'react-intersection-observer/test-utils';
|
||||
import OpenSourceProjects from './open-source-projects';
|
||||
|
||||
describe('OpenSourceProjects', () => {
|
||||
it('should render successfully', () => {
|
||||
mockAllIsIntersecting(true);
|
||||
const { baseElement } = render(<OpenSourceProjects />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
328
nx-dev/ui-home/src/lib/open-source-projects.tsx
Normal file
@ -0,0 +1,328 @@
|
||||
import React, { ReactComponentElement, useEffect } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { motion, useAnimation } from 'framer-motion';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
import cx from 'classnames';
|
||||
|
||||
export function OpenSourceProjects(): ReactComponentElement<any> {
|
||||
const projectList = [
|
||||
{
|
||||
title: 'Storybook',
|
||||
href: 'https://github.com/storybookjs/storybook',
|
||||
description:
|
||||
'The UI component explorer. Develop, document, & test React, Vue, Angular, Web Components, Ember, Svelte & more!',
|
||||
icon: (
|
||||
<svg
|
||||
className="w-10 h-auto text-[#FF4785]"
|
||||
fill="currentColor"
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M16.71.243l-.12 2.71a.18.18 0 00.29.15l1.06-.8.9.7a.18.18 0 00.28-.14l-.1-2.76 1.33-.1a1.2 1.2 0 011.279 1.2v21.596a1.2 1.2 0 01-1.26 1.2l-16.096-.72a1.2 1.2 0 01-1.15-1.16l-.75-19.797a1.2 1.2 0 011.13-1.27L16.7.222zM13.64 9.3c0 .47 3.16.24 3.59-.08 0-3.2-1.72-4.89-4.859-4.89-3.15 0-4.899 1.72-4.899 4.29 0 4.45 5.999 4.53 5.999 6.959 0 .7-.32 1.1-1.05 1.1-.96 0-1.35-.49-1.3-2.16 0-.36-3.649-.48-3.769 0-.27 4.03 2.23 5.2 5.099 5.2 2.79 0 4.969-1.49 4.969-4.18 0-4.77-6.099-4.64-6.099-6.999 0-.97.72-1.1 1.13-1.1.45 0 1.25.07 1.19 1.87z" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'FluentUi (Microsoft)',
|
||||
href: 'https://github.com/microsoft/fluentui',
|
||||
description:
|
||||
'Fluent UI web represents a collection of utilities, React components, and web components for building web applications.',
|
||||
icon: (
|
||||
<svg
|
||||
className="w-10 h-auto text-[#5E5E5E]"
|
||||
fill="currentColor"
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M0 0v11.408h11.408V0zm12.594 0v11.408H24V0zM0 12.594V24h11.408V12.594zm12.594 0V24H24V12.594z" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'NgRx',
|
||||
href: 'https://github.com/ngrx/platform',
|
||||
description: 'Reactive libraries for Angular.',
|
||||
icon: (
|
||||
<svg
|
||||
className="w-10 h-auto"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 1000 1000"
|
||||
>
|
||||
<defs />
|
||||
<g
|
||||
id="badge"
|
||||
stroke="none"
|
||||
strokeWidth="1"
|
||||
fill="none"
|
||||
fillRule="evenodd"
|
||||
>
|
||||
<polygon
|
||||
id="Path-2"
|
||||
fill="#412846"
|
||||
points="500.96252 11 44 169.619503 109.419009 775.863609 500.96252 989.147518"
|
||||
/>
|
||||
<polygon
|
||||
id="Path-2"
|
||||
fill="#4B314F"
|
||||
points="499 11 955.96252 169.619503 890.543511 775.863609 499 989.147518"
|
||||
/>
|
||||
<path
|
||||
d="M727.748042,345.712306 L727.66634,345.452948 C748.53141,368.675743 759.248655,396.250955 759.818077,428.178583 C760.387499,460.10621 749.670253,493.785553 727.419362,529.113702 C744.049216,516.186231 763.254044,488.280572 784.970754,445.720993 C794.352489,531.973497 759.496406,597.488822 680.07676,642.358274 C705.433171,640.019987 739.098221,623.326102 780.852373,592.218304 C736.295204,699.492316 654.368246,756.091448 535.071499,762.0157 C419.779066,761.984828 345.090509,692.70063 345.149347,692.744623 C297.749003,655.853422 265.136294,609.356006 247.420657,553.461194 C219.071352,522.501468 218.788687,519.181412 215.864399,506.810213 C212.94011,494.439015 217.711589,490.983038 226.016225,478.877684 C231.552649,470.807448 232.857288,459.198337 230.012754,444.257657 C222.955013,434.470009 218.890643,419.140866 217.819642,398.270229 C217.819642,388.184149 224.550937,377.542369 238.013526,366.344888 C251.476116,355.147407 259.735587,346.535764 262.727877,340.60672 C265.010137,337.374281 265.891913,323.360897 265.373204,298.56657 C265.233841,274.213659 278.755317,260.964316 305.93763,258.818543 C346.7111,255.599883 369.705986,224.934529 382.516256,210.988846 C391.056436,201.691724 403.695194,197.172941 419.636711,197.086041 C442.079696,196.034098 462.499977,204.637166 480.091445,222.390999 C523.906033,220.124746 568.786858,231.940816 614.26226,257.53906 C678.886453,295.927519 714.155144,337.500002 720.068335,382.04686 C713.141516,440.672126 634.388911,439.139539 484.158007,377.434888 C405.540854,399.703741 366.890462,447.959933 368.174379,522.203462 C368.120638,590.331666 401.093921,639.837612 466.867448,670.671325 C434.809471,639.197634 421.156861,612.743966 425.754563,590.835913 C492.434057,669.802565 568.387234,699.317583 653.4812,679.387085 C615.964887,680.696908 586.248445,668.625202 563.883439,642.99059 C621.400796,641.592694 675.697848,614.89246 726.828497,562.61827 C697.312743,586.105598 666.427352,594.999478 633.726894,589.404987 C722.294422,519.773811 753.634804,438.542918 727.748042,345.712306 Z M567,335 C574.179702,335 580,329.179702 580,322 C580,314.820298 574.179702,309 567,309 C559.820298,309 554,314.820298 554,322 C554,329.179702 559.820298,335 567,335 Z"
|
||||
id="Combined-Shape"
|
||||
fill="#BA2BD2"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'NativeScript',
|
||||
href: 'https://github.com/NativeScript/NativeScript',
|
||||
description:
|
||||
'NativeScript empowers you to access native platform APIs from JavaScript directly. Angular, Capacitor, Ionic, React, Svelte, Vue and you name it compatible.',
|
||||
icon: (
|
||||
<svg
|
||||
className="w-10 h-auto text-[#3655FF]"
|
||||
fill="currentColor"
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M1.77 1.76A5.68 5.68 0 0 1 5.8 0h12.6c1.37 0 2.65.6 3.83 1.76A5.43 5.43 0 0 1 24 5.7v12.77c0 1.34-.56 2.58-1.68 3.73A5.77 5.77 0 0 1 18.25 24H5.87a6.3 6.3 0 0 1-4.1-1.57C.69 21.45.1 20.03 0 18.13V5.73a5.21 5.21 0 0 1 1.77-3.97zm6.25 8.3l7.93 10.06h2.12c.49-.06.88-.2 1.17-.43.3-.23.5-.56.64-1v-4.94c.08-.95.67-1.54 1.77-1.75-1.1-.4-1.69-1.02-1.77-1.86V5.42c-.12-.44-.33-.8-.64-1.07a1.83 1.83 0 0 0-1.09-.47H16v10.2L8.02 3.87H5.79c-.56.1-.97.3-1.25.6S4.08 5.25 4 5.9v4.85c-.35.69-.9 1.1-1.65 1.25.85.16 1.4.61 1.65 1.36v4.77c.02.55.2 1 .54 1.37.33.36.7.53 1.1.5H8l.02-9.94z" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Typescript eslint',
|
||||
href: 'https://github.com/typescript-eslint/typescript-eslint',
|
||||
description:
|
||||
'Monorepo for all the tooling which enables ESLint to support TypeScript',
|
||||
icon: (
|
||||
<svg
|
||||
className="w-10 h-auto text-[#3178C6]"
|
||||
fill="currentColor"
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M1.125 0C.502 0 0 .502 0 1.125v21.75C0 23.498.502 24 1.125 24h21.75c.623 0 1.125-.502 1.125-1.125V1.125C24 .502 23.498 0 22.875 0zm17.363 9.75c.612 0 1.154.037 1.627.111a6.38 6.38 0 0 1 1.306.34v2.458a3.95 3.95 0 0 0-.643-.361 5.093 5.093 0 0 0-.717-.26 5.453 5.453 0 0 0-1.426-.2c-.3 0-.573.028-.819.086a2.1 2.1 0 0 0-.623.242c-.17.104-.3.229-.393.374a.888.888 0 0 0-.14.49c0 .196.053.373.156.529.104.156.252.304.443.444s.423.276.696.41c.273.135.582.274.926.416.47.197.892.407 1.266.628.374.222.695.473.963.753.268.279.472.598.614.957.142.359.214.776.214 1.253 0 .657-.125 1.21-.373 1.656a3.033 3.033 0 0 1-1.012 1.085 4.38 4.38 0 0 1-1.487.596c-.566.12-1.163.18-1.79.18a9.916 9.916 0 0 1-1.84-.164 5.544 5.544 0 0 1-1.512-.493v-2.63a5.033 5.033 0 0 0 3.237 1.2c.333 0 .624-.03.872-.09.249-.06.456-.144.623-.25.166-.108.29-.234.373-.38a1.023 1.023 0 0 0-.074-1.089 2.12 2.12 0 0 0-.537-.5 5.597 5.597 0 0 0-.807-.444 27.72 27.72 0 0 0-1.007-.436c-.918-.383-1.602-.852-2.053-1.405-.45-.553-.676-1.222-.676-2.005 0-.614.123-1.141.369-1.582.246-.441.58-.804 1.004-1.089a4.494 4.494 0 0 1 1.47-.629 7.536 7.536 0 0 1 1.77-.201zm-15.113.188h9.563v2.166H9.506v9.646H6.789v-9.646H3.375z" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'HomeBridge UI',
|
||||
href: 'https://github.com/oznu/homebridge-config-ui-x',
|
||||
description:
|
||||
'The Homebridge UI. Monitor, configure and backup Homebridge from a browser.',
|
||||
icon: (
|
||||
<svg
|
||||
className="w-10 h-auto text-[#491F59]"
|
||||
fill="currentColor"
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<title>Homebridge</title>
|
||||
<path d="M12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0zm8.116 12.262a.74.74 0 0 1-.741-.74c0-.008.005-.016.005-.025l-1.46-1.46a1.31 1.31 0 0 1-.38-.917V5.731a.285.285 0 0 0-.284-.283h-.915a.284.284 0 0 0-.284.283v2.413L12.17 4.383a.284.284 0 0 0-.4.003L4.438 11.72a.283.283 0 0 0 0 .4l.696.697a.286.286 0 0 0 .4 0l5.635-5.552a1.302 1.302 0 0 1 1.83.008l5.525 5.525a1.3 1.3 0 0 1 0 1.836l-.679.68a1.305 1.305 0 0 1-1.824.012l-3.876-3.766a.283.283 0 0 0-.4.004l-3.723 3.74a.285.285 0 0 0 0 .4l.687.69a.283.283 0 0 0 .4 0l2.013-1.986a1.302 1.302 0 0 1 1.824 0l1.994 1.96.007.007a1.299 1.299 0 0 1 0 1.837l-1.985 1.984v.013a.74.74 0 1 1-.74-.741c.009 0 .016.005.025.005l1.975-1.98a.284.284 0 0 0 .084-.201.28.28 0 0 0-.085-.2l-1.995-1.96a.285.285 0 0 0-.4 0l-2.006 1.98a1.3 1.3 0 0 1-1.83-.004l-.69-.689a1.301 1.301 0 0 1 0-1.834l3.72-3.74a1.303 1.303 0 0 1 1.826-.016l3.879 3.758a.285.285 0 0 0 .4 0l.679-.679a.285.285 0 0 0 0-.4L12.28 7.986a.284.284 0 0 0-.4 0l-5.637 5.555a1.301 1.301 0 0 1-1.829-.008l-.698-.694-.002-.003a1.296 1.296 0 0 1 .002-1.834l7.334-7.334a1.305 1.305 0 0 1 1.821-.015l2.166 2.097v-.019a1.3 1.3 0 0 1 1.299-1.298h.916a1.3 1.3 0 0 1 1.298 1.298v3.384a.282.282 0 0 0 .083.2l1.467 1.467h.014a.74.74 0 0 1 .001 1.48z" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
// {
|
||||
// title: 'Responsible AI widget (Microsoft)',
|
||||
// href: 'https://github.com/microsoft/responsible-ai-widgets',
|
||||
// description:
|
||||
// 'This project provides responsible AI user interfaces for Fairlearn, interpret-community, and Error Analysis, as well as foundational building blocks that they rely on.',
|
||||
// icon: (
|
||||
// <svg
|
||||
// className="w-10 h-auto text-[#5E5E5E]"
|
||||
// fill="currentColor"
|
||||
// role="img"
|
||||
// viewBox="0 0 24 24"
|
||||
// xmlns="http://www.w3.org/2000/svg"
|
||||
// >
|
||||
// <path d="M0 0v11.408h11.408V0zm12.594 0v11.408H24V0zM0 12.594V24h11.408V12.594zm12.594 0V24H24V12.594z" />
|
||||
// </svg>
|
||||
// ),
|
||||
// },
|
||||
{
|
||||
title: 'NGX Bootstrap',
|
||||
href: 'https://github.com/valor-software/ngx-bootstrap',
|
||||
description:
|
||||
'Fast and reliable Bootstrap widgets in Angular (supports Ivy engine)',
|
||||
icon: (
|
||||
<svg
|
||||
className="w-10 h-auto"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 27"
|
||||
>
|
||||
<mask
|
||||
id="mask0_201:20"
|
||||
style={{ maskType: 'alpha' }}
|
||||
maskUnits="userSpaceOnUse"
|
||||
>
|
||||
<path
|
||||
d="M11.9595 0L0 4.40496L1.89024 20.8044L11.9595 26.6047L22.1104 20.7263L24 4.32741L11.9595 0Z"
|
||||
fill="white"
|
||||
/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_201:20)">
|
||||
<path
|
||||
d="M11.9595 0L0 4.40496L1.89024 20.8044L11.9595 26.6047L22.1104 20.7263L24 4.32741L11.9595 0Z"
|
||||
fill="#DD0031"
|
||||
/>
|
||||
<path d="M25.1163 0H11.907V28.093H25.1163V0Z" fill="#C3002F" />
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M9.48837 11.3488H13.4188C13.9968 11.3488 14.4785 11.1803 14.8639 10.8431C15.2492 10.506 15.4419 10.0201 15.4419 9.38543C15.4419 8.67146 15.2685 8.16905 14.9217 7.87817C14.5748 7.5873 14.0739 7.44186 13.4188 7.44186H9.48837V11.3488ZM6.88372 5.39535H13.5471C14.7761 5.39535 15.7618 5.68197 16.5043 6.25523C17.2468 6.82848 17.6181 7.69487 17.6181 8.85441C17.6181 9.55795 17.4484 10.1605 17.1092 10.6621C16.7699 11.1637 16.2867 11.5513 15.6594 11.8249V11.864C16.5043 12.0464 17.1444 12.4535 17.5797 13.0854C18.0149 13.7173 18.2326 14.5088 18.2326 15.4598C18.2326 16.007 18.1365 16.5184 17.9445 16.9939C17.7525 17.4695 17.4516 17.8799 17.042 18.2251C16.6323 18.5704 16.1075 18.844 15.4674 19.0459C14.8273 19.2479 14.0656 19.3488 13.1822 19.3488H6.88372V5.39535ZM9.48837 17.3023H13.7085C14.4342 17.3023 14.9975 17.1136 15.3985 16.7363C15.7995 16.3589 16 15.8248 16 15.134C16 14.456 15.7995 13.9347 15.3985 13.5701C14.9975 13.2055 14.4342 13.0233 13.7085 13.0233H9.48837V17.3023Z"
|
||||
fill="white"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'WooCommerce',
|
||||
href: 'https://github.com/woocommerce/woocommerce',
|
||||
description:
|
||||
'WooCommerce is a customizable, open-source eCommerce platform built on WordPress. Get started quickly and make your way.',
|
||||
icon: (
|
||||
<svg
|
||||
className="w-10 h-auto text-[#96588A]"
|
||||
fill="currentColor"
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M2.227 4.857A2.228 2.228 0 000 7.094v7.457c0 1.236 1.001 2.237 2.237 2.237h9.253l4.229 2.355-.962-2.355h7.006c1.236 0 2.237-1 2.237-2.237V7.094c0-1.236-1-2.237-2.237-2.237zm8.08 1.311c.194.002.372.071.535.2a.769.769 0 01.304.56.851.851 0 01-.098.47c-.382.707-.696 1.894-.951 3.542-.246 1.6-.334 2.846-.275 3.739.02.245-.02.46-.118.647a.632.632 0 01-.52.353c-.255.02-.52-.098-.775-.362-.913-.933-1.639-2.326-2.169-4.18a184.085 184.085 0 00-1.413 2.825c-.578 1.11-1.069 1.678-1.481 1.708-.265.02-.49-.206-.687-.677-.5-1.286-1.04-3.768-1.619-7.448-.03-.255.02-.48.157-.657.137-.186.344-.284.618-.304.5-.04.785.196.854.706.304 2.051.638 3.788.991 5.21L5.809 8.41c.196-.373.441-.57.736-.589.431-.03.696.245.804.824.246 1.305.56 2.414.932 3.356.255-2.492.687-4.288 1.295-5.397.148-.274.363-.412.648-.431a.866.866 0 01.084-.004zm3.734 1.063c.167 0 .343.02.53.06.687.146 1.216.52 1.57 1.137.314.53.47 1.168.47 1.933 0 1.011-.254 1.933-.765 2.777-.588.981-1.354 1.472-2.305 1.472-.167 0-.344-.02-.53-.059-.697-.147-1.217-.52-1.57-1.138-.314-.54-.471-1.187-.471-1.943 0-1.01.255-1.933.765-2.767.599-.981 1.364-1.472 2.306-1.472zm6.152 0c.167 0 .343.02.53.06.696.146 1.216.52 1.57 1.137.314.53.47 1.168.47 1.933 0 1.011-.254 1.933-.765 2.777-.588.981-1.354 1.472-2.305 1.472-.167 0-.344-.02-.53-.059-.697-.147-1.217-.52-1.57-1.138-.314-.54-.471-1.187-.471-1.943 0-1.01.255-1.933.765-2.767.599-.981 1.364-1.472 2.306-1.472zm-6.107 1.645c-.307-.002-.606.201-.889.622a3.173 3.173 0 00-.52 1.168c-.05.225-.069.47-.069.716 0 .284.06.589.177.893.147.382.343.589.579.638.245.049.51-.06.795-.315.363-.323.608-.804.745-1.452.05-.225.069-.47.069-.726a2.49 2.49 0 00-.176-.893c-.148-.382-.344-.588-.58-.637a.714.714 0 00-.131-.014zm6.152 0c-.307-.002-.606.201-.889.622a3.173 3.173 0 00-.52 1.168c-.049.225-.069.47-.069.716 0 .284.06.589.177.893.147.382.344.589.579.638.245.049.51-.06.795-.315.363-.323.608-.804.745-1.452.04-.225.07-.47.07-.726a2.49 2.49 0 00-.177-.893c-.148-.382-.344-.588-.58-.637a.714.714 0 00-.131-.014Z" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
// {
|
||||
// title: 'Taiga UI',
|
||||
// href: 'https://github.com/TinkoffCreditSystems/taiga-ui',
|
||||
// description:
|
||||
// 'Taiga UI is fully-treeshakable Angular UI Kit consisting of multiple base libraries and several add-ons.',
|
||||
// icon: (
|
||||
// <svg
|
||||
// className="w-10 h-auto"
|
||||
// role="img"
|
||||
// viewBox="0 0 34 30"
|
||||
// fill="none"
|
||||
// xmlns="http://www.w3.org/2000/svg"
|
||||
// >
|
||||
// <path
|
||||
// fillRule="evenodd"
|
||||
// clipRule="evenodd"
|
||||
// d="M34 29.4667L17 0L0 29.4667H10.3208L14.6218 22.8197H11.4867L17.0002 14.09L22.5137 22.8197H19.3785L23.6795 29.4667H34Z"
|
||||
// fill="#FF7043"
|
||||
// />
|
||||
// </svg>
|
||||
// ),
|
||||
// },
|
||||
];
|
||||
const opacityTranslateXVariant = {
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
x: -46,
|
||||
},
|
||||
visible: (delay: number = 0) => ({
|
||||
opacity: 1,
|
||||
x: 0,
|
||||
transition: { delay, duration: 0.32 },
|
||||
}),
|
||||
};
|
||||
const controls = useAnimation();
|
||||
const [ref, inView] = useInView({ threshold: 0.5, triggerOnce: true });
|
||||
|
||||
useEffect(() => {
|
||||
if (!inView) return;
|
||||
controls.start('visible');
|
||||
}, [controls, inView]);
|
||||
|
||||
return (
|
||||
<div id="open-source">
|
||||
<motion.div
|
||||
ref={ref}
|
||||
animate={controls}
|
||||
initial="hidden"
|
||||
variants={{
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
when: 'beforeChildren',
|
||||
staggerChildren: 0.12,
|
||||
ease: 'linear',
|
||||
duration: 0.24,
|
||||
type: 'tween',
|
||||
},
|
||||
},
|
||||
}}
|
||||
className="lg:mx-auto lg:max-w-7xl p-4 flex"
|
||||
>
|
||||
<div className="rounded-lg bg-gray-200 overflow-hidden shadow divide-y divide-gray-200 sm:divide-y-0 sm:grid sm:grid-cols-2 sm:gap-px">
|
||||
{projectList.map((project, index: number) => (
|
||||
<motion.div
|
||||
key={project.title}
|
||||
custom={0.12 * index + 0.24}
|
||||
variants={opacityTranslateXVariant}
|
||||
className={cx(
|
||||
index === 0
|
||||
? 'rounded-tl-lg rounded-tr-lg sm:rounded-tr-none'
|
||||
: '',
|
||||
index === 1 ? 'sm:rounded-tr-lg' : '',
|
||||
index === projectList.length - 2 ? 'sm:rounded-bl-lg' : '',
|
||||
index === projectList.length - 1
|
||||
? 'rounded-bl-lg rounded-br-lg sm:rounded-bl-none'
|
||||
: '',
|
||||
'relative group bg-white p-6 focus-within:ring-2 focus-within:ring-inset focus-within:ring-blue-nx-base'
|
||||
)}
|
||||
>
|
||||
<div>
|
||||
<span className="rounded-lg inline-flex">{project.icon}</span>
|
||||
</div>
|
||||
<div className="mt-2">
|
||||
<h3 className="text-lg font-medium">
|
||||
<Link href={project.href}>
|
||||
<a
|
||||
target="_blank"
|
||||
rel="nofollow"
|
||||
className="focus:outline-none"
|
||||
>
|
||||
{/* Extend touch target to entire panel */}
|
||||
<span className="absolute inset-0" aria-hidden="true" />
|
||||
{project.title}
|
||||
</a>
|
||||
</Link>
|
||||
</h3>
|
||||
<p className="mt-2 text-sm text-gray-400">
|
||||
{project.description}
|
||||
</p>
|
||||
</div>
|
||||
<span
|
||||
className="pointer-events-none absolute top-6 right-6 text-gray-300 group-hover:text-gray-400 transition-all group-hover:translate-x-2 group-hover:-translate-y-2"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<svg
|
||||
className="h-6 w-6"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path d="M20 4h1a1 1 0 00-1-1v1zm-1 12a1 1 0 102 0h-2zM8 3a1 1 0 000 2V3zM3.293 19.293a1 1 0 101.414 1.414l-1.414-1.414zM19 4v12h2V4h-2zm1-1H8v2h12V3zm-.707.293l-16 16 1.414 1.414 16-16-1.414-1.414z" />
|
||||
</svg>
|
||||
</span>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default OpenSourceProjects;
|
||||
11
nx-dev/ui-home/src/lib/performance.spec.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { mockAllIsIntersecting } from 'react-intersection-observer/test-utils';
|
||||
import AffectedCommand from './affected-command';
|
||||
|
||||
describe('AffectedCommand', () => {
|
||||
it('should render successfully', () => {
|
||||
mockAllIsIntersecting(true);
|
||||
const { baseElement } = render(<AffectedCommand />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
157
nx-dev/ui-home/src/lib/performance.tsx
Normal file
@ -0,0 +1,157 @@
|
||||
import React, { ReactComponentElement, useEffect, useRef } from 'react';
|
||||
import {
|
||||
animate,
|
||||
motion,
|
||||
MotionValue,
|
||||
useAnimation,
|
||||
useMotionValue,
|
||||
useTransform,
|
||||
} from 'framer-motion';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
|
||||
function Counter({
|
||||
from = 0,
|
||||
to = 10,
|
||||
round = 0,
|
||||
progress,
|
||||
}: {
|
||||
from: number;
|
||||
to: number;
|
||||
round: number;
|
||||
progress: MotionValue<number>;
|
||||
}): ReactComponentElement<any> {
|
||||
const ref = useRef();
|
||||
const value = useTransform(progress, [0, 1000], [from, to], {
|
||||
clamp: false,
|
||||
});
|
||||
|
||||
const { format: formatNumber } = new Intl.NumberFormat('en-US', {
|
||||
minimumFractionDigits: round,
|
||||
maximumFractionDigits: round,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
return value.onChange((v) => {
|
||||
if (ref !== undefined && ref.current !== undefined)
|
||||
ref.current.firstChild.data = formatNumber(
|
||||
round === 0 ? Math.round(v) : Number(v.toFixed(round))
|
||||
);
|
||||
});
|
||||
}, [formatNumber, round, value]);
|
||||
|
||||
return <span ref={ref}>{formatNumber(value.get())}</span>;
|
||||
}
|
||||
|
||||
export function Performance(): ReactComponentElement<any> {
|
||||
const progress: MotionValue<number> = useMotionValue(0);
|
||||
const opacityVariant = {
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
},
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: { duration: 0.32, ease: 'easeOut' },
|
||||
},
|
||||
};
|
||||
const controls = useAnimation();
|
||||
const [ref, inView] = useInView({ threshold: 0.5, triggerOnce: true });
|
||||
|
||||
useEffect(() => {
|
||||
if (!inView) return;
|
||||
controls.start('visible');
|
||||
animate(progress, 1000, {
|
||||
type: 'spring',
|
||||
damping: 50,
|
||||
});
|
||||
}, [controls, inView, progress]);
|
||||
|
||||
return (
|
||||
<div id="performance" className="mt-80">
|
||||
<motion.div
|
||||
ref={ref}
|
||||
animate={controls}
|
||||
initial="hidden"
|
||||
variants={{
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
when: 'beforeChildren',
|
||||
staggerChildren: 0.12,
|
||||
ease: 'linear',
|
||||
duration: 0.24,
|
||||
type: 'tween',
|
||||
},
|
||||
},
|
||||
}}
|
||||
className="lg:mx-auto lg:max-w-7xl lg:px-8 lg:grid lg:grid-cols-2 lg:grid-flow-col-dense lg:gap-24"
|
||||
>
|
||||
<div className="px-4 max-w-xl mx-auto sm:px-6 lg:py-32 lg:max-w-none lg:mx-0 lg:px-0 lg:col-start-2">
|
||||
<div>
|
||||
<div className="mt-6">
|
||||
<motion.h2
|
||||
variants={opacityVariant}
|
||||
className="text-3xl font-extrabold tracking-tight text-gray-900"
|
||||
>
|
||||
Nx is Fast
|
||||
</motion.h2>
|
||||
<motion.p
|
||||
variants={opacityVariant}
|
||||
className="mt-4 text-lg text-gray-500"
|
||||
>
|
||||
Nx uses its distributed task execution and computation caching
|
||||
to keep your CI time the same, whether you build one project or
|
||||
a thousand.
|
||||
</motion.p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-8 grid grid-cols-1 sm:grid-cols-2 lg:col-start-1">
|
||||
<div className="p-8 lg:pt-0 lg:pl-0 lg:pb-8 lg:pr-8 col-span-1 flex flex-col justify-center border-r border-b border-gray-100">
|
||||
<div className="text-lg text-gray-600">Up to</div>
|
||||
<div className="my-2 text-7xl font-bold text-gray-800">
|
||||
<Counter from={0} to={3} round={0} progress={progress} />{' '}
|
||||
<span className="-ml-3 text-3xl">x</span>
|
||||
</div>
|
||||
<div className="text-md font-medium text-gray-600">
|
||||
reduction in CI time for mid-size projects with standard CI setups
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-8 lg:pr-0 lg:pt-0 lg:pb-8 lg:pl-8 col-span-1 flex flex-col justify-center border-l border-b border-gray-100">
|
||||
<div className="text-lg text-gray-600">Up to</div>
|
||||
<div className="my-2 text-7xl font-bold text-gray-800">
|
||||
<Counter from={0} to={14} round={0} progress={progress} />{' '}
|
||||
<span className="-ml-3 text-3xl">x</span>
|
||||
</div>
|
||||
<div className="text-md font-medium text-gray-600">
|
||||
reduction in CI time for large projects with standard CI setups
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-8 lg:pb-0 lg:pl-0 lg:pt-8 lg:pr-8 col-span-1 flex flex-col justify-center border-r border-t border-gray-100">
|
||||
<div className="text-lg text-gray-600">Up to</div>
|
||||
<div className="my-2 text-7xl font-bold text-gray-800">
|
||||
<Counter from={0} to={50} round={0} progress={progress} />{' '}
|
||||
<span className="-ml-3 text-3xl">%</span>
|
||||
</div>
|
||||
<div className="text-md font-medium text-gray-600">
|
||||
reduction in CI time for large projects with highly-optimized
|
||||
distributed CI setups
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-8 lg:pb-0 lg:pr-0 lg:pt-8 lg:pl-8 col-span-1 flex flex-col justify-center border-l border-t border-gray-100">
|
||||
<div className="text-lg text-gray-600">Average</div>
|
||||
<div className="my-2 text-7xl font-bold text-gray-800">
|
||||
<Counter from={0} to={2.5} round={1} progress={progress} />{' '}
|
||||
<span className="-ml-3 text-3xl">x</span>
|
||||
</div>
|
||||
<div className="text-md font-medium text-gray-600">
|
||||
reduction in computation time
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Performance;
|
||||
11
nx-dev/ui-home/src/lib/vscode-plugin.spec.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { mockAllIsIntersecting } from 'react-intersection-observer/test-utils';
|
||||
import VscodePlugin from './vscode-plugin';
|
||||
|
||||
describe('VscodePlugin', () => {
|
||||
it('should render successfully', () => {
|
||||
mockAllIsIntersecting(true);
|
||||
const { baseElement } = render(<VscodePlugin />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
105
nx-dev/ui-home/src/lib/vscode-plugin.tsx
Normal file
@ -0,0 +1,105 @@
|
||||
import React, { ReactComponentElement, useEffect } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { motion, useAnimation } from 'framer-motion';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
import Image from 'next/image';
|
||||
|
||||
export function VscodePlugin(): ReactComponentElement<any> {
|
||||
const opacityTranslateXVariant = {
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
x: -46,
|
||||
},
|
||||
visible: (delay: number = 0) => ({
|
||||
opacity: 1,
|
||||
x: 0,
|
||||
transition: { delay, duration: 0.32 },
|
||||
}),
|
||||
};
|
||||
const opacityVariant = {
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
},
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: { duration: 0.32, ease: 'easeOut' },
|
||||
},
|
||||
};
|
||||
const controls = useAnimation();
|
||||
const [ref, inView] = useInView({ threshold: 0.5, triggerOnce: true });
|
||||
|
||||
useEffect(() => {
|
||||
if (!inView) return;
|
||||
controls.start('visible');
|
||||
}, [controls, inView]);
|
||||
|
||||
return (
|
||||
<div id="vscode-plugin" className="mt-16 md:mt-32">
|
||||
<motion.div
|
||||
ref={ref}
|
||||
animate={controls}
|
||||
initial="hidden"
|
||||
variants={{
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
when: 'beforeChildren',
|
||||
staggerChildren: 0.12,
|
||||
ease: 'linear',
|
||||
duration: 0.24,
|
||||
type: 'tween',
|
||||
},
|
||||
},
|
||||
}}
|
||||
className="lg:mx-auto lg:max-w-7xl lg:px-8 lg:grid lg:grid-cols-2 lg:grid-flow-col-dense lg:gap-24"
|
||||
>
|
||||
<div className="px-4 max-w-xl mx-auto sm:px-6 lg:py-32 lg:max-w-none lg:mx-0 lg:px-0 lg:col-start-2">
|
||||
<div>
|
||||
<div className="mt-6">
|
||||
<motion.h2
|
||||
variants={opacityVariant}
|
||||
className="text-3xl font-extrabold tracking-tight text-gray-900"
|
||||
>
|
||||
Visual Studio Code Plugin
|
||||
</motion.h2>
|
||||
<motion.p
|
||||
variants={opacityVariant}
|
||||
className="mt-4 text-lg text-gray-500"
|
||||
>
|
||||
Nx Console adds Nx-aware autocompletion and code lenses. It
|
||||
helps you generate components in folders, refactor your
|
||||
projects, construct commands, and much more.
|
||||
</motion.p>
|
||||
<motion.div variants={opacityVariant} className="mt-6">
|
||||
<Link href="/getting-started/console">
|
||||
<a className="inline-flex px-4 py-2 border border-transparent text-base font-medium rounded-md shadow-sm text-white bg-blue-nx-base hover:bg-blue-nx-dark transition">
|
||||
Install Nx Console
|
||||
</a>
|
||||
</Link>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-12 sm:mt-16 lg:mt-0 lg:col-start-1">
|
||||
<div className="relative px-4 lg:px-0 lg:h-full">
|
||||
<motion.div
|
||||
variants={opacityTranslateXVariant}
|
||||
className="-mt-8 mx-auto w-full max-w-screen-sm rounded-xl shadow-xl border border-gray-300 lg:absolute lg:right-0 lg:h-full lg:w-auto lg:max-w-none overflow-hidden"
|
||||
>
|
||||
<Image
|
||||
src="/images/nx-console.webp"
|
||||
alt="Nx Console VS Code plugin"
|
||||
layout={'fixed'}
|
||||
width={690}
|
||||
height={482}
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default VscodePlugin;
|
||||
12
nx-dev/ui-home/src/lib/youtube-channel.spec.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import YoutubeChannel from './youtube-channel';
|
||||
import { mockAllIsIntersecting } from 'react-intersection-observer/test-utils';
|
||||
|
||||
describe('YoutubeChannel', () => {
|
||||
it('should render successfully', () => {
|
||||
mockAllIsIntersecting(true);
|
||||
const { baseElement } = render(<YoutubeChannel />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
68
nx-dev/ui-home/src/lib/youtube-channel.tsx
Normal file
@ -0,0 +1,68 @@
|
||||
import React, { ReactComponentElement, useEffect } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { motion, useAnimation } from 'framer-motion';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
|
||||
export function YoutubeChannel(): ReactComponentElement<any> {
|
||||
const controls = useAnimation();
|
||||
const [ref, inView] = useInView({ threshold: 0.5, triggerOnce: true });
|
||||
|
||||
useEffect(() => {
|
||||
if (!inView) return;
|
||||
controls.start('visible');
|
||||
}, [controls, inView]);
|
||||
|
||||
return (
|
||||
<div id="vscode-plgin" className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<motion.div
|
||||
ref={ref}
|
||||
animate={controls}
|
||||
initial="hidden"
|
||||
variants={{
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
ease: 'linear',
|
||||
duration: 0.24,
|
||||
type: 'tween',
|
||||
},
|
||||
},
|
||||
}}
|
||||
className="bg-blue-nx-base rounded-lg shadow-xl overflow-hidden lg:grid lg:grid-cols-2 lg:gap-4"
|
||||
>
|
||||
<div className="pt-10 pb-12 px-6 sm:pt-16 sm:px-16 lg:py-16 lg:pr-0 xl:py-20 xl:px-20 lg:order-2">
|
||||
<div className="lg:self-center">
|
||||
<h2 className="text-3xl font-extrabold text-white sm:text-4xl">
|
||||
<span className="block">A dedicated</span>
|
||||
<span className="block">Youtube Channel</span>
|
||||
</h2>
|
||||
<p className="mt-4 text-lg leading-6 text-gray-100">
|
||||
Get the latest news and video tutorials for free. Like and
|
||||
subscribe, you know the drill.
|
||||
</p>
|
||||
<Link href="https://www.youtube.com/c/Nrwl_io?utm_source=nx.dev">
|
||||
<a
|
||||
rel="nofollow"
|
||||
target="_blank"
|
||||
className="mt-8 bg-white border border-transparent rounded-md shadow px-5 py-3 inline-flex items-center text-base font-medium text-blue-nx-base hover:bg-gray-100"
|
||||
>
|
||||
Check the Nx Youtube channel
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="-mt-6 aspect-w-5 aspect-h-3 md:aspect-w-2 md:aspect-h-1 lg:order-1">
|
||||
<img
|
||||
loading="lazy"
|
||||
className="transform -translate-x-6 translate-y-6 rounded-md object-cover object-left-top sm:-translate-x-22 lg:translate-y-20"
|
||||
src="/images/nrwlio-channel.webp"
|
||||
alt="nrwl youtube channel"
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default YoutubeChannel;
|
||||
23
nx-dev/ui-home/tsconfig.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"allowJs": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
14
nx-dev/ui-home/tsconfig.lib.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"lib": ["dom"],
|
||||
"types": ["node", "dom"]
|
||||
},
|
||||
"files": [
|
||||
"../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
|
||||
"../../node_modules/@nrwl/react/typings/image.d.ts"
|
||||
],
|
||||
"exclude": ["**/*.spec.ts", "**/*.spec.tsx"],
|
||||
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
|
||||
}
|
||||
15
nx-dev/ui-home/tsconfig.spec.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"types": ["jest", "node"]
|
||||
},
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.spec.tsx",
|
||||
"**/*.spec.js",
|
||||
"**/*.spec.jsx",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
||||
@ -2,6 +2,7 @@ export * from './lib/header';
|
||||
export * from './lib/feature-list';
|
||||
export * from './lib/footer';
|
||||
export * from './lib/selector';
|
||||
export * from './lib/inline-command';
|
||||
export * from './lib/npx-create-nx-workspace';
|
||||
export * from './lib/nx-users-showcase';
|
||||
export * from './lib/plugin-card';
|
||||
export * from './lib/testimonials';
|
||||
|
||||
@ -5,123 +5,257 @@ export interface FooterProps {
|
||||
useDarkBackground?: boolean;
|
||||
}
|
||||
export function Footer({ useDarkBackground }: FooterProps) {
|
||||
const navigation = {
|
||||
solutions: [
|
||||
{ name: 'Nx', href: 'https://nx.dev' },
|
||||
{ name: 'NxCloud', href: 'https://nx.app/?utm_source=nx.dev' },
|
||||
{ name: 'Nrwl', href: 'https://nrwl.io/?utm_source=nx.dev' },
|
||||
],
|
||||
resources: [
|
||||
{ name: 'Blog', href: 'https://blog.nrwl.io/?utm_source=nx.dev' },
|
||||
{
|
||||
name: 'Youtube Channel',
|
||||
href: 'https://youtube.com/nrwl_io?utm_source=nx.dev',
|
||||
},
|
||||
{
|
||||
name: 'Nx Playbook',
|
||||
href: 'https://nxplaybook.com/?utm_source=nx.dev',
|
||||
},
|
||||
{ name: 'Nrwl', href: 'https://nrwl.io/?utm_source=nx.dev' },
|
||||
],
|
||||
community: [
|
||||
{ name: 'Twitter', href: 'https://twitter.com/NXdevtools' },
|
||||
{ name: 'Github', href: 'https://github.com/nrwl/nx/' },
|
||||
{
|
||||
name: 'Newsletter',
|
||||
href: 'https://go.nrwl.io/nx-newsletter?utm_source=nx.dev',
|
||||
},
|
||||
{
|
||||
name: 'Slack',
|
||||
href: 'https://go.nrwl.io/join-slack?utm_source=nx.dev',
|
||||
},
|
||||
{
|
||||
name: 'Help Us',
|
||||
href: 'https://github.com/nrwl/nx/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Acommunity',
|
||||
},
|
||||
],
|
||||
help: [
|
||||
{ name: 'Documentation', href: '/getting-started/intro' },
|
||||
{ name: 'Community', href: '/community' },
|
||||
{
|
||||
name: 'StackOverflow',
|
||||
href: 'https://stackoverflow.com/questions/tagged/nrwl-nx',
|
||||
},
|
||||
{
|
||||
name: 'Report Issues',
|
||||
href: 'https://github.com/nrwl/nx/issues?q=is%3Aopen+is%3Aissue',
|
||||
},
|
||||
],
|
||||
social: [
|
||||
{
|
||||
name: 'Twitter',
|
||||
href: 'https://twitter.com/NXdevtools?utm_source=nx.dev',
|
||||
icon: (props: any) => (
|
||||
<svg fill="currentColor" viewBox="0 0 24 24" {...props}>
|
||||
<path d="M8.29 20.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0022 5.92a8.19 8.19 0 01-2.357.646 4.118 4.118 0 001.804-2.27 8.224 8.224 0 01-2.605.996 4.107 4.107 0 00-6.993 3.743 11.65 11.65 0 01-8.457-4.287 4.106 4.106 0 001.27 5.477A4.072 4.072 0 012.8 9.713v.052a4.105 4.105 0 003.292 4.022 4.095 4.095 0 01-1.853.07 4.108 4.108 0 003.834 2.85A8.233 8.233 0 012 18.407a11.616 11.616 0 006.29 1.84" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'GitHub',
|
||||
href: 'https://github.com/nrwl/nx?utm_source=nx.dev',
|
||||
icon: (props: any) => (
|
||||
<svg fill="currentColor" viewBox="0 0 24 24" {...props}>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'Slack',
|
||||
href: 'https://go.nrwl.io/join-slack?utm_source=nx.dev',
|
||||
icon: (props: any) => (
|
||||
<svg
|
||||
fill="currentColor"
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zM6.313 15.165a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zM8.834 6.313a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zM18.956 8.834a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zM17.688 8.834a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zM15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zM15.165 17.688a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'Newsletter',
|
||||
href: 'https://go.nrwl.io/nx-newsletter?utm_source=nx.dev',
|
||||
icon: (props: any) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M19 20H5a2 2 0 01-2-2V6a2 2 0 012-2h10a2 2 0 012 2v1m2 13a2 2 0 01-2-2V7m2 13a2 2 0 002-2V9a2 2 0 00-2-2h-2m-4-3H9M7 16h6M7 8h6v4H7V8z"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
return (
|
||||
<footer
|
||||
className={cx(useDarkBackground ? 'bg-blue-nx-dark' : 'bg-white')}
|
||||
aria-labelledby="footer-heading"
|
||||
>
|
||||
<h2 id="footer-heading" className="sr-only">
|
||||
Footer
|
||||
</h2>
|
||||
<div className="max-w-7xl mx-auto py-12 px-4 sm:px-6 lg:py-16 lg:px-8">
|
||||
<div className="xl:grid xl:grid-cols-3 xl:gap-8">
|
||||
<div className="text-gray-500 space-y-4 xl:col-span-1">
|
||||
<svg
|
||||
className="h-14 subpixel-antialiased"
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<title>Nx</title>
|
||||
<path d="M11.987 14.138l-3.132 4.923-5.193-8.427-.012 8.822H0V4.544h3.691l5.247 8.833.005-3.998 3.044 4.759zm.601-5.761c.024-.048 0-3.784.008-3.833h-3.65c.002.059-.005 3.776-.003 3.833h3.645zm5.634 4.134a2.061 2.061 0 0 0-1.969 1.336 1.963 1.963 0 0 1 2.343-.739c.396.161.917.422 1.33.283a2.1 2.1 0 0 0-1.704-.88zm3.39 1.061c-.375-.13-.8-.277-1.109-.681-.06-.08-.116-.17-.176-.265a2.143 2.143 0 0 0-.533-.642c-.294-.216-.68-.322-1.18-.322a2.482 2.482 0 0 0-2.294 1.536 2.325 2.325 0 0 1 4.002.388.75.75 0 0 0 .836.334c.493-.105.46.36 1.203.518v-.133c-.003-.446-.246-.55-.75-.733zm2.024 1.266a.723.723 0 0 0 .347-.638c-.01-2.957-2.41-5.487-5.37-5.487a5.364 5.364 0 0 0-4.487 2.418c-.01-.026-1.522-2.39-1.538-2.418H8.943l3.463 5.423-3.379 5.32h3.54l1.54-2.366 1.568 2.366h3.541l-3.21-5.052a.7.7 0 0 1-.084-.32 2.69 2.69 0 0 1 2.69-2.691h.001c1.488 0 1.736.89 2.057 1.308.634.826 1.9.464 1.9 1.541a.707.707 0 0 0 1.066.596zm.35.133c-.173.372-.56.338-.755.639-.176.271.114.412.114.412s.337.156.538-.311c.104-.231.14-.488.103-.74z" />
|
||||
</svg>
|
||||
<p className="text-base">Smart, Extensible Build Framework</p>
|
||||
<div className="flex space-x-6">
|
||||
{navigation.social.map((item) => (
|
||||
<Link key={item.name} href={item.href}>
|
||||
<a
|
||||
className={cx(
|
||||
'pt-16 md:pt-32 text-white body-font',
|
||||
useDarkBackground ? 'bg-blue-nx-dark' : 'bg-blue-nx-base'
|
||||
'text-gray-400',
|
||||
useDarkBackground
|
||||
? 'hover:text-gray-300'
|
||||
: 'hover:text-gray-500'
|
||||
)}
|
||||
>
|
||||
<div className="max-w-screen-sm mx-auto px-5 py-5">
|
||||
{/*FOOTER LINKS*/}
|
||||
<div className="my-12 flex sm:flex-row flex-col items-start text-center sm:text-left">
|
||||
<div className="w-full sm:w-1/3 flex flex-col p-6 mt-8 sm:mt-0">
|
||||
<h3 className="text-lg font-extrabold leading-none tracking-tight mb-4">
|
||||
<span className="sr-only">{item.name}</span>
|
||||
<item.icon className="h-6 w-6" aria-hidden="true" />
|
||||
</a>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-12 grid grid-cols-2 gap-8 xl:mt-0 xl:col-span-2">
|
||||
<div className="md:grid md:grid-cols-2 md:gap-8">
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-gray-400 tracking-wider uppercase">
|
||||
Resources
|
||||
</h3>
|
||||
<ul>
|
||||
<li className="mb-2">
|
||||
<ul role="list" className="mt-4 space-y-4">
|
||||
{navigation.resources.map((item) => (
|
||||
<li key={item.name}>
|
||||
<Link href={item.href}>
|
||||
<a
|
||||
href="https://blog.nrwl.io/?utm_source=nx.dev"
|
||||
target="_blank"
|
||||
rel="nofollow"
|
||||
className="cursor-pointer block"
|
||||
className={cx(
|
||||
'text-base text-gray-500',
|
||||
useDarkBackground
|
||||
? 'hover:text-gray-200'
|
||||
: 'hover:text-gray-900'
|
||||
)}
|
||||
>
|
||||
Blog
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://nrwl.io/?utm_source=nx.dev"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="cursor-pointer block"
|
||||
>
|
||||
Nrwl
|
||||
{item.name}
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="w-full sm:w-1/3 flex flex-col p-6 mt-8 sm:mt-0">
|
||||
<h3 className="text-lg font-extrabold leading-none tracking-tight mb-4">
|
||||
<div className="mt-12 md:mt-0">
|
||||
<h3 className="text-sm font-semibold text-gray-400 tracking-wider uppercase">
|
||||
Help
|
||||
</h3>
|
||||
<ul>
|
||||
<li className="mb-2">
|
||||
<Link href={`/getting-started/intro`}>
|
||||
<a className="cursor-pointer block">Documentation</a>
|
||||
<ul role="list" className="mt-4 space-y-4">
|
||||
{navigation.help.map((item) => (
|
||||
<li key={item.name}>
|
||||
<Link href={item.href}>
|
||||
<a
|
||||
className={cx(
|
||||
'text-base text-gray-500',
|
||||
useDarkBackground
|
||||
? 'hover:text-gray-200'
|
||||
: 'hover:text-gray-900'
|
||||
)}
|
||||
>
|
||||
{item.name}
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
<li className="mb-2">
|
||||
<Link href="/community">
|
||||
<a className="cursor-pointer block">Community</a>
|
||||
</Link>
|
||||
</li>
|
||||
<li className="mb-2">
|
||||
<a
|
||||
href="https://stackoverflow.com/questions/tagged/nrwl-nx"
|
||||
target="_blank"
|
||||
rel="nofollow"
|
||||
className="cursor-pointer block"
|
||||
>
|
||||
StackOverflow
|
||||
</a>
|
||||
</li>
|
||||
<li className="mb-2">
|
||||
<a
|
||||
href="https://github.com/nrwl/nx/issues?q=is%3Aopen+is%3Aissue"
|
||||
target="_blank"
|
||||
rel="nofollow"
|
||||
className="cursor-pointer block"
|
||||
>
|
||||
Report Issues
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="w-full sm:w-1/3 flex flex-col p-6 mt-8 sm:mt-0">
|
||||
<h3 className="text-lg font-extrabold leading-none tracking-tight mb-4">
|
||||
</div>
|
||||
<div className="md:grid md:grid-cols-2 md:gap-8">
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-gray-400 tracking-wider uppercase">
|
||||
Community
|
||||
</h3>
|
||||
<ul>
|
||||
<li className="mb-2">
|
||||
<ul role="list" className="mt-4 space-y-4">
|
||||
{navigation.community.map((item) => (
|
||||
<li key={item.name}>
|
||||
<Link href={item.href}>
|
||||
<a
|
||||
href="https://twitter.com/NXdevtools"
|
||||
target="_blank"
|
||||
rel="nofollow"
|
||||
className="cursor-pointer block"
|
||||
className={cx(
|
||||
'text-base text-gray-500',
|
||||
useDarkBackground
|
||||
? 'hover:text-gray-200'
|
||||
: 'hover:text-gray-900'
|
||||
)}
|
||||
>
|
||||
Twitter
|
||||
{item.name}
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
<li className="mb-2">
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="mt-12 md:mt-0">
|
||||
<h3 className="text-sm font-semibold text-gray-400 tracking-wider uppercase">
|
||||
Solutions
|
||||
</h3>
|
||||
<ul role="list" className="mt-4 space-y-4">
|
||||
{navigation.solutions.map((item) => (
|
||||
<li key={item.name}>
|
||||
<Link href={item.href}>
|
||||
<a
|
||||
href="https://github.com/nrwl/nx/"
|
||||
target="_blank"
|
||||
rel="nofollow"
|
||||
className="cursor-pointer block"
|
||||
className={cx(
|
||||
'text-base text-gray-500',
|
||||
useDarkBackground
|
||||
? 'hover:text-gray-200'
|
||||
: 'hover:text-gray-900'
|
||||
)}
|
||||
>
|
||||
Github
|
||||
</a>
|
||||
</li>
|
||||
<li className="mb-2">
|
||||
<a
|
||||
href="https://github.com/nrwl/nx/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Acommunity"
|
||||
target="_blank"
|
||||
rel="nofollow"
|
||||
className="cursor-pointer block"
|
||||
>
|
||||
Help us
|
||||
{item.name}
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-16 mb-6 w-full text-center">
|
||||
Created with
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-12 border-t border-gray-200 pt-6">
|
||||
<p className="text-base text-gray-400 xl:text-center">
|
||||
© 2021 made with{' '}
|
||||
<svg
|
||||
className="mx-1 h-4 w-4 inline align-baseline"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="-mt-0.5 h-5 w-5 inline"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
@ -131,30 +265,22 @@ export function Footer({ useDarkBackground }: FooterProps) {
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>{' '}
|
||||
by
|
||||
<a
|
||||
href="https://nrwl.io"
|
||||
className="text-gray-600 ml-1 point-cursor"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
by{' '}
|
||||
<Link href="https://nrwl.io/?utm_source=nx.dev">
|
||||
<a target="_blank" rel="nofollow">
|
||||
<svg
|
||||
className="inline-block align-bottom ml-1 h-6 w-12 text-white"
|
||||
fill="currentcolor"
|
||||
viewBox="0 0 402.32 125.56"
|
||||
className="-mt-0.5 ml-0.5 w-14 h-auto inline"
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="currentColor"
|
||||
>
|
||||
<g>
|
||||
<polygon points="123.57 110.54 123.57 125.56 146.66 125.56 146.66 112.72 123.57 110.54" />
|
||||
<path d="M95,102.39l-.14,0c-.08-1.78-1.64-3-2.23-3.76a2.31,2.31,0,0,1-.54-1.18h0A27.52,27.52,0,0,0,67,72h0A8.38,8.38,0,0,0,64,68.75a8.43,8.43,0,0,1-3.19-6.63v0a9.41,9.41,0,0,0-8.34,7.36,23.35,23.35,0,0,1-6.32-37.28,30.16,30.16,0,0,1,22-9.42A30.55,30.55,0,0,1,97.73,45.42a15.3,15.3,0,0,1-9.11,5.36A15.15,15.15,0,0,0,76.28,63.32c5.88,0,9.79,8,20.71,8a9.91,9.91,0,0,0,9.18-6.16,9.93,9.93,0,0,0,9.19,6.16,19.61,19.61,0,0,0,8.56-1.9V50.82l-.19,0C119,50,114.27,46.52,112.67,42h0a57.41,57.41,0,1,0-91.78,59.89,11.81,11.81,0,0,1-3.46-1.25,11.4,11.4,0,0,0-6.55-1.5A11.67,11.67,0,0,0,.78,115a33.3,33.3,0,0,1,9.48-2,33.79,33.79,0,0,1,5.7.1h0a29.56,29.56,0,0,0,4.71.07q1.24-.09,2.46-.27a28.79,28.79,0,0,0,9.82-3.4,54.59,54.59,0,0,0,7.35,2.8A74.29,74.29,0,0,0,90.38,109a8.94,8.94,0,0,0,2-1.25,2.94,2.94,0,0,0,1.24.49L165.42,115ZM29.54,47.26c.11-1.54,1.07-2.72,2.14-2.65s1.86,1.39,1.75,2.93-1.07,2.72-2.15,2.65S29.43,48.8,29.54,47.26ZM30,69.66c1.09-.89,3-.36,4.3,1.2s1.44,3.55.35,4.45-3,.36-4.3-1.2S28.94,70.56,30,69.66Zm-5.33-20c.54,0,1,.59,1,1.36s-.38,1.41-.92,1.43-1-.58-1-1.35S24.17,49.66,24.7,49.63Zm-.78,8.86c1-.24,2.18.78,2.53,2.28s-.22,2.92-1.27,3.16-2.18-.77-2.53-2.28S22.87,58.74,23.92,58.49Zm40.78,41.7a2.87,2.87,0,0,1-5.57-1.35c.35-1.46,1.52-.84,3.06-.46S65.05,98.74,64.7,100.19Z" />
|
||||
<polygon points="179.75 43.56 179.75 87.26 142.97 43.56 123.57 43.56 123.57 103.1 146.66 108.56 146.66 81.87 183.44 125.56 202.84 125.56 202.84 43.56 179.75 43.56" />
|
||||
<path d="M244.47,63.19A34.5,34.5,0,0,1,257.15,61v20A48.15,48.15,0,0,0,252,80.7q-7.26,0-11.37,3.86T236.55,96.4v29.16H213.94V62.07h21.54v7.62A21,21,0,0,1,244.47,63.19Z" />
|
||||
<path d="M362.16,62.07l-18.35,63.49h-21.9l-7.53-29.1-8,29.1H284.48L266.13,62.07h21.43l8.59,32.06,9.07-32.06H324.5l8.71,32.41,9.07-32.41Z" />
|
||||
<path d="M393.28,28.64H370.61v74c0,19.88,12.84,22.41,24.89,22.41,3.67,0,6.82-.35,6.82-.35V107.44s-1.31.12-2.75.12c-5.11,0-6.29-2-6.29-7.59Z" />
|
||||
</g>
|
||||
<path d="M3.357 8.258a3.424 3.424 0 00-.845.123l.054-.02a3.437 3.437 0 00-.841.346 3.437 3.437 0 00-.262.168 3.437 3.437 0 00-.11.078 3.424 3.424 0 00-.025.022 3.437 3.437 0 00-.01.005 3.424 3.424 0 00-.103.084 3.437 3.437 0 00-.115.104 3.437 3.437 0 00-.05.045 3.424 3.424 0 00-.08.08 3.424 3.424 0 00-.099.107 3.437 3.437 0 00-.03.034 3.424 3.424 0 00-.071.086 3.437 3.437 0 00-.034.04 3.424 3.424 0 00-.066.088 3.437 3.437 0 00-.006.008 3.424 3.424 0 00-.072.1 3.437 3.437 0 00-.014.02 3.424 3.424 0 00-.082.132 3.424 3.424 0 00-.074.127 3.437 3.437 0 00-.012.026 3.424 3.424 0 00-.062.12 3.424 3.424 0 00-.067.143 3.424 3.424 0 00-.054.135 3.437 3.437 0 00-.008.02 3.424 3.424 0 00-.131.437 3.424 3.424 0 00-.031.152 3.424 3.424 0 00-.026.149 3.437 3.437 0 000 .013 3.424 3.424 0 00-.027.303A3.424 3.424 0 000 11.68a3.437 3.437 0 000 .04 3.424 3.424 0 00.004.124A3.424 3.424 0 00.016 12a3.424 3.424 0 00.015.14 3.437 3.437 0 00.01.057 3.424 3.424 0 00.018.108 3.437 3.437 0 000 .004 3.424 3.424 0 00.025.123 3.437 3.437 0 00.037.15 3.437 3.437 0 00.096.297 3.437 3.437 0 00.056.144 3.437 3.437 0 00.432.745c.014.02.025.024.04.043a3.424 3.424 0 00.007.01 3.424 3.424 0 00.305.33l.011.013c.1.09.16.132.137.129.008.006.02.01.03.018a3.424 3.424 0 00.017.017.711.711 0 01-.205-.08.683.683 0 00-.39-.088.696.696 0 00-.608.947 1.993 1.993 0 01.564-.12 2.088 2.088 0 01.34.007 1.707 1.707 0 00.283.006c.05-.004.098-.01.147-.018a1.714 1.714 0 00.584-.203 3.424 3.424 0 00.437.17 4.43 4.43 0 002.989-.193.528.528 0 00.115-.076.179.179 0 00.076.03l1.789.169v.863H8.75v-.734l1.12.105-4.204-.754a.111.111 0 00-.014-.004c-.01-.1-.095-.172-.13-.218a.134.134 0 01-.03-.07 1.64 1.64 0 00-1.496-1.52.504.504 0 00-.18-.193.503.503 0 01-.187-.4.56.56 0 00-.498.44 1.393 1.393 0 01-.377-2.222 1.798 1.798 0 011.312-.563A1.824 1.824 0 015.83 10.96a.914.914 0 01-.543.32.904.904 0 00-.736.748c.35 0 .585.477 1.236.477a.59.59 0 00.547-.367.592.592 0 00.549.367 1.17 1.17 0 00.49-.106v2.002l1.377.327v-1.592l2.193 2.605H12.1v-4.89h-1.38v2.605L8.53 10.852H7.373v.427c-.283-.05-.556-.255-.65-.52a3.424 3.424 0 00-3.366-2.501zM22.109 9.96v4.414c0 1.186.766 1.336 1.485 1.336.219 0 .406-.02.406-.02v-1.03s-.078.007-.164.007c-.305 0-.375-.12-.375-.453V9.96zm-6.816 1.932a2.057 2.057 0 00-.709.128 1.253 1.253 0 00-.535.385v-.453h-1.285v3.79h1.347v-1.74c0-.316.081-.551.244-.704.164-.154.39-.23.678-.23a2.937 2.937 0 01.307.017v-1.193a2.057 2.057 0 00-.047 0zm.584.06l1.094 3.787h1.306l.477-1.736.45 1.736h1.306l1.094-3.787h-1.186l-.54 1.932-.52-1.932h-1.15l-.542 1.912-.512-1.912zm-12.281 2.14c.03 0 .07.016.117.027.092.023.17.02.15.108a.171.171 0 01-.332-.08c.01-.044.033-.056.065-.055z" />
|
||||
</svg>
|
||||
</a>
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-full text-center">© 2021</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
|
||||
11
nx-dev/ui/common/src/lib/npx-create-nx-workspace.spec.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import NpxCreateNxWorkspace from './npx-create-nx-workspace';
|
||||
|
||||
describe('NpxCreateNxWorkspace', () => {
|
||||
it('should render successfully', () => {
|
||||
const { baseElement } = render(<NpxCreateNxWorkspace />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
568
nx-dev/ui/common/src/lib/npx-create-nx-workspace.tsx
Normal file
@ -0,0 +1,568 @@
|
||||
import { AnimateSharedLayout, motion, useAnimation } from 'framer-motion';
|
||||
|
||||
const typing = (line: string, delay: number = 0): any[] =>
|
||||
Array.from(line).map((char, index) => (
|
||||
<motion.span
|
||||
key={[char, index].join('-')}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{
|
||||
delay: index * 0.04 + delay,
|
||||
ease: 'linear',
|
||||
duration: 0.1,
|
||||
}}
|
||||
>
|
||||
{char}
|
||||
</motion.span>
|
||||
));
|
||||
|
||||
export function NpxCreateNxWorkspace() {
|
||||
const npxCreateNxWorkspace = useAnimation();
|
||||
const wrapper = useAnimation();
|
||||
const firstLoading = useAnimation();
|
||||
const frameworkSelectionTitle = useAnimation();
|
||||
const frameworkSelectionAnswerSection = useAnimation();
|
||||
const frameworkSelectionAnswerSectionArrow = useAnimation();
|
||||
const frameworkSelectionAnswerSectionPreviousHighlight = useAnimation();
|
||||
const frameworkSelectionAnswerSectionNextHighlight = useAnimation();
|
||||
const frameworkSelectionAnswerValidation = useAnimation();
|
||||
const applicationName = useAnimation();
|
||||
const stylesheetSelectionTitle = useAnimation();
|
||||
const stylesheetSelectionAnswerSection = useAnimation();
|
||||
const stylesheetSelectionAnswerSectionArrow = useAnimation();
|
||||
const stylesheetSelectionAnswerSectionPreviousHighlight = useAnimation();
|
||||
const stylesheetSelectionAnswerSectionNextHighlight = useAnimation();
|
||||
const stylesheetSelectionAnswerValidation = useAnimation();
|
||||
const nxCloudSelectionTitle = useAnimation();
|
||||
const nxCloudSelectionAnswerSection = useAnimation();
|
||||
const nxCloudSelectionAnswerSectionArrow = useAnimation();
|
||||
const nxCloudSelectionAnswerSectionPreviousHighlight = useAnimation();
|
||||
const nxCloudSelectionAnswerSectionNextHighlight = useAnimation();
|
||||
const nxCloudSelectionAnswerValidation = useAnimation();
|
||||
const creatingNxWorkspace = useAnimation();
|
||||
const creatingNxWorkspace2 = useAnimation();
|
||||
const secondLoading = useAnimation();
|
||||
const workpaceReady = useAnimation();
|
||||
|
||||
const sequence = async () => {
|
||||
await npxCreateNxWorkspace.start({
|
||||
opacity: 1,
|
||||
transition: {
|
||||
ease: 'easeOut',
|
||||
duration: 0.12,
|
||||
},
|
||||
});
|
||||
await firstLoading.start({
|
||||
width: '100%',
|
||||
transition: { delay: 2.4, ease: 'easeOut', duration: 0.24 },
|
||||
});
|
||||
await frameworkSelectionSequence();
|
||||
await applicationName.start({
|
||||
opacity: 1,
|
||||
transition: {
|
||||
ease: 'easeOut',
|
||||
duration: 0.2,
|
||||
},
|
||||
});
|
||||
await stylesheetSelectionSequence(1.8);
|
||||
await nxCloudSelectionSequence();
|
||||
await creatingNxWorkspace.start({
|
||||
opacity: 1,
|
||||
transition: {
|
||||
ease: 'easeOut',
|
||||
duration: 0.2,
|
||||
},
|
||||
});
|
||||
await creatingNxWorkspace2.start({
|
||||
opacity: 1,
|
||||
transition: {
|
||||
ease: 'easeOut',
|
||||
duration: 0.2,
|
||||
},
|
||||
});
|
||||
await secondLoading.start({
|
||||
width: '100%',
|
||||
transition: { ease: 'easeOut', duration: 0.24 },
|
||||
});
|
||||
workpaceReady.start({
|
||||
opacity: 1,
|
||||
transition: { ease: 'easeOut', duration: 0.24 },
|
||||
});
|
||||
return await wrapper.start({
|
||||
y: -82,
|
||||
transition: { ease: 'easeOut', duration: 0.24 },
|
||||
});
|
||||
};
|
||||
|
||||
const frameworkSelectionSequence = async (delay: number = 0) => {
|
||||
await frameworkSelectionTitle.start({
|
||||
opacity: 1,
|
||||
transition: {
|
||||
ease: 'easeOut',
|
||||
delay,
|
||||
duration: 0.2,
|
||||
},
|
||||
});
|
||||
await frameworkSelectionAnswerSection.start({
|
||||
opacity: 1,
|
||||
transition: {
|
||||
ease: 'easeOut',
|
||||
duration: 0.12,
|
||||
},
|
||||
});
|
||||
await frameworkSelectionAnswerSectionArrow.start({
|
||||
y: 36,
|
||||
transition: { ease: 'easeOut', duration: 0.24 },
|
||||
});
|
||||
await frameworkSelectionAnswerSectionPreviousHighlight.start({
|
||||
color: '#E5E7EB',
|
||||
transition: { ease: 'easeOut', duration: 0.12 },
|
||||
});
|
||||
await frameworkSelectionAnswerSectionNextHighlight.start({
|
||||
color: '#34D399',
|
||||
transition: { ease: 'easeOut', duration: 0.12 },
|
||||
});
|
||||
await frameworkSelectionAnswerSection.start({
|
||||
opacity: 0,
|
||||
transition: {
|
||||
delay: 2,
|
||||
ease: 'easeOut',
|
||||
duration: 0.12,
|
||||
},
|
||||
transitionEnd: {
|
||||
display: 'none',
|
||||
},
|
||||
});
|
||||
return frameworkSelectionAnswerValidation.start({
|
||||
opacity: 1,
|
||||
transition: { ease: 'easeOut', duration: 0.24 },
|
||||
});
|
||||
};
|
||||
const stylesheetSelectionSequence = async (delay: number = 0) => {
|
||||
await stylesheetSelectionTitle.start({
|
||||
opacity: 1,
|
||||
transition: {
|
||||
delay,
|
||||
ease: 'easeOut',
|
||||
duration: 0.2,
|
||||
},
|
||||
});
|
||||
await stylesheetSelectionAnswerSection.start({
|
||||
opacity: 1,
|
||||
transition: {
|
||||
ease: 'easeOut',
|
||||
duration: 0.12,
|
||||
},
|
||||
});
|
||||
await stylesheetSelectionAnswerSectionArrow.start({
|
||||
y: 72,
|
||||
transition: { ease: 'easeOut', duration: 0.42 },
|
||||
});
|
||||
await stylesheetSelectionAnswerSectionPreviousHighlight.start({
|
||||
color: '#E5E7EB',
|
||||
transition: { ease: 'easeOut', duration: 0.12 },
|
||||
});
|
||||
await stylesheetSelectionAnswerSectionNextHighlight.start({
|
||||
color: '#34D399',
|
||||
transition: { ease: 'easeOut', duration: 0.12 },
|
||||
});
|
||||
await stylesheetSelectionAnswerSection.start({
|
||||
opacity: 0,
|
||||
transition: {
|
||||
delay: 2,
|
||||
ease: 'easeOut',
|
||||
duration: 0.12,
|
||||
},
|
||||
transitionEnd: {
|
||||
display: 'none',
|
||||
},
|
||||
});
|
||||
return stylesheetSelectionAnswerValidation.start({
|
||||
opacity: 1,
|
||||
transition: { ease: 'easeOut', duration: 0.24 },
|
||||
});
|
||||
};
|
||||
const nxCloudSelectionSequence = async (delay: number = 0) => {
|
||||
await nxCloudSelectionTitle.start({
|
||||
opacity: 1,
|
||||
transition: {
|
||||
delay,
|
||||
ease: 'easeOut',
|
||||
duration: 0.2,
|
||||
},
|
||||
});
|
||||
await nxCloudSelectionAnswerSection.start({
|
||||
opacity: 1,
|
||||
transition: {
|
||||
ease: 'easeOut',
|
||||
duration: 0.12,
|
||||
},
|
||||
});
|
||||
await nxCloudSelectionAnswerSectionArrow.start({
|
||||
y: 0,
|
||||
transition: { ease: 'easeOut', duration: 0.24 },
|
||||
});
|
||||
await nxCloudSelectionAnswerSectionPreviousHighlight.start({
|
||||
color: '#E5E7EB',
|
||||
transition: { ease: 'easeOut', duration: 0.12 },
|
||||
});
|
||||
await nxCloudSelectionAnswerSectionNextHighlight.start({
|
||||
color: '#34D399',
|
||||
transition: { ease: 'easeOut', duration: 0.12 },
|
||||
});
|
||||
await nxCloudSelectionAnswerSection.start({
|
||||
opacity: 0,
|
||||
transition: {
|
||||
delay: 2,
|
||||
ease: 'easeOut',
|
||||
duration: 0.12,
|
||||
},
|
||||
transitionEnd: {
|
||||
display: 'none',
|
||||
},
|
||||
});
|
||||
return nxCloudSelectionAnswerValidation.start({
|
||||
opacity: 1,
|
||||
transition: { ease: 'easeOut', duration: 0.24 },
|
||||
});
|
||||
};
|
||||
|
||||
sequence();
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className="pt-4 shadow-lg text-gray-200 text-xs font-mono subpixel-antialiased
|
||||
bg-gray-800 pb-6 pt-4 rounded-lg leading-normal max-w-full overflow-hidden h-96"
|
||||
>
|
||||
<div className="px-5 top mb-2 flex">
|
||||
<div className="h-3 w-3 bg-red-500 rounded-full" />
|
||||
<div className="ml-2 h-3 w-3 bg-yellow-300 rounded-full" />
|
||||
<div className="ml-2 h-3 w-3 bg-green-500 rounded-full" />
|
||||
</div>
|
||||
<div className="px-5 overflow-y-hidden">
|
||||
<motion.div initial={{ y: 0 }} animate={wrapper}>
|
||||
<div className="mt-4 flex">
|
||||
<span className="text-green-nx-base mr-2">/workspace ➜</span>
|
||||
<motion.p
|
||||
initial={{ opacity: 0 }}
|
||||
animate={npxCreateNxWorkspace}
|
||||
className="flex-1 typing items-center"
|
||||
>
|
||||
{typing('npx create-nx-workspace ludicrous-narwhals').map(
|
||||
(x) => x
|
||||
)}
|
||||
</motion.p>
|
||||
</div>
|
||||
<div className="mt-2 flex flex-col">
|
||||
<AnimateSharedLayout>
|
||||
{/*LOADING*/}
|
||||
<motion.div
|
||||
className="inline-block items-center bg-green-nx-base"
|
||||
initial={{ width: '0%', height: '12px' }}
|
||||
animate={firstLoading}
|
||||
/>
|
||||
{/*FRAMEWORK SELECTION*/}
|
||||
<motion.div
|
||||
className="mt-2 flex-1 items-center"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={frameworkSelectionTitle}
|
||||
>
|
||||
What to create in the new workspace{' '}
|
||||
<motion.span
|
||||
className="text-green-nx-base"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={frameworkSelectionAnswerValidation}
|
||||
>
|
||||
react [a workspace with a single React application]
|
||||
</motion.span>
|
||||
</motion.div>
|
||||
<motion.div
|
||||
className="mt-2 relative"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={frameworkSelectionAnswerSection}
|
||||
>
|
||||
{/*SELECTION ARROW*/}
|
||||
<motion.div
|
||||
className="absolute -left-4 top-0 text-green-nx-base"
|
||||
initial={{ y: 0 }}
|
||||
animate={frameworkSelectionAnswerSectionArrow}
|
||||
>
|
||||
❯
|
||||
</motion.div>
|
||||
<motion.span
|
||||
initial={{ color: '#34D399' }}
|
||||
animate={frameworkSelectionAnswerSectionPreviousHighlight}
|
||||
>
|
||||
empty [an empty workspace with a layout that works best for
|
||||
building apps]
|
||||
</motion.span>
|
||||
<br />
|
||||
<motion.span
|
||||
initial={{ color: '#E5E7EB' }}
|
||||
animate={frameworkSelectionAnswerSectionNextHighlight}
|
||||
>
|
||||
react [a workspace with a single React application]
|
||||
</motion.span>
|
||||
<br />
|
||||
angular [a workspace with a single Angular application]
|
||||
<br />
|
||||
next.js [a workspace with a single Next.js application]
|
||||
<br />
|
||||
nest [a workspace with a single Nest application]
|
||||
<br />
|
||||
express [a workspace with a single Express application]
|
||||
<br />
|
||||
web components [a workspace with a single app built using web
|
||||
components]
|
||||
<br />
|
||||
<span className="text-gray-500">(Use arrow keys)</span>
|
||||
</motion.div>
|
||||
{/*APPLICATION NAME*/}
|
||||
<motion.div
|
||||
className="flex-1 items-center"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={applicationName}
|
||||
>
|
||||
Application name{' '}
|
||||
<span className="text-green-nx-base">
|
||||
{typing('tuxboard', 7).map((x) => x)}
|
||||
</span>
|
||||
</motion.div>
|
||||
{/*STYLESHEET FORMAT*/}
|
||||
<motion.div
|
||||
className="flex-1 items-center"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={stylesheetSelectionTitle}
|
||||
>
|
||||
Default stylesheet format{' '}
|
||||
<motion.span
|
||||
className="text-green-nx-base"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={stylesheetSelectionAnswerValidation}
|
||||
>
|
||||
styled-components [
|
||||
<a
|
||||
href="https://styled-components.com"
|
||||
target="_blank"
|
||||
rel="nofollow"
|
||||
className="cursor-pointer opacity-50 hover:underline hover:opacity-100"
|
||||
>
|
||||
https://styled-components.com
|
||||
</a>
|
||||
]
|
||||
</motion.span>
|
||||
</motion.div>
|
||||
<motion.div
|
||||
className="mt-2 relative"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={stylesheetSelectionAnswerSection}
|
||||
>
|
||||
{/*SELECTION ARROW*/}
|
||||
<motion.div
|
||||
className="absolute -left-4 top-0 text-green-nx-base"
|
||||
initial={{ y: 0 }}
|
||||
animate={stylesheetSelectionAnswerSectionArrow}
|
||||
>
|
||||
❯
|
||||
</motion.div>
|
||||
<motion.span
|
||||
initial={{ color: '#34D399' }}
|
||||
animate={stylesheetSelectionAnswerSectionPreviousHighlight}
|
||||
>
|
||||
CSS
|
||||
</motion.span>
|
||||
<br />
|
||||
SASS(.scss) [
|
||||
<a
|
||||
href="https://sass-lang.com"
|
||||
target="_blank"
|
||||
rel="nofollow"
|
||||
className="cursor-pointer opacity-50 hover:underline hover:opacity-100"
|
||||
>
|
||||
https://sass-lang.com
|
||||
</a>
|
||||
] <br />
|
||||
Stylus(.styl)[
|
||||
<a
|
||||
href="https://stylus-lang.com"
|
||||
target="_blank"
|
||||
rel="nofollow"
|
||||
className="cursor-pointer opacity-50 hover:underline hover:opacity-100"
|
||||
>
|
||||
https://stylus-lang.com
|
||||
</a>
|
||||
] <br />
|
||||
LESS [
|
||||
<a
|
||||
href="https://lesscss.org"
|
||||
target="_blank"
|
||||
rel="nofollow"
|
||||
className="cursor-pointer opacity-50 hover:underline hover:opacity-100"
|
||||
>
|
||||
https://lesscss.org
|
||||
</a>
|
||||
] <br />
|
||||
<motion.span
|
||||
initial={{ color: '#E5E7EB' }}
|
||||
animate={stylesheetSelectionAnswerSectionNextHighlight}
|
||||
>
|
||||
styled-components [
|
||||
<a
|
||||
href="https://styled-components.com"
|
||||
target="_blank"
|
||||
rel="nofollow"
|
||||
className="cursor-pointer opacity-50 hover:underline hover:opacity-100"
|
||||
>
|
||||
https://styled-components.com
|
||||
</a>
|
||||
]
|
||||
</motion.span>
|
||||
<br />
|
||||
emotion [
|
||||
<a
|
||||
href="https://emotion.sh"
|
||||
target="_blank"
|
||||
rel="nofollow"
|
||||
className="cursor-pointer opacity-50 hover:underline hover:opacity-100"
|
||||
>
|
||||
https://emotion.sh
|
||||
</a>
|
||||
] <br />
|
||||
styled-jsx [
|
||||
<a
|
||||
href="https://www.npmjs.com/package/styled-jsx"
|
||||
target="_blank"
|
||||
rel="nofollow"
|
||||
className="cursor-pointer opacity-50 hover:underline hover:opacity-100"
|
||||
>
|
||||
https://www.npmjs.com/package/styled-jsx
|
||||
</a>
|
||||
] <br />
|
||||
<span className="text-gray-500">(Use arrow keys)</span>
|
||||
</motion.div>
|
||||
{/*NX CLOUD*/}
|
||||
<motion.div
|
||||
layout
|
||||
className="flex-1 items-center"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={nxCloudSelectionTitle}
|
||||
>
|
||||
Use Nx Cloud? (It's free and doesn't require registration.){' '}
|
||||
<motion.span
|
||||
className="text-green-nx-base"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={nxCloudSelectionAnswerValidation}
|
||||
>
|
||||
Yes
|
||||
</motion.span>
|
||||
</motion.div>
|
||||
<motion.div
|
||||
className="mt-2 relative"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={nxCloudSelectionAnswerSection}
|
||||
>
|
||||
{/*SELECTION ARROW*/}
|
||||
<motion.div
|
||||
className="absolute -left-4 top-0 text-green-nx-base"
|
||||
initial={{ y: 18 }}
|
||||
animate={nxCloudSelectionAnswerSectionArrow}
|
||||
>
|
||||
❯
|
||||
</motion.div>
|
||||
<motion.span
|
||||
initial={{ color: '#E5E7EB' }}
|
||||
animate={nxCloudSelectionAnswerSectionNextHighlight}
|
||||
>
|
||||
Yes
|
||||
</motion.span>
|
||||
<br />
|
||||
<motion.span
|
||||
initial={{ color: '#34D399' }}
|
||||
animate={nxCloudSelectionAnswerSectionPreviousHighlight}
|
||||
>
|
||||
No
|
||||
</motion.span>
|
||||
<br />
|
||||
<span className="text-gray-500">(Use arrow keys)</span>
|
||||
</motion.div>
|
||||
{/*CREATING NX WORKSPACE*/}
|
||||
<motion.div
|
||||
layout
|
||||
className="mt-2"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={creatingNxWorkspace}
|
||||
>
|
||||
<span className="px-1 py-0.5 bg-green-nx-base">NX</span> Nx is
|
||||
creating your workspace. To make sure the command works
|
||||
reliably in all environments, and that the preset is applied
|
||||
correctly, Nx will run "yarn install" several times. Please
|
||||
wait.
|
||||
</motion.div>
|
||||
<motion.div
|
||||
layout
|
||||
className="mt-2"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={creatingNxWorkspace2}
|
||||
>
|
||||
Creating your workspace
|
||||
</motion.div>
|
||||
{/*LOADING*/}
|
||||
<motion.div
|
||||
layout
|
||||
className="mt-2 items-center bg-green-nx-base"
|
||||
initial={{ width: '0%', height: '12px' }}
|
||||
animate={secondLoading}
|
||||
/>
|
||||
{/*NX WORKSPACE CREATED*/}
|
||||
<motion.div
|
||||
layout
|
||||
className="mt-2"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={workpaceReady}
|
||||
>
|
||||
<div>
|
||||
<span className="px-1 py-0.5 bg-green-nx-base">
|
||||
NX SUCCESS
|
||||
</span>{' '}
|
||||
Nx has successfully created the workspace.
|
||||
</div>
|
||||
<div className="my-3 w-full h-px bg-gray-100" />
|
||||
<div>
|
||||
<span className="px-1 py-0.5 bg-green-nx-base">NX</span>
|
||||
<span className="ml-1 px-1 py-0.5 bg-yellow-500">
|
||||
NOTE
|
||||
</span>{' '}
|
||||
First time using Nx? Check out this interactive Nx tutorial.
|
||||
<br />
|
||||
<a
|
||||
href="https://nx.dev/react/tutorial/01-create-application"
|
||||
target="_blank"
|
||||
rel="nofollow"
|
||||
className="cursor-pointer opacity-50 hover:underline hover:opacity-100"
|
||||
>
|
||||
https://nx.dev/react/tutorial/01-create-application
|
||||
</a>
|
||||
<br />
|
||||
Prefer watching videos? Check out this free Nx course on
|
||||
Egghead.io.
|
||||
<br />
|
||||
<a
|
||||
href="https://egghead.io/playlists/scale-react-development-with-nx-4038"
|
||||
target="_blank"
|
||||
rel="nofollow"
|
||||
className="cursor-pointer opacity-50 hover:underline hover:opacity-100"
|
||||
>
|
||||
https://egghead.io/playlists/scale-react-development-with-nx-4038
|
||||
</a>
|
||||
</div>
|
||||
</motion.div>
|
||||
</AnimateSharedLayout>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default NpxCreateNxWorkspace;
|
||||
112
nx-dev/ui/common/src/lib/testimonials.tsx
Normal file
@ -0,0 +1,112 @@
|
||||
import React from 'react';
|
||||
|
||||
export function Testimonials() {
|
||||
return (
|
||||
<section className="bg-blue-nx-base">
|
||||
<div className="max-w-7xl mx-auto md:grid md:grid-cols-2 md:px-6 lg:px-8">
|
||||
<div className="py-12 px-4 sm:px-6 md:flex md:flex-col md:py-16 md:pl-0 md:pr-10 md:border-r md:border-blue-nx-dark lg:pr-16">
|
||||
<div className="md:flex-shrink-0">
|
||||
<div className="mx-auto flex items-center text-white font-mono tracking-wider">
|
||||
<svg
|
||||
role="img"
|
||||
className="w-8 h-8"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path d="M1.125 0C.502 0 0 .502 0 1.125v21.75C0 23.498.502 24 1.125 24h21.75c.623 0 1.125-.502 1.125-1.125V1.125C24 .502 23.498 0 22.875 0zm17.363 9.75c.612 0 1.154.037 1.627.111a6.38 6.38 0 0 1 1.306.34v2.458a3.95 3.95 0 0 0-.643-.361 5.093 5.093 0 0 0-.717-.26 5.453 5.453 0 0 0-1.426-.2c-.3 0-.573.028-.819.086a2.1 2.1 0 0 0-.623.242c-.17.104-.3.229-.393.374a.888.888 0 0 0-.14.49c0 .196.053.373.156.529.104.156.252.304.443.444s.423.276.696.41c.273.135.582.274.926.416.47.197.892.407 1.266.628.374.222.695.473.963.753.268.279.472.598.614.957.142.359.214.776.214 1.253 0 .657-.125 1.21-.373 1.656a3.033 3.033 0 0 1-1.012 1.085 4.38 4.38 0 0 1-1.487.596c-.566.12-1.163.18-1.79.18a9.916 9.916 0 0 1-1.84-.164 5.544 5.544 0 0 1-1.512-.493v-2.63a5.033 5.033 0 0 0 3.237 1.2c.333 0 .624-.03.872-.09.249-.06.456-.144.623-.25.166-.108.29-.234.373-.38a1.023 1.023 0 0 0-.074-1.089 2.12 2.12 0 0 0-.537-.5 5.597 5.597 0 0 0-.807-.444 27.72 27.72 0 0 0-1.007-.436c-.918-.383-1.602-.852-2.053-1.405-.45-.553-.676-1.222-.676-2.005 0-.614.123-1.141.369-1.582.246-.441.58-.804 1.004-1.089a4.494 4.494 0 0 1 1.47-.629 7.536 7.536 0 0 1 1.77-.201zm-15.113.188h9.563v2.166H9.506v9.646H6.789v-9.646H3.375z" />
|
||||
</svg>
|
||||
<span className="ml-2 font-bold ">TypeScript-ESLint</span>
|
||||
</div>
|
||||
</div>
|
||||
<blockquote className="mt-6 md:flex-grow md:flex md:flex-col">
|
||||
<div className="relative text-lg font-medium text-white md:flex-grow">
|
||||
<svg
|
||||
className="hidden md:flex absolute top-0 left-0 transform -translate-x-4 -translate-y-4 h-8 w-8 text-green-nx-base"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 32 32"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M9.352 4C4.456 7.456 1 13.12 1 19.36c0 5.088 3.072 8.064 6.624 8.064 3.36 0 5.856-2.688 5.856-5.856 0-3.168-2.208-5.472-5.088-5.472-.576 0-1.344.096-1.536.192.48-3.264 3.552-7.104 6.624-9.024L9.352 4zm16.512 0c-4.8 3.456-8.256 9.12-8.256 15.36 0 5.088 3.072 8.064 6.624 8.064 3.264 0 5.856-2.688 5.856-5.856 0-3.168-2.304-5.472-5.184-5.472-.576 0-1.248.096-1.44.192.48-3.264 3.456-7.104 6.528-9.024L25.864 4z" />
|
||||
</svg>
|
||||
<p className="relative">
|
||||
Nx is good good blah blah, I use it everyday.
|
||||
</p>
|
||||
</div>
|
||||
<footer className="mt-8">
|
||||
<div className="flex items-start">
|
||||
<div className="flex-shrink-0 inline-flex rounded-full border-2 border-white">
|
||||
<img
|
||||
className="h-12 w-12 rounded-full"
|
||||
src="https://avatars.githubusercontent.com/u/900523?v=4"
|
||||
alt="James Henry avatar"
|
||||
/>
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<div className="text-base font-medium text-white">
|
||||
James Henry
|
||||
</div>
|
||||
<div className="text-base font-medium text-gray-300">
|
||||
Software Architect, TypeScript-ESLint
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</blockquote>
|
||||
</div>
|
||||
<div className="py-12 px-4 border-t-2 border-blue-nx-dark sm:px-6 md:py-16 md:pr-0 md:pl-10 md:border-t-0 md:border-l lg:pl-16">
|
||||
<div className="md:flex-shrink-0">
|
||||
<div className="mx-auto flex items-center text-white font-mono tracking-wider">
|
||||
<svg
|
||||
className="w-10 h-auto"
|
||||
fill="currentColor"
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M16.71.243l-.12 2.71a.18.18 0 00.29.15l1.06-.8.9.7a.18.18 0 00.28-.14l-.1-2.76 1.33-.1a1.2 1.2 0 011.279 1.2v21.596a1.2 1.2 0 01-1.26 1.2l-16.096-.72a1.2 1.2 0 01-1.15-1.16l-.75-19.797a1.2 1.2 0 011.13-1.27L16.7.222zM13.64 9.3c0 .47 3.16.24 3.59-.08 0-3.2-1.72-4.89-4.859-4.89-3.15 0-4.899 1.72-4.899 4.29 0 4.45 5.999 4.53 5.999 6.959 0 .7-.32 1.1-1.05 1.1-.96 0-1.35-.49-1.3-2.16 0-.36-3.649-.48-3.769 0-.27 4.03 2.23 5.2 5.099 5.2 2.79 0 4.969-1.49 4.969-4.18 0-4.77-6.099-4.64-6.099-6.999 0-.97.72-1.1 1.13-1.1.45 0 1.25.07 1.19 1.87z" />
|
||||
</svg>
|
||||
<span className="ml-2 font-bold ">Storybook</span>
|
||||
</div>
|
||||
</div>
|
||||
<blockquote className="mt-6 md:flex-grow md:flex md:flex-col">
|
||||
<div className="relative text-lg font-medium text-white md:flex-grow">
|
||||
<svg
|
||||
className="hidden md:flex absolute top-0 left-0 transform -translate-x-4 -translate-y-4 h-8 w-8 text-green-nx-base"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 32 32"
|
||||
>
|
||||
<path d="M9.352 4C4.456 7.456 1 13.12 1 19.36c0 5.088 3.072 8.064 6.624 8.064 3.36 0 5.856-2.688 5.856-5.856 0-3.168-2.208-5.472-5.088-5.472-.576 0-1.344.096-1.536.192.48-3.264 3.552-7.104 6.624-9.024L9.352 4zm16.512 0c-4.8 3.456-8.256 9.12-8.256 15.36 0 5.088 3.072 8.064 6.624 8.064 3.264 0 5.856-2.688 5.856-5.856 0-3.168-2.304-5.472-5.184-5.472-.576 0-1.248.096-1.44.192.48-3.264 3.456-7.104 6.528-9.024L25.864 4z" />
|
||||
</svg>
|
||||
<p className="relative">
|
||||
Nx is good good blah blah blah, saves me $$ from CI with
|
||||
NxCloud.
|
||||
</p>
|
||||
</div>
|
||||
<footer className="mt-8">
|
||||
<div className="flex items-start">
|
||||
<div className="flex-shrink-0 inline-flex rounded-full border-2 border-white">
|
||||
<img
|
||||
className="h-12 w-12 rounded-full"
|
||||
src="https://images.unsplash.com/photo-1489424731084-a5d8b219a5bb?ixlib=rb-0.3.5&q=80&fm=jpg&crop=faces&fit=crop&h=200&w=200&s=8cc7a3620510c32066d3fbb193e7eb23"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<div className="text-base font-medium text-white">
|
||||
Jane Doe
|
||||
</div>
|
||||
<div className="text-base font-medium text-gray-300">
|
||||
CEO, Storybook
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</blockquote>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default Testimonials;
|
||||
@ -121,7 +121,6 @@
|
||||
"angular": "1.8.0",
|
||||
"autoprefixer": "^10.2.5",
|
||||
"babel-jest": "27.2.3",
|
||||
"caniuse-lite": "^1.0.30001251",
|
||||
"chalk": "4.1.0",
|
||||
"chokidar": "^3.5.1",
|
||||
"commitizen": "^4.0.3",
|
||||
@ -273,14 +272,18 @@
|
||||
"@docsearch/react": "^1.0.0-alpha.14",
|
||||
"@headlessui/react": "^1.1.1",
|
||||
"@heroicons/react": "^1.0.1",
|
||||
"@tailwindcss/aspect-ratio": "^0.3.0",
|
||||
"@tailwindcss/forms": "^0.3.4",
|
||||
"classnames": "^2.3.1",
|
||||
"core-js": "^3.6.5",
|
||||
"framer-motion": "^4.1.17",
|
||||
"glob": "7.1.4",
|
||||
"gray-matter": "^4.0.2",
|
||||
"npm-run-path": "^4.0.1",
|
||||
"react": "17.0.2",
|
||||
"react-copy-to-clipboard": "^5.0.3",
|
||||
"react-dom": "17.0.2",
|
||||
"react-intersection-observer": "^8.32.2",
|
||||
"react-markdown": "^6.0.2",
|
||||
"react-syntax-highlighter": "^15.4.3",
|
||||
"regenerator-runtime": "0.13.7",
|
||||
@ -296,4 +299,3 @@
|
||||
"**/xmlhttprequest-ssl": "~1.6.2"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -55,6 +55,8 @@
|
||||
"@nrwl/nx-dev/feature-versions-and-flavors": [
|
||||
"./nx-dev/feature-versions-and-flavors/src/index.ts"
|
||||
],
|
||||
"@nrwl/nx-dev/ui-commands": ["./nx-dev/ui-commands/src/index.ts"],
|
||||
"@nrwl/nx-dev/ui-home": ["./nx-dev/ui-home/src/index.ts"],
|
||||
"@nrwl/nx-dev/ui/common": ["./nx-dev/ui/common/src/index.ts"],
|
||||
"@nrwl/nx-dev/ui/member-card": ["./nx-dev/ui/member-card/src/index.ts"],
|
||||
"@nrwl/nx-dev/ui/sponsor-card": ["./nx-dev/ui/sponsor-card/src/index.ts"],
|
||||
|
||||
@ -49,7 +49,9 @@
|
||||
"nx-dev-feature-search": "nx-dev/feature-search",
|
||||
"nx-dev-feature-storage": "nx-dev/feature-storage",
|
||||
"nx-dev-feature-versions-and-flavors": "nx-dev/feature-versions-and-flavors",
|
||||
"nx-dev-ui-commands": "nx-dev/ui-commands",
|
||||
"nx-dev-ui-common": "nx-dev/ui/common",
|
||||
"nx-dev-ui-home": "nx-dev/ui-home",
|
||||
"nx-dev-ui-member-card": "nx-dev/ui/member-card",
|
||||
"nx-dev-ui-sponsor-card": "nx-dev/ui/sponsor-card",
|
||||
"nx-plugin": "packages/nx-plugin",
|
||||
|
||||
90
yarn.lock
@ -1873,7 +1873,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
|
||||
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
|
||||
|
||||
"@emotion/is-prop-valid@0.8.8", "@emotion/is-prop-valid@^0.8.3", "@emotion/is-prop-valid@^0.8.6":
|
||||
"@emotion/is-prop-valid@0.8.8", "@emotion/is-prop-valid@^0.8.2", "@emotion/is-prop-valid@^0.8.3", "@emotion/is-prop-valid@^0.8.6":
|
||||
version "0.8.8"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a"
|
||||
integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==
|
||||
@ -4193,6 +4193,18 @@
|
||||
dependencies:
|
||||
defer-to-connect "^2.0.0"
|
||||
|
||||
"@tailwindcss/aspect-ratio@^0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@tailwindcss/aspect-ratio/-/aspect-ratio-0.3.0.tgz#f779ab3f07cac848fb844122d6662ba6560010b8"
|
||||
integrity sha512-DMgWskNJR6FNPLbQ8Xoq/PKV/9DfNKh5dvKB+SM8x7lVl4+pnxlZ3Ns4+yGmurA/ze708HrnCG1tXk85HolJmw==
|
||||
|
||||
"@tailwindcss/forms@^0.3.4":
|
||||
version "0.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.3.4.tgz#e4939dc16450eccf4fd2029770096f38cbb556d4"
|
||||
integrity sha512-vlAoBifNJUkagB+PAdW4aHMe4pKmSLroH398UPgIogBFc91D2VlHUxe4pjxQhiJl0Nfw53sHSJSQBSTQBZP3vA==
|
||||
dependencies:
|
||||
mini-svg-data-uri "^1.2.3"
|
||||
|
||||
"@tailwindcss/typography@^0.4.1":
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.4.1.tgz#51ddbceea6a0ee9902c649dbe58871c81a831212"
|
||||
@ -7133,10 +7145,15 @@ caniuse-api@^3.0.0:
|
||||
lodash.memoize "^4.1.2"
|
||||
lodash.uniq "^4.5.0"
|
||||
|
||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001032, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001125, caniuse-lite@^1.0.30001202, caniuse-lite@^1.0.30001219, caniuse-lite@^1.0.30001228, caniuse-lite@^1.0.30001251, caniuse-lite@^1.0.30001272, caniuse-lite@^1.0.30001274:
|
||||
version "1.0.30001279"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001279.tgz#eb06818da481ef5096a3b3760f43e5382ed6b0ce"
|
||||
integrity sha512-VfEHpzHEXj6/CxggTwSFoZBBYGQfQv9Cf42KPlO79sWXCD1QNKWKsKzFeWL7QpZHJQYAvocqV6Rty1yJMkqWLQ==
|
||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001032, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001125, caniuse-lite@^1.0.30001202, caniuse-lite@^1.0.30001219, caniuse-lite@^1.0.30001228, caniuse-lite@^1.0.30001251:
|
||||
version "1.0.30001271"
|
||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz"
|
||||
integrity sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA==
|
||||
|
||||
caniuse-lite@^1.0.30001272, caniuse-lite@^1.0.30001274:
|
||||
version "1.0.30001280"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001280.tgz#066a506046ba4be34cde5f74a08db7a396718fb7"
|
||||
integrity sha512-kFXwYvHe5rix25uwueBxC569o53J6TpnGu0BEEn+6Lhl2vsnAumRFWEBhDft1fwyo6m1r4i+RqA4+163FpeFcA==
|
||||
|
||||
canonical-path@1.0.0:
|
||||
version "1.0.0"
|
||||
@ -11141,6 +11158,26 @@ fragment-cache@^0.2.1:
|
||||
dependencies:
|
||||
map-cache "^0.2.2"
|
||||
|
||||
framer-motion@^4.1.17:
|
||||
version "4.1.17"
|
||||
resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-4.1.17.tgz#4029469252a62ea599902e5a92b537120cc89721"
|
||||
integrity sha512-thx1wvKzblzbs0XaK2X0G1JuwIdARcoNOW7VVwjO8BUltzXPyONGAElLu6CiCScsOQRI7FIk/45YTFtJw5Yozw==
|
||||
dependencies:
|
||||
framesync "5.3.0"
|
||||
hey-listen "^1.0.8"
|
||||
popmotion "9.3.6"
|
||||
style-value-types "4.1.4"
|
||||
tslib "^2.1.0"
|
||||
optionalDependencies:
|
||||
"@emotion/is-prop-valid" "^0.8.2"
|
||||
|
||||
framesync@5.3.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/framesync/-/framesync-5.3.0.tgz#0ecfc955e8f5a6ddc8fdb0cc024070947e1a0d9b"
|
||||
integrity sha512-oc5m68HDO/tuK2blj7ZcdEBRx3p1PjrgHazL8GYEpvULhrtGIFbQArN6cQS2QhW8mitffaB+VYzMjDqBxxQeoA==
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
fresh@0.5.2:
|
||||
version "0.5.2"
|
||||
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
|
||||
@ -12054,10 +12091,20 @@ hex-color-regex@^1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
|
||||
integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==
|
||||
|
||||
highlight.js@^10.1.1, highlight.js@^10.4.1, highlight.js@~10.7.0:
|
||||
version "10.7.3"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531"
|
||||
integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==
|
||||
hey-listen@^1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/hey-listen/-/hey-listen-1.0.8.tgz#8e59561ff724908de1aa924ed6ecc84a56a9aa68"
|
||||
integrity sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==
|
||||
|
||||
highlight.js@^10.1.1:
|
||||
version "10.6.0"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.6.0.tgz#0073aa71d566906965ba6e1b7be7b2682f5e18b6"
|
||||
integrity sha512-8mlRcn5vk/r4+QcqerapwBYTe+iPL5ih6xrNylxrnBdHQiijDETfXX7VIxC3UiCRiINBJfANBAsPzAvRQj8RpQ==
|
||||
|
||||
highlight.js@^10.4.1, highlight.js@~10.7.0:
|
||||
version "10.7.2"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.2.tgz#89319b861edc66c48854ed1e6da21ea89f847360"
|
||||
integrity sha512-oFLl873u4usRM9K63j4ME9u3etNF0PLiJhSQ8rdfuL51Wn3zkD6drf9ZW0dOzjnZI22YYG24z30JcmfCZjMgYg==
|
||||
|
||||
history@^4.9.0:
|
||||
version "4.10.1"
|
||||
@ -17355,6 +17402,16 @@ polished@^4.0.5:
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.14.0"
|
||||
|
||||
popmotion@9.3.6:
|
||||
version "9.3.6"
|
||||
resolved "https://registry.yarnpkg.com/popmotion/-/popmotion-9.3.6.tgz#b5236fa28f242aff3871b9e23721f093133248d1"
|
||||
integrity sha512-ZTbXiu6zIggXzIliMi8LGxXBF5ST+wkpXGEjeTUDUOCdSQ356hij/xjeUdv0F8zCQNeqB1+PR5/BB+gC+QLAPw==
|
||||
dependencies:
|
||||
framesync "5.3.0"
|
||||
hey-listen "^1.0.8"
|
||||
style-value-types "4.1.4"
|
||||
tslib "^2.1.0"
|
||||
|
||||
portfinder@^1.0.25, portfinder@^1.0.28:
|
||||
version "1.0.28"
|
||||
resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778"
|
||||
@ -18676,6 +18733,11 @@ react-inspector@^5.1.0:
|
||||
is-dom "^1.0.0"
|
||||
prop-types "^15.0.0"
|
||||
|
||||
react-intersection-observer@^8.32.2:
|
||||
version "8.32.2"
|
||||
resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-8.32.2.tgz#527eeecf569309d64ed96330636d90aac336c957"
|
||||
integrity sha512-QTcea+n28AvOHbTku+jErfQqknbc4Nuh7EUNik8p/JMN56W2Jhjs+qcYZzQhAoyLX8pZD0QXpYX0lW87faackQ==
|
||||
|
||||
react-is@17.0.2, react-is@^17.0.0, react-is@^17.0.1, react-is@^17.0.2:
|
||||
version "17.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
|
||||
@ -20917,6 +20979,14 @@ style-to-object@0.3.0, style-to-object@^0.3.0:
|
||||
dependencies:
|
||||
inline-style-parser "0.1.1"
|
||||
|
||||
style-value-types@4.1.4:
|
||||
version "4.1.4"
|
||||
resolved "https://registry.yarnpkg.com/style-value-types/-/style-value-types-4.1.4.tgz#80f37cb4fb024d6394087403dfb275e8bb627e75"
|
||||
integrity sha512-LCJL6tB+vPSUoxgUBt9juXIlNJHtBMy8jkXzUJSBzeHWdBu6lhzHqCvLVkXFGsFIlNa2ln1sQHya/gzaFmB2Lg==
|
||||
dependencies:
|
||||
hey-listen "^1.0.8"
|
||||
tslib "^2.1.0"
|
||||
|
||||
styled-components@5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.0.0.tgz#fc59932c9b574571fa3cd462c862af1956114ff2"
|
||||
@ -21670,7 +21740,7 @@ tslib@2.1.0, tslib@~2.1.0:
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
|
||||
integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
|
||||
|
||||
tslib@2.3.1, tslib@^2, tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.3.0:
|
||||
tslib@2.3.1, tslib@^2, tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01"
|
||||
integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==
|
||||
|
||||