Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs(en): merge gulp into docschina/cn @ c8af31dc #7

Open
wants to merge 22 commits into
base: cn
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7c6a91f
Add Decojent as a new org sponsor (#124)
phated Jul 29, 2020
8ae19df
Add a package-lock because docusaurus had breaking changes
phated Jul 28, 2020
8274253
Utilize OneGraph to join GitHub Sponsors & OpenCollective
phated Jul 28, 2020
c4cd0a2
Merge branch 'source' of https://github.com/gulpjs/gulpjs.github.io i…
docschina-bot Aug 3, 2020
ba40a85
Disable Navbar search on Plugins page to focus on plugin search (#125)
Aug 4, 2020
f4959db
Fix weighting to remove some sketchy packages
phated Aug 4, 2020
7141598
Add code comment linking to npm search API docs
phated Aug 4, 2020
d0c3bf3
useLocation & formatting
phated Aug 4, 2020
487199c
Merge branch 'source' of https://github.com/gulpjs/gulpjs.github.io i…
docschina-bot Aug 10, 2020
bd278d5
Add special styling for deprecated plugins in search (closes $113) (#…
Aug 23, 2020
cd4b5ca
Add advanced section to the sidebar
phated Aug 24, 2020
826e792
Merge branch 'source' of https://github.com/gulpjs/gulpjs.github.io i…
docschina-bot Aug 24, 2020
eb3ed48
docs(en): fetch all
docschina-bot Aug 28, 2020
abe0ac3
Remove company that ended sponsorship
phated Oct 20, 2020
4fe7b9a
Add first recipe to sidebar
phated Oct 21, 2020
e1cc1ea
docs(en): fetch all
docschina-bot Oct 23, 2020
3797585
Fix: Show copy to clipboard button (#130)
Oct 23, 2020
0ffbe8b
Merge branch 'source' of https://github.com/gulpjs/gulpjs.github.io i…
docschina-bot Oct 26, 2020
7d3d696
docs(en): fetch all
docschina-bot Jan 15, 2021
ac31770
Fix: Cleanup hero svg (#132)
jagdish7908 Jan 21, 2021
c8af31d
Merge branch 'source' of https://github.com/gulpjs/gulpjs.github.io i…
docschina-bot Jan 25, 2021
90e1cc5
docs(en): merging all conflicts
docschina-bot Jan 29, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -21,7 +21,6 @@ yarn-error.log*
*.log

# lock
package-lock.json
yarn.lock

# generated
2 changes: 1 addition & 1 deletion .npmrc
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
package-lock=false
package-lock=true
loglevel=error
204 changes: 204 additions & 0 deletions docs/advanced/creating-custom-registries.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
---
id: creating-custom-registries
title: Creating Custom Registries
hide_title: true
sidebar_label: Creating Custom Registries
---

# Creating Custom Registries

Allows custom registries to be plugged into the task system, which can provide shared tasks or augmented functionality. Registries are registered using [`registry()`][registry-api-docs].

## Structure

In order to be accepted by gulp, custom registries must follow a specific format.

```js
// as a function
function TestRegistry() {}

TestRegistry.prototype.init = function (gulpInst) {}
TestRegistry.prototype.get = function (name) {}
TestRegistry.prototype.set = function (name, fn) {}
TestRegistry.prototype.tasks = function () {}

// as a class
class TestRegistry {
init(gulpInst) {}

get(name) {}

set(name, fn) {}

tasks() {}
}
```

If a registry instance passed to `registry()` doesn't have all four methods, an error will be thrown.

## Registration

If we want to register our example registry from above, we will need to pass an instance of it to `registry()`.

```js
const { registry } = require('gulp');

// ... TestRegistry setup code

// good!
registry(new TestRegistry())

// bad!
registry(TestRegistry())
// This will trigger an error: 'Custom registries must be instantiated, but it looks like you passed a constructor'
```

## Methods

### `init(gulpInst)`

The `init()` method of a registry is called at the very end of the `registry()` function. The gulp instance passed as the only argument (`gulpInst`) can be used to pre-define tasks using
`gulpInst.task(taskName, fn)`.

#### Parameters

| parameter | type | note |
|:---------:|:----:|------|
| gulpInst | object | Instance of gulp. |

### `get(name)`

The `get()` method receives a task `name` for the custom registry to resolve and return, or `undefined` if no task with that name exists.

#### Parameters

| parameter | type | note |
|:---------:|:----:|------|
| name | string | Name of the task to be retrieved. |

### `set(name, fn)`

The `set()` method receives a task `name` and `fn`. This is called internally by `task()` to provide user-registered tasks to custom registries.

#### Parameters

| parameter | type | note |
|:---------:|:----:|------|
| name | string | Name of the task to be set. |
| fn | function | Task function to be set. |

### `tasks()`

Must return an object listing all tasks in the registry.

## Use Cases

### Sharing Tasks

To share common tasks with all your projects, you can expose an `init` method on the registry and it will receive the an instance of gulp as the only argument. You can then use `gulpInst.task(name, fn)` to register pre-defined tasks.

For example, you might want to share a `clean` task:

```js
const fs = require('fs');
const util = require('util');

const DefaultRegistry = require('undertaker-registry');
const del = require('del');

function CommonRegistry(opts){
DefaultRegistry.call(this);

opts = opts || {};

this.buildDir = opts.buildDir || './build';
}

util.inherits(CommonRegistry, DefaultRegistry);

CommonRegistry.prototype.init = function(gulpInst) {
const buildDir = this.buildDir;
const exists = fs.existsSync(buildDir);

if(exists){
throw new Error('Cannot initialize common tasks. ' + buildDir + ' directory exists.');
}

gulpInst.task('clean', function(){
return del([buildDir]);
});
}

module.exports = CommonRegistry;
```

Then to use it in a project:

```js
const { registry, series, task } = require('gulp');
const CommonRegistry = require('myorg-common-tasks');

registry(new CommonRegistry({ buildDir: '/dist' }));

task('build', series('clean', function build(cb) {
// do things
cb();
}));
```

### Sharing Functionality

By controlling how tasks are added to the registry, you can decorate them.

For example, if you wanted all tasks to share some data, you can use a custom registry to bind them to that data. Be sure to return the altered task, as per the description of registry methods above:

```js
const { registry, series, task } = require('gulp');
const util = require('util');
const DefaultRegistry = require('undertaker-registry');

// Some task defined somewhere else
const BuildRegistry = require('./build.js');
const ServeRegistry = require('./serve.js');

function ConfigRegistry(config){
DefaultRegistry.call(this);
this.config = config;
}

util.inherits(ConfigRegistry, DefaultRegistry);

ConfigRegistry.prototype.set = function set(name, fn) {
// The `DefaultRegistry` uses `this._tasks` for storage.
var task = this._tasks[name] = fn.bind(this.config);
return task;
};

registry(new BuildRegistry());
registry(new ServeRegistry());

// `registry` will reset each task in the registry with
// `ConfigRegistry.prototype.set` which will bind them to the config object.
registry(new ConfigRegistry({
src: './src',
build: './build',
bindTo: '0.0.0.0:8888'
}));

task('default', series('clean', 'build', 'serve', function(cb) {
console.log('Server bind to ' + this.bindTo);
console.log('Serving' + this.build);
cb();
}));
```

## Examples

* [undertaker-registry][undertaker-registry-example]: The Gulp 4 default registry.
* [undertaker-common-tasks][undertaker-common-tasks-example]: Proof-of-concept custom registry that pre-defines tasks.
* [undertaker-task-metadata][undertaker-task-metadata-example]: Proof-of-concept custom registry that attaches metadata to each task.

[registry-api-docs]: ../api/registry.md
[undertaker-registry-example]: https://github.com/gulpjs/undertaker-registry
[undertaker-common-tasks-example]: https://github.com/gulpjs/undertaker-common-tasks
[undertaker-task-metadata-example]: https://github.com/gulpjs/undertaker-task-metadata
33 changes: 26 additions & 7 deletions docs/api/registry.md
Original file line number Diff line number Diff line change
@@ -7,7 +7,6 @@ sidebar_label: registry()

# registry()


Allows custom registries to be plugged into the task system, which can provide shared tasks or augmented functionality.

**Note:** Only tasks registered with `task()` will be provided to the custom registry. The task functions passed directly to `series()` or `parallel()` will not be provided - if you need to customize the registry behavior, compose tasks with string references.
@@ -50,14 +49,34 @@ If a `registryInstance` is passed, nothing will be returned. If no arguments are

### Errors

When a constructor (instead of an instance) is passed as `registryInstance`, throws an error with the message, "Custom registries must be instantiated, but it looks like you passed a constructor".
#### Incorrect parameter

When a constructor (instead of an instance) is passed as `registryInstance`, throws an error with the message:

> Custom registries must be instantiated, but it looks like you passed a constructor.

#### Missing `get` method

When a registry without a `get` method is passed as `registryInstance`, throws an error with the message:

> Custom registry must have `get` function.

#### Missing `set` method

When a registry without a `set` method is passed as `registryInstance`, throws an error with the message:

> Custom registry must have `set` function.

#### Missing `init` method

When a registry without an `init` method is passed as `registryInstance`, throws an error with the message:

When a registry without a `get` method is passed as `registryInstance`, throws an error with the message, "Custom registry must have `get` function".
> Custom registry must have `init` function"

When a registry without a `set` method is passed as `registryInstance`, throws an error with the message, "Custom registry must have `set` function".
#### Missing `tasks` method

When a registry without an `init` method is passed as `registryInstance`, throws an error with the message, "Custom registry must have `init` function"
When a registry without a `tasks` method is passed as `registryInstance`, throws an error with the message:

When a registry without a `tasks` method is passed as `registryInstance`, throws an error with the message, "Custom registry must have `tasks` function".
> Custom registry must have `tasks` function.

[creating-custom-registries]: ../documentation-missing.md
[creating-custom-registries]: ../advanced/creating-custom-registries.md
2 changes: 1 addition & 1 deletion docs/api/task.md
Original file line number Diff line number Diff line change
@@ -61,7 +61,7 @@ Since any registered task can be run from the command line, avoid using spaces i

| parameter | type | note |
|:--------------:|:------:|-------|
| taskName | string | An alias for the task function within the the task system. Not needed when using named functions for `taskFunction`. |
| taskName | string | An alias for the task function within the task system. Not needed when using named functions for `taskFunction`. |
| taskFunction<br />**(required)** | function | A [task function][task-concepts] or composed task - generated by `series()` and `parallel()`. Ideally a named function. [Task metadata][task-metadata-section] can be attached to provide extra information to the command line. |

### Returns
100 changes: 100 additions & 0 deletions docs/recipes/automate-releases.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
id: automate-releases
title: Automate Releases
hide_title: true
sidebar_label: Automate Releases
---

# Automate Releases

If your project follows a semantic versioning, it may be a good idea to automatize the steps needed to do a release.
The recipe below bumps the project version, commits the changes to git and creates a new GitHub release.

For publishing a GitHub release you'll need to [create a personal access token](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token) and add it to your project. However, we don't want to commit it, so we'll use [`dotenv`](https://www.npmjs.com/package/dotenv) to load it from a git-ignored `.env` file:

```
GH_TOKEN=ff34885...
```

Don't forget to add `.env` to your `.gitignore`.

Next, install all the necessary dependencies for this recipe:

```sh
npm install --save-dev conventional-recommended-bump conventional-changelog-cli conventional-github-releaser dotenv execa
```

Based on your environment, setup and preferences, your release workflow might look something like this:

``` js
const gulp = require('gulp');
const conventionalRecommendedBump = require('conventional-recommended-bump');
const conventionalGithubReleaser = require('conventional-github-releaser');
const execa = require('execa');
const fs = require('fs');
const { promisify } = require('util');
const dotenv = require('dotenv');

// load environment variables
const result = dotenv.config();

if (result.error) {
throw result.error;
}

// Conventional Changelog preset
const preset = 'angular';
// print output of commands into the terminal
const stdio = 'inherit';

async function bumpVersion() {
// get recommended version bump based on commits
const { releaseType } = await promisify(conventionalRecommendedBump)({ preset });
// bump version without committing and tagging
await execa('npm', ['version', releaseType, '--no-git-tag-version'], {
stdio,
});
}

async function changelog() {
await execa(
'npx',
[
'conventional-changelog',
'--preset',
preset,
'--infile',
'CHANGELOG.md',
'--same-file',
],
{ stdio }
);
}

async function commitTagPush() {
// even though we could get away with "require" in this case, we're taking the safe route
// because "require" caches the value, so if we happen to use "require" again somewhere else
// we wouldn't get the current value, but the value of the last time we called "require"
const { version } = JSON.parse(await promisify(fs.readFile)('package.json'));
const commitMsg = `chore: release ${version}`;
await execa('git', ['add', '.'], { stdio });
await execa('git', ['commit', '--message', commitMsg], { stdio });
await execa('git', ['tag', `v${version}`], { stdio });
await execa('git', ['push', '--follow-tags'], { stdio });
}

function githubRelease(done) {
conventionalGithubReleaser(
{ type: 'oauth', token: process.env.GH_TOKEN },
{ preset },
done
);
}

exports.release = gulp.series(
bumpVersion,
changelog,
commitTagPush,
githubRelease
);
```
46 changes: 37 additions & 9 deletions docusaurus.config.js
Original file line number Diff line number Diff line change
@@ -22,15 +22,26 @@ module.exports = {
target: '_self',
},
links: [
<<<<<<< HEAD
{ to: 'docs/cn/getting-started/quick-start',
label: 'Get Started',
position: 'left',
},
{ to: 'docs/cn/api/concepts',
=======
{
to: 'docs/en/getting-started/quick-start',
label: 'Get Started',
position: 'left',
},
{
to: 'docs/en/api/concepts',
>>>>>>> c8af31dc927ce9beba5f63b433267a1a46c3622c
label: 'API',
position: 'left',
},
{ to: 'plugins',
{
to: 'plugins',
label: 'Plugins',
position: 'left',
},
@@ -45,14 +56,16 @@ module.exports = {
position: 'left',
emphasis: true,
},
{ href: 'https://twitter.com/gulpjs',
{
href: 'https://twitter.com/gulpjs',
logo: {
alt: 'Gulp on Twitter',
src: 'img/twitter.svg',
},
position: 'right'
},
{ href: 'https://medium.com/gulpjs',
{
href: 'https://medium.com/gulpjs',
logo: {
alt: 'The gulp blog',
src: 'img/medium.svg',
@@ -63,29 +76,44 @@ module.exports = {
},
footer: {
links: [
{ items: [
{
items: [
{ html: '<img src="/img/gulp-white-logo.svg" alt="gulp" href="/" />' }
]
},
{ title: 'Docs',
{
title: 'Docs',
items: [
<<<<<<< HEAD
{ to: 'docs/cn/getting-started/quick-start',
label: 'Getting Started',
},
{ to: 'docs/cn/api/concepts',
=======
{
to: 'docs/en/getting-started/quick-start',
label: 'Getting Started',
},
{
to: 'docs/en/api/concepts',
>>>>>>> c8af31dc927ce9beba5f63b433267a1a46c3622c
label: 'API',
},
]
},
{ title: 'Community',
{
title: 'Community',
items: [
{ href: 'https://github.com/gulpjs/gulp',
{
href: 'https://github.com/gulpjs/gulp',
label: 'GitHub',
},
{ href: 'https://stackoverflow.com/questions/tagged/gulp',
{
href: 'https://stackoverflow.com/questions/tagged/gulp',
label: 'Stack Overflow',
},
{ href: 'https://twitter.com/gulpjs',
{
href: 'https://twitter.com/gulpjs',
label: 'Twitter',
}
]
16,764 changes: 16,764 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

18 changes: 10 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -13,14 +13,16 @@
"swizzle": "docusaurus swizzle"
},
"devDependencies": {
"@docusaurus/core": "^2.0.0-alpha.50",
"@docusaurus/plugin-content-docs": "^2.0.0-alpha.50",
"@docusaurus/plugin-content-pages": "^2.0.0-alpha.50",
"@docusaurus/plugin-google-analytics": "^2.0.0-alpha.50",
"@docusaurus/plugin-google-gtag": "^2.0.0-alpha.50",
"@docusaurus/plugin-sitemap": "^2.0.0-alpha.50",
"@docusaurus/theme-classic": "^2.0.0-alpha.50",
"@docusaurus/theme-search-algolia": "^2.0.0-alpha.50",
"@docusaurus/core": "2.0.0-alpha.50",
"@docusaurus/plugin-content-docs": "2.0.0-alpha.50",
"@docusaurus/plugin-content-pages": "2.0.0-alpha.50",
"@docusaurus/plugin-google-analytics": "2.0.0-alpha.50",
"@docusaurus/plugin-google-gtag": "2.0.0-alpha.50",
"@docusaurus/plugin-sitemap": "2.0.0-alpha.50",
"@docusaurus/theme-classic": "2.0.0-alpha.50",
"@docusaurus/theme-search-algolia": "2.0.0-alpha.50",
"@docusaurus/types": "2.0.0-alpha.50",
"@docusaurus/utils": "2.0.0-alpha.50",
"del": "^5.1.0",
"docusaurus-plugin-sass": "^0.1.8",
"github-download-directory": "^1.2.0",
6 changes: 6 additions & 0 deletions sidebars.json
Original file line number Diff line number Diff line change
@@ -10,6 +10,12 @@
"getting-started/using-plugins",
"getting-started/watching-files"
],
"Advanced": [
"advanced/creating-custom-registries"
],
"Recipes": [
"recipes/automate-releases"
],
"API": [
"api/concepts",
"api/src",
5 changes: 5 additions & 0 deletions src/css/docs.css
Original file line number Diff line number Diff line change
@@ -299,3 +299,8 @@ table tr td + td + td:last-child {
box-shadow: 6px 6px 0 0 var(--ifm-color-secondary);
transition: box-shadow .1s ease-in, transform .1s ease-in;
}

/* Fix: show "Copy to clipboard" button */
button.copyButton_node_modules-\@docusaurus-theme-classic-src-theme-CodeBlock- {
color: var(--ifm-color-white);
}
52 changes: 37 additions & 15 deletions src/pages/plugins/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useEffect, useState} from 'react';
import React, { useEffect, useState } from 'react';
import classnames from 'classnames';

import Layout from '@theme/Layout';
@@ -16,6 +16,7 @@ function isInternalKeyword(keyword) {
class Plugin {
constructor(object) {
this._package = object.package;
this._flags = object.flags ? object.flags : {};
}

get key() {
@@ -26,6 +27,16 @@ class Plugin {
return this._package.name;
}

get isDeprecated() {
const isDeprecated = this._flags.deprecated ? true : false;
return isDeprecated;
}

get deprecatedMessage() {
const deprecatedMessage = this._flags.deprecated ? this._flags.deprecated : '';
return deprecatedMessage;
}

get description() {
return this._package.description;
}
@@ -62,9 +73,9 @@ class Plugin {
}

if (homepage &&
homepage !== npm &&
homepage !== repository &&
homepage !== `${repository}#readme`) {
homepage !== npm &&
homepage !== repository &&
homepage !== `${repository}#readme`) {
links.push({ text: 'homepage', href: homepage });
}

@@ -95,21 +106,30 @@ function PluginFooter({ keywords = [] }) {
}

function PluginComponent({ plugin }) {
const { isDeprecated, deprecatedMessage } = plugin
const cardClasses = classnames('card', { [styles.pluginDeprecatedCard]: isDeprecated });
const cardHeaderClasses = classnames('card__header', {
[styles.pluginCardHeader]: !isDeprecated,
[styles.deprecatedCardHeader]: isDeprecated
});
const cardBodyClasses = 'card__body';

return (
<div className="row padding-vert--md">
<div className="col col--10 col--offset-1">
<div key={plugin.key} className="card">
<div className={classnames('card__header', styles.pluginCardHeader)}>
<div key={plugin.key} className={cardClasses}>
<div className={cardHeaderClasses}>
{isDeprecated && <span className="badge badge--primary">Deprecated</span>}
<h2><a className={styles.primaryUrl} href={plugin.primaryUrl}>{plugin.name}</a></h2>
<span className="badge badge--primary">{plugin.version}</span>
{!isDeprecated && <span className="badge badge--primary">{plugin.version}</span>}
</div>
<div className="card__body">
{plugin.description}
<div className={cardBodyClasses}>
{isDeprecated ? <div className={styles.deprecatedMessage}>{deprecatedMessage}</div> : plugin.description}
<div className="padding-top--sm">
{plugin.links.map((link) => <a key={link.text} className="padding-right--sm" href={link.href}>{link.text}</a>)}
</div>
</div>
<PluginFooter keywords={plugin.keywords} />
{!isDeprecated && <PluginFooter keywords={plugin.keywords} />}
</div>
</div>
</div>
@@ -120,7 +140,7 @@ function noop(evt) {
evt && evt.preventDefault();
}

function Paginate({onPage = noop}) {
function Paginate({ onPage = noop }) {
return (
<div className="row padding-vert--md">
<div className="col col--4 col--offset-4">
@@ -141,7 +161,6 @@ function keywordsToQuerystring(keywords) {
} else {
keywordsStr += `gulpplugin`;
}

return keywordsStr;
}

@@ -150,6 +169,8 @@ async function fetchPackages(keywords, searchText = '', pageNumber = 0) {

let search = [
keywordsToQuerystring(keywords),
"is:unstable",
"not:unstable"
];
if (searchText) {
search.push(encodeURIComponent(searchText));
@@ -159,11 +180,12 @@ async function fetchPackages(keywords, searchText = '', pageNumber = 0) {
const text = search.join(' ');

try {
const initialUrl = `${baseUrl}?from=${from}&text=${text}`;
// https://github.com/npm/registry/blob/master/docs/REGISTRY-API.md#get-v1search
const initialUrl = `${baseUrl}?from=${from}&text=${text}&quality=0.5&popularity=1.0&maintenance=0.1`;
const response = await fetch(initialUrl);
const { total, objects } = await response.json();
return { total, plugins: objects.map(toPlugin) };
} catch(err) {
} catch (err) {
console.log(err);
return { total: 0, plugins: [] };
}
@@ -277,7 +299,7 @@ function useSearch() {


function PluginsPage() {
const [{title, plugins, placeholder, hasMore}, {search, paginate}] = useSearch();
const [{ title, plugins, placeholder, hasMore }, { search, paginate }] = useSearch();
const [searchInput, setSearchInput] = useState(``);

let onSubmit = (evt) => {
25 changes: 24 additions & 1 deletion src/pages/plugins/plugins.module.scss
Original file line number Diff line number Diff line change
@@ -4,7 +4,6 @@

.searchInput {
flex-grow: 1;

appearance: none;
background-color: var(--ifm-navbar-search-input-background-color);
background-image: var(--ifm-navbar-search-input-icon);
@@ -31,6 +30,30 @@
font-size: 1.1rem;
}

.pluginDeprecatedCard {
background-color: #ffdfdf;
}

.deprecatedCardHeader {
display: flex;
justify-content: flex-start;
align-items: center;

h2 {
margin-left: var(--ifm-card-horizontal-spacing);
}
}


.deprecatedMessage {
color: var(--ifm-color-primary-dark);
background-color: var(--ifm-color-white);
padding: 0.5rem;
border-radius: var(--ifm-card-border-radius);
border-style: solid;
border-width: 1px;
}

.pluginCardHeader {
display: flex;
justify-content: space-between;
104 changes: 41 additions & 63 deletions src/theme/BackerBanner/index.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,15 @@
// TODO: This file needs a massive rewrite for GitHub Sponsors
import React, { useState, useEffect } from 'react';
import classnames from 'classnames';
import shuffle from 'lodash.shuffle';
import ExternalLink from '@theme/ExternalLink';

import styles from './banner.module.scss';

const collectiveURL ='https://rest.opencollective.com/v2/gulpjs/orders/incoming?status=active,paid&limit=1000';
const sponsorsURL = 'https://serve.onegraph.com/graphql?app_id=c8251aa1-22ab-4dca-9e57-e7c335ddcd7c';

function uniqueBySlug(array) {
const predicate = function (o) {
return o.fromAccount.slug;
}
return array.reduce(function(acc, curr) {
return acc.filter(function (a) {
return predicate(a) === predicate(curr);
}).length ? acc : acc.push(curr) && acc
}, []);
}

const specialFilter = [
'addyosmani',
];

const thirtyTwoDaysAgo = Date.now() - 2.765e+9;

function withinMonth(createdAt) {
const datePaid = new Date(createdAt);
return datePaid >= thirtyTwoDaysAgo;
}

function recentNonCompanies(backer) {
if (backer.fromAccount && specialFilter.includes(backer.fromAccount.slug)) {
return false;
}

if (backer.fromAccount && backer.fromAccount.type === 'ORGANIZATION') {
return false;
}

if (backer.tier && backer.tier.slug === 'company') {
return false;
}

if (backer.frequency === 'MONTHLY' && backer.status === 'ACTIVE') {
return true;
}

if (backer.frequency === 'ONETIME' && backer.status === 'PAID' && withinMonth(backer.createdAt)) {
function between5And250(backer) {
const amount = backer.tier.amountDonated;
if (amount >= 500 && amount < 25000) {
return true;
}

@@ -59,38 +21,54 @@ function selectRandom(backers) {
}

async function getBackers() {
const response = await fetch(collectiveURL);
const orders = await response.json();
const response = await fetch(sponsorsURL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
doc_id: 'fe685787-b348-42a4-960c-2322add1e11b',
}),
});

const allBackers = orders.nodes.filter(recentNonCompanies);
// TODO: Handle errors
const { data, errors } = await response.json();

const uniqueBackers = uniqueBySlug(allBackers);
const backersToDisplay = selectRandom(uniqueBackers)
let ghBackers = data.gitHub.organization.sponsors.nodes;
let ocBackers = data.openCollective.organization.sponsors.nodes;
let allBackers = [].concat(ghBackers, ocBackers);

return backersToDisplay.map(function(backer) {
const fromAccount = backer.fromAccount;
const totalDonations = backer.totalDonations;
const validBackers = allBackers.filter(between5And250);

const name = fromAccount.name;
const slug = fromAccount.slug;
const website = fromAccount.website;
const twitterHandle = fromAccount.twitterHandle;
const imageUrl = fromAccount.imageUrl;
const backersToDisplay = selectRandom(validBackers)

return backersToDisplay.map(function (backer) {
const {
name,
openCollectiveHandle,
twitterHandle,
githubHandle,
avatarUrl
} = backer.sponsor;
// It is in US cents
const monthlyAmount = (backer.tier.amountDonated / 100);

let href;
if (website) {
href = website;
if (githubHandle) {
href = `https://github.com/${githubHandle}`;
} else if (twitterHandle) {
href = 'https://twitter.com/' + twitterHandle
href = `https://twitter.com/${twitterHandle}`;
} else {
href = 'https://opencollective.com/' + slug
href = `https://opencollective.com/${openCollectiveHandle}`
}

let usersName = name || githubHandle || twitterHandle || openCollectiveHandle || '';

return {
key: slug,
src: imageUrl,
alt: name,
title: `Thank you ${name} for $${totalDonations.value}!`,
key: href,
src: avatarUrl,
alt: usersName,
title: `Thank you ${usersName} for the $${monthlyAmount}/month!`,
href: href,
};
});
12 changes: 6 additions & 6 deletions src/theme/Hero/svg.js
Original file line number Diff line number Diff line change
@@ -50,13 +50,13 @@ function Svg() {
<path
stroke="#0A0908"
strokeWidth="6"
d="M293 191L293 304"
d="M293 191L293 303"
opacity="0.1"
></path>
<path
stroke="#CF4647"
strokeWidth="6"
d="M293 191L293 304"
d="M293 191L293 303"
className={styles.line_down_anim}
opacity="0.1"
></path>
@@ -117,13 +117,13 @@ function Svg() {
<path
stroke="#0A0908"
strokeWidth="6"
d="M101.216 186L101 302"
d="M101 186L101 302"
opacity="0.1"
></path>
<path
stroke="#CF4647"
strokeWidth="6"
d="M101.216 186L101 302"
d="M101 186L101 302"
className={`${styles.line_down_anim} ${styles.second}`}
opacity="0.1"
></path>
@@ -143,13 +143,13 @@ function Svg() {
<path
stroke="#0A0908"
strokeWidth="6"
d="M463 156l.3 148"
d="M463 157l.3 147"
opacity="0.1"
></path>
<path
stroke="#CF4647"
strokeWidth="6"
d="M463 156l.3 148"
d="M463 157l.3 147"
className={`${styles.line_down_anim} ${styles.second}`}
opacity="0.1"
></path>
69 changes: 40 additions & 29 deletions src/theme/Navbar/index.js
Original file line number Diff line number Diff line change
@@ -5,12 +5,13 @@
* LICENSE file in the root directory of this source tree.
*/

import React, {useCallback, useState} from 'react';
import React, { useCallback, useState, useEffect } from 'react';
import classnames from 'classnames';
import Link from '@docusaurus/Link';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useBaseUrl from '@docusaurus/useBaseUrl';
import isInternalUrl from '@docusaurus/isInternalUrl';
import { useLocation } from '@docusaurus/router';

import SearchBar from '@theme/SearchBar';
import Toggle from '@theme/Toggle';
@@ -20,18 +21,18 @@ import useLogo from '@theme/hooks/useLogo';

import styles from './styles.module.css';

function noop() {}
function noop() { }

const useLinkLogo = (logo = {}) => {
const {
siteConfig: {baseUrl} = {},
siteConfig: { baseUrl } = {},
} = useDocusaurusContext();
const {isDarkTheme} = useThemeContext();
const { isDarkTheme } = useThemeContext();
const logoLink = logo.href || baseUrl;
let logoLinkProps = {};

if (logo.target) {
logoLinkProps = {target: logo.target};
logoLinkProps = { target: logo.target };
} else if (!isInternalUrl(logoLink)) {
logoLinkProps = {
rel: 'noopener noreferrer',
@@ -48,10 +49,10 @@ const useLinkLogo = (logo = {}) => {
};
};

function NavLink({activeBasePath, to, href, logo, label, position, ...props}) {
function NavLink({ activeBasePath, to, href, logo, label, position, ...props }) {
const toUrl = useBaseUrl(to);
const activeBaseUrl = useBaseUrl(activeBasePath);
const {logoImageUrl, logoAlt} = useLinkLogo(logo);
const { logoImageUrl, logoAlt } = useLinkLogo(logo);

const content = logoImageUrl != null ? <img
className={classnames(styles.navbarIcon)}
@@ -62,27 +63,27 @@ function NavLink({activeBasePath, to, href, logo, label, position, ...props}) {
<Link
{...(href
? {
target: '_blank',
rel: 'noopener noreferrer',
href,
}
target: '_blank',
rel: 'noopener noreferrer',
href,
}
: {
activeClassName: 'navbar__link--active',
to: toUrl,
...(activeBasePath
? {
isActive: (_match, location) =>
location.pathname.startsWith(activeBaseUrl),
}
: null),
})}
activeClassName: 'navbar__link--active',
to: toUrl,
...(activeBasePath
? {
isActive: (_match, location) =>
location.pathname.startsWith(activeBaseUrl),
}
: null),
})}
{...props}>
{content}
</Link>
);
}

function NavItem({items, emphasis, position, ...props}) {
function NavItem({ items, emphasis, position, ...props }) {
if (!items) {
return <NavLink className={classnames('navbar__item', 'navbar__link', {
'navbar__link--icon': props.logo,
@@ -111,21 +112,29 @@ function NavItem({items, emphasis, position, ...props}) {
);
}

function notPluginPage(pathname) {
return pathname !== '/plugins' && pathname !== '/plugins/';
}

function Navbar() {
const {
siteConfig: {
themeConfig: {
navbar: {title, links = [], hideOnScroll = false} = {},
navbar: { title, links = [], hideOnScroll = false } = {},
disableDarkMode = false,
},
},
isClient,
} = useDocusaurusContext();
const {isDarkTheme, setLightTheme, setDarkTheme} = useThemeContext();
const {navbarRef, isNavbarVisible} = useHideableNavbar(hideOnScroll);
const {logoLink, logoLinkProps, logoImageUrl, logoAlt} = useLogo();

const location = useLocation();
const [enableSearch, setEnableSearch] = useState(notPluginPage(location.pathname));
useEffect(() => {
setEnableSearch(notPluginPage(location.pathname));
}, [location]);
const { isDarkTheme, setLightTheme, setDarkTheme } = useThemeContext();
const { navbarRef, isNavbarVisible } = useHideableNavbar(hideOnScroll);
const { logoLink, logoLinkProps, logoImageUrl, logoAlt } = useLogo();
const onToggleChange = useCallback(
e => (e.target.checked ? setDarkTheme() : setLightTheme()),
[setLightTheme, setDarkTheme],
@@ -170,10 +179,12 @@ function Navbar() {
onChange={onToggleChange}
/>
)}
<SearchBar
handleSearchBarToggle={noop}
isSearchBarExpanded={true}
/>
{enableSearch && (
<SearchBar
handleSearchBarToggle={noop}
isSearchBarExpanded={true}
/>
)}
</div>
</div>
</nav>
1 change: 1 addition & 0 deletions static/sponsor-logos/decojent.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.