diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 279d3f105a..0000000000 --- a/.babelrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "presets": ["next/babel"], - "plugins": ["transform-define", "transform-object-assign"] -} diff --git a/.gitignore b/.gitignore index d0ba1dbc90..1fd10aa23e 100644 --- a/.gitignore +++ b/.gitignore @@ -56,8 +56,11 @@ typings/ # Next.js build output .idea -.next/ *.log # Mac finder artifacts .DS_Store + +# Gatsby cache +.cache +public diff --git a/.restyled.yaml b/.restyled.yaml index 8a958a9d83..dc85f8a683 100644 --- a/.restyled.yaml +++ b/.restyled.yaml @@ -4,5 +4,5 @@ restylers: include: - './*.{js,md}' - 'pages/**/*.js' - - 'public/static/docs/**/*.{js,md}' + - 'content/docs/**/*.{js,md}' - 'src/**/*.js' diff --git a/README.md b/README.md index dbbf0bf0b7..d71a000618 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![owl logo](https://dvc.org/static/img/logo-github-readme.png) +![owl logo](https://dvc.org/img/logo-github-readme.png) [![Maintainability](https://api.codeclimate.com/v1/badges/5872e0a572ec8b74bd8d/maintainability)](https://codeclimate.com/github/iterative/dvc.org/maintainability) [![CircleCI](https://circleci.com/gh/iterative/dvc.org.svg?style=svg)](https://circleci.com/gh/iterative/dvc.org) diff --git a/config/prismjs/dvc-commands.js b/config/prismjs/dvc-commands.js new file mode 100644 index 0000000000..145e33d3f2 --- /dev/null +++ b/config/prismjs/dvc-commands.js @@ -0,0 +1,52 @@ +/* eslint-env node */ + +module.exports = [ + 'version', + 'update', + 'unprotect', + 'unlock', + 'tag', + 'status', + 'run', + 'root', + 'repro', + 'remove', + 'remote remove', + 'remote modify', + 'remote list', + 'remote default', + 'remote add', + 'remote', + 'push', + 'pull', + 'pkg', + 'pipeline show', + 'pipeline list', + 'pipeline', + 'move', + 'metrics show', + 'metrics remove', + 'metrics modify', + 'metrics diff', + 'metrics add', + 'metrics', + 'lock', + 'list', + 'install', + 'init', + 'import-url', + 'import', + 'help', + 'get-url', + 'get', + 'gc', + 'fetch', + 'diff', + 'destroy', + 'config', + 'commit', + 'checkout', + 'cache dir', + 'cache', + 'add' +] diff --git a/config/prismjs/dvc-hook.js b/config/prismjs/dvc-hook.js new file mode 100644 index 0000000000..89caa435c0 --- /dev/null +++ b/config/prismjs/dvc-hook.js @@ -0,0 +1,18 @@ +/* eslint-env node */ + +const Prism = require('prismjs') + +// Make sure the $ part of the command prompt in shell +// examples isn't copiable by making it an 'input' token. +Prism.hooks.add('after-tokenize', env => { + if (env.language !== 'dvc') { + return + } + + for (const token of env.tokens) { + if (token.type === 'line' && /^\$\s+$/.test(token.content[0])) { + const old = token.content[0] + token.content[0] = new Prism.Token('input', old, null, old, false) + } + } +}) diff --git a/config/prismjs/dvc.js b/config/prismjs/dvc.js new file mode 100644 index 0000000000..7d09682506 --- /dev/null +++ b/config/prismjs/dvc.js @@ -0,0 +1,66 @@ +/* eslint-env node */ + +// we require prism and load its bash module so we have +// Prism.languages.bash to embed into our DVC language. + +const Prism = require('prismjs') +require('prismjs/components/prism-bash') +require('./dvc-hook') +const { bash } = Prism.languages + +const dvc = require('./dvc-commands') + +// Command arrays are intentionally reverse sorted +// to prevent shorter matches before longer ones + +const git = [ + 'tag', + 'status', + 'remote update', + 'remote rename', + 'remote remove', + 'remote add', + 'remote', + 'push', + 'pull', + 'merge', + 'init', + 'fetch', + 'commit', + 'clone', + 'checkout', + 'add' +] + +const beforeCommand = String.raw`(\$[\s(]+|;\s*)` + +/* tslint:disable object-literal-sort-keys */ + +Prism.languages.dvc = { + line: { + pattern: /(?<=(^|\n))\$[\s\S]*?[^\\](:?\n|$)/, + inside: { + dvc: { + pattern: new RegExp( + String.raw`${beforeCommand}\b(?:dvc (?:${dvc.join('|')}))\b` + ), + greedy: true, + lookbehind: true + }, + git: { + pattern: new RegExp( + String.raw`${beforeCommand}\b(?:git (?:${git.join('|')}))\b` + ), + greedy: true, + lookbehind: true + }, + command: { + pattern: new RegExp(String.raw`${beforeCommand}\b[a-zA-Z0-9\-_]+\b`), + greedy: true, + lookbehind: true + }, + ...bash + } + }, + comment: bash.comment +} diff --git a/config/prismjs/usage.js b/config/prismjs/usage.js new file mode 100644 index 0000000000..8b1c9493f5 --- /dev/null +++ b/config/prismjs/usage.js @@ -0,0 +1,13 @@ +/* eslint-env node */ + +const dvc = require('./dvc-commands') +const Prism = require('prismjs') + +Prism.languages.usage = { + dvc: { + pattern: new RegExp(`dvc (?:${dvc.join('|')})`) + }, + usage: { + pattern: /(^|\n)\s*(usage|positional arguments|optional arguments)/ + } +} diff --git a/content/docs/api-reference/get_url.md b/content/docs/api-reference/get_url.md new file mode 100644 index 0000000000..9a83e33a09 --- /dev/null +++ b/content/docs/api-reference/get_url.md @@ -0,0 +1,110 @@ +# dvc.api.get_url() + +Returns the URL to the storage location of a data file or directory tracked in a +DVC project. + +```py +def get_url(path: str, + repo: str = None, + rev: str = None, + remote: str = None) -> str +``` + +#### Usage: + +```py +import dvc.api + +resource_url = dvc.api.get_url( + 'get-started/data.xml', + repo='https://github.com/iterative/dataset-registry') + +# resource_url is now "https://remote.dvc.org/dataset-registry/a3/04afb96060aad90176268345e10355" +``` + +## Description + +Returns the URL string of the storage location (in a +[DVC remote](/doc/command-reference/remote)) where a target file or directory, +specified by its `path` in a `repo` (DVC project), is stored. + +The URL is formed by reading the project's +[remote configuration](/doc/command-reference/config#remote) and the +[DVC-file](/doc/user-guide/dvc-file-format) where the given `path` is an +output. The URL schema returned depends on the +[type](/doc/command-reference/remote/add#supported-storage-types) of the +`remote` used (see the [Parameters](#parameters) section). + +If the target is a directory, the returned URL will end in `.dir`. Refer to +[Structure of cache directory](/doc/user-guide/dvc-files-and-directories#structure-of-cache-directory) +and `dvc add` to learn more about how DVC handles data directories. + +⚠️ This function does not check for the actual existence of the file or +directory in the remote storage. + +πŸ’‘ Having the resource's URL, it should be possible to download it directly with +an appropriate library, such as +[`boto3`](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Object.download_fileobj) +or +[`paramiko`](https://docs.paramiko.org/en/stable/api/sftp.html#paramiko.sftp_client.SFTPClient.get). + +## Parameters + +- **`path`** - location and file name of the file or directory in `repo`, + relative to the project's root. + +- `repo` - specifies the location of the DVC project. It can be a URL or a file + system path. Both HTTP and SSH protocols are supported for online Git repos + (e.g. `[user@]server:project.git`). _Default_: The current project is used + (the current working directory tree is walked up to find it). + +- `rev` - Git commit (any [revision](https://git-scm.com/docs/revisions) such as + a branch or tag name, or a commit hash). If `repo` is not a Git repo, this + option is ignored. _Default_: `HEAD`. + +- `remote` - name of the [DVC remote](/doc/command-reference/remote) to use to + form the returned URL string. _Default_: The + [default remote](/doc/command-reference/remote/default) of `repo` is used. + +## Exceptions + +- `dvc.api.UrlNotDvcRepoError` - `repo` is not a DVC project. + +- `dvc.exceptions.NoRemoteError` - no `remote` is found. + +## Example: Getting the URL to a DVC-tracked file + +```py +import dvc.api + +resource_url = dvc.api.get_url( + 'get-started/data.xml', + repo='https://github.com/iterative/dataset-registry' + ) + +print(resource_url) +``` + +The script above prints + +`https://remote.dvc.org/dataset-registry/a3/04afb96060aad90176268345e10355` + +This URL represents the location where the data is stored, and is built by +reading the corresponding DVC-file +([`get-started/data.xml.dvc`](https://github.com/iterative/dataset-registry/blob/master/get-started/data.xml.dvc)) +where the `md5` file hash is stored, + +```yaml +outs: + - md5: a304afb96060aad90176268345e10355 + path: get-started/data.xml +``` + +and the project configuration +([`.dvc/config`](https://github.com/iterative/dataset-registry/blob/master/.dvc/config)) +where the remote URL is saved: + +```ini +['remote "storage"'] +url = https://remote.dvc.org/dataset-registry +``` diff --git a/content/docs/api-reference/index.md b/content/docs/api-reference/index.md new file mode 100644 index 0000000000..0298b185ab --- /dev/null +++ b/content/docs/api-reference/index.md @@ -0,0 +1,16 @@ +# Python API + +DVC can be used as a Python library, simply [install](/doc/install) with `pip` +or `conda`. This reference provides the details about the functions in the API +module `dvc.api`, which can be imported any regular way, for example: + +```py +import dvc.api +``` + +The purpose of this API is to provide programatic access to the data or models +[stored and versioned](/doc/use-cases/versioning-data-and-model-files) in +DVC repositories from Python code. + +Please choose a function from the navigation sidebar to the left, or click the +`Next` button below to jump into the first one β†˜ diff --git a/content/docs/api-reference/open.md b/content/docs/api-reference/open.md new file mode 100644 index 0000000000..858090e0fb --- /dev/null +++ b/content/docs/api-reference/open.md @@ -0,0 +1,200 @@ +# dvc.api.open() + +Opens a tracked file. + +```py +def open(path: str, + repo: str = None, + rev: str = None, + remote: str = None, + mode: str = "r", + encoding: str = None) +``` + +#### Usage: + +```py +import dvc.api + +with dvc.api.open( + 'get-started/data.xml', + repo='https://github.com/iterative/dataset-registry' + ) as fd: + # ... fd is a file descriptor that can be processed normally. +``` + +## Description + +Open a data or model file tracked in a DVC project and generate a +corresponding +[file object](https://docs.python.org/3/glossary.html#term-file-object). The +file can be tracked by DVC or by Git. + +> The exact type of file object depends on the `mode` used. For more details, +> please refer to Python's +> [`open()`](https://docs.python.org/3/library/functions.html#open) built-in, +> which is used under the hood. + +`dvc.api.open()` may only be used as a +[context manager](https://www.python.org/dev/peps/pep-0343/#context-managers-in-the-standard-library) +(using the `with` keyword, as shown in the examples). + +This function makes a direct connection to the +[remote storage](/doc/command-reference/remote/add#supported-storage-types) +(except for Google Drive), so the file contents can be streamed. Your code can +process the data [buffer](https://docs.python.org/3/c-api/buffer.html) as it's +streamed, which optimizes memory usage. + +> Use `dvc.api.read()` to load the complete file contents in a single function +> call – no _context manager_ involved. Neither function utilizes disc space. + +## Parameters + +- **`path`** - location and file name of the file in `repo`, relative to the + project's root. + +- `repo` - specifies the location of the DVC project. It can be a URL or a file + system path. Both HTTP and SSH protocols are supported for online Git repos + (e.g. `[user@]server:project.git`). _Default_: The current project is used + (the current working directory tree is walked up to find it). + +- `rev` - Git commit (any [revision](https://git-scm.com/docs/revisions) such as + a branch or tag name, or a commit hash). If `repo` is not a Git repo, this + option is ignored. _Default_: `HEAD`. + +- `remote` - name of the [DVC remote](/doc/command-reference/remote) to look for + the target data. _Default_: The + [default remote](/doc/command-reference/remote/default) of `repo` is used if a + `remote` argument is not given. For local projects, the cache is + tied before the default remote. + +- `mode` - specifies the mode in which the file is opened. Defaults to `"r"` + (read). Mirrors the namesake parameter in builtin + [`open()`](https://docs.python.org/3/library/functions.html#open). + +- `encoding` - + [codec](https://docs.python.org/3/library/codecs.html#standard-encodings) used + to decode the file contents to a string. This should only be used in text + mode. Defaults to `"utf-8"`. Mirrors the namesake parameter in builtin + `open()`. + +## Exceptions + +- `dvc.exceptions.FileMissingError` - file in `path` is missing from `repo`. + +- `dvc.exceptions.PathMissingError` - `path` cannot be found in `repo`. + +- `dvc.api.UrlNotDvcRepoError` - `repo` is not a DVC project. + +- `dvc.exceptions.NoRemoteError` - no `remote` is found. + +## Example: Use data or models from DVC repositories + +Any data artifact hosted online can be processed directly in your +Python code with this API. For example, an XML file tracked in a public DVC repo +on Github can be processed like this: + +```py +from xml.sax import parse +import dvc.api +from mymodule import mySAXHandler + +with dvc.api.open( + 'get-started/data.xml', + repo='https://github.com/iterative/dataset-registry' + ) as fd: + parse(fd, mySAXHandler) +``` + +Notice that we use a [SAX](http://www.saxproject.org/) XML parser here because +`dvc.api.open()` is able to stream the data from +[remote storage](/doc/command-reference/remote/add#supported-storage-types). +(The `mySAXHandler` object should handle the event-driven parsing of the +document in this case.) This increases the performance of the code (minimizing +memory usage), and is typically faster than loading the whole data into memory. + +> If you just needed to load the complete file contents into memory, you can use +> `dvc.api.read()` instead: +> +> ```py +> from xml.dom.minidom import parse +> import dvc.api +> +> xmldata = dvc.api.read('get-started/data.xml', +> repo='https://github.com/iterative/dataset-registry') +> xmldom = parse(xmldata) +> ``` + +## Example: Accessing private repos + +This is just a matter of using the right `repo` argument, for example an SSH URL +(requires that the +[credentials are configured](https://help.github.com/en/github/authenticating-to-github/connecting-to-github-with-ssh) +locally): + +```py +import dvc.api + +with dvc.api.open( + 'features.dat', + repo='git@server.com:path/to/repo.git' + ) as fd: + # ... Process 'features' +``` + +## Example: Use different versions of data + +The `rev` argument lets you specify any Git commit to look for an artifact. This +way any previous version, or alternative experiment can be accessed +programmatically. For example, let's say your DVC repo has tagged releases of a +CSV dataset: + +```py +import csv +import dvc.api + +with dvc.api.open( + 'clean.csv', + rev='v1.1.0' + ) as fd: + reader = csv.reader(fd) + # ... Process 'clean' data from version 1.1.0 +``` + +Also, notice that we didn't supply a `repo` argument in this example. DVC will +attempt to find a DVC project to use in the current working +directory tree, and look for the file contents of `clean.csv` in its local +cache; no download will happen if found. See the +[Parameters](#parameters) section for more info. + +## Example: Chose a specific remote as the data source + +Sometimes we may want to choose the [remote](/doc/command-reference/remote) data +source, for example if the `repo` has no default remote set. This can be done by +providing a `remote` argument: + +```py +import dvc.api + +with open( + 'activity.log', + repo='location/of/dvc/project', + remote='my-s3-bucket' + ) as fd: + for line in fd: + match = re.search(r'user=(\w+)', line) + # ... Process users activity log +``` + +## Example: Specify the text encoding + +To chose which codec to open a text file with, send an `encoding` argument: + +```py +import dvc.api + +with dvc.api.open( + 'data/nlp/words_ru.txt', + encoding='koi8_r') as fd: + # ... Process Russian words +``` diff --git a/content/docs/api-reference/read.md b/content/docs/api-reference/read.md new file mode 100644 index 0000000000..2083df3728 --- /dev/null +++ b/content/docs/api-reference/read.md @@ -0,0 +1,101 @@ +# dvc.api.read() + +Returns the contents of a tracked file. + +```py +def open(path: str, + repo: str = None, + rev: str = None, + remote: str = None, + mode: str = "r", + encoding: str = None) +``` + +#### Usage: + +```py +import dvc.api + +modelpkl = dvc.api.read( + 'model.pkl', + repo='https://github.com/example/project.git', + mode='rb') +``` + +## Description + +This function wraps [`dvc.api.open()`](/doc/api-reference/open), for a simple +way to return the complete contents of a file tracked in a DVC +project. The file can be tracked by DVC or by Git. + +> This is similar to the `dvc get` command in our CLI. + +The returned contents can be a +[string](https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str) +or a [bytearray](https://docs.python.org/3/library/stdtypes.html#bytearray). +These are loaded to memory directly (without using any disc space). + +> The type returned depends on the `mode` used. For more details, please refer +> to Python's [`open()`](https://docs.python.org/3/library/functions.html#open) +> built-in, which is used under the hood. + +## Parameters + +- **`path`** - location and file name of the file in `repo`, relative to the + project's root. + +- `repo` - specifies the location of the DVC project. It can be a URL or a file + system path. Both HTTP and SSH protocols are supported for online Git repos + (e.g. `[user@]server:project.git`). _Default_: The current project is used + (the current working directory tree is walked up to find it). + +- `rev` - Git commit (any [revision](https://git-scm.com/docs/revisions) such as + a branch or tag name, or a commit hash). If `repo` is not a Git repo, this + option is ignored. _Default_: `HEAD`. + +- `remote` - name of the [DVC remote](/doc/command-reference/remote) to look for + the target data. _Default_: The + [default remote](/doc/command-reference/remote/default) of `repo` is used if a + `remote` argument is not given. For local projects, the cache is + tied before the default remote. + +- `mode` - specifies the mode in which the file is opened. Defaults to `"r"` + (read). Mirrors the namesake parameter in builtin + [`open()`](https://docs.python.org/3/library/functions.html#open). + +- `encoding` - + [codec](https://docs.python.org/3/library/codecs.html#standard-encodings) used + to decode the file contents to a string. This should only be used in text + mode. Defaults to `"utf-8"`. Mirrors the namesake parameter in builtin + `open()`. + +## Exceptions + +- `dvc.exceptions.FileMissingError` - file in `path` is missing from `repo`. + +- `dvc.exceptions.PathMissingError` - `path` cannot be found in `repo`. + +- `dvc.api.UrlNotDvcRepoError` - `repo` is not a DVC project. + +- `dvc.exceptions.NoRemoteError` - no `remote` is found. + +## Example: Load data from a DVC repository + +Any data artifact hosted online can be loaded directly in your +Python code with this API. For example, let's say that you want to load and +unserialize a binary model from a repo on Github: + +```py +import pickle +import dvc.api + +model = pickle.loads( + dvc.api.read( + 'model.pkl', + repo='https://github.com/example/project.git' + mode='rb' + ) + ) +``` + +> We're using `'rb'` mode here for compatibility with `pickle.loads()`. diff --git a/public/static/docs/changelog/0.18.md b/content/docs/changelog/0.18.md similarity index 94% rename from public/static/docs/changelog/0.18.md rename to content/docs/changelog/0.18.md index 27890748e4..08dbf0f167 100644 --- a/public/static/docs/changelog/0.18.md +++ b/content/docs/changelog/0.18.md @@ -29,10 +29,10 @@ really excited to share the progress with you: to use: - More heavy operations render dynamic progress bar (e.g. file hash - computation): ![](/static/img/0.18-progress.gif) + computation): ![](/img/0.18-progress.gif) - Pipeline visualization via command line. Just run `dvc pipeline show` with - option `--ascii` and a target: ![](/static/img/0.18-pipeline.gif) + option `--ascii` and a target: ![](/img/0.18-pipeline.gif) - Many hidden gems: `dvc repro` dry and interactive modes, improved overall commands verbosity and revised commands help. diff --git a/public/static/docs/changelog/0.35.md b/content/docs/changelog/0.35.md similarity index 98% rename from public/static/docs/changelog/0.35.md rename to content/docs/changelog/0.35.md index 774fd547d6..a3063ec96d 100644 --- a/public/static/docs/changelog/0.35.md +++ b/content/docs/changelog/0.35.md @@ -57,7 +57,7 @@ improvements) we have done in the last few months: - πŸ™‚ A lot of **UI improvements** . Starting from the finally fixed nasty issue with Windows command prompt printing a lot of garbage symbols, to using progress bars for checkouts, better metrics output, and lots of smaller - things: ![|528x200](/static/img/0.35-metrics.gif) + things: ![|528x200](/img/0.35-metrics.gif) - ⚑️ **Performance optimizations.** The most notable one is the migration from using a plain JSON file to an (embedded) SQLLite instance, to cache file and diff --git a/public/static/docs/command-reference/add.md b/content/docs/command-reference/add.md similarity index 100% rename from public/static/docs/command-reference/add.md rename to content/docs/command-reference/add.md diff --git a/public/static/docs/command-reference/cache/dir.md b/content/docs/command-reference/cache/dir.md similarity index 100% rename from public/static/docs/command-reference/cache/dir.md rename to content/docs/command-reference/cache/dir.md diff --git a/public/static/docs/command-reference/cache/index.md b/content/docs/command-reference/cache/index.md similarity index 100% rename from public/static/docs/command-reference/cache/index.md rename to content/docs/command-reference/cache/index.md diff --git a/public/static/docs/command-reference/checkout.md b/content/docs/command-reference/checkout.md similarity index 100% rename from public/static/docs/command-reference/checkout.md rename to content/docs/command-reference/checkout.md diff --git a/public/static/docs/command-reference/commit.md b/content/docs/command-reference/commit.md similarity index 100% rename from public/static/docs/command-reference/commit.md rename to content/docs/command-reference/commit.md diff --git a/public/static/docs/command-reference/config.md b/content/docs/command-reference/config.md similarity index 100% rename from public/static/docs/command-reference/config.md rename to content/docs/command-reference/config.md diff --git a/public/static/docs/command-reference/destroy.md b/content/docs/command-reference/destroy.md similarity index 100% rename from public/static/docs/command-reference/destroy.md rename to content/docs/command-reference/destroy.md diff --git a/public/static/docs/command-reference/diff.md b/content/docs/command-reference/diff.md similarity index 100% rename from public/static/docs/command-reference/diff.md rename to content/docs/command-reference/diff.md diff --git a/public/static/docs/command-reference/fetch.md b/content/docs/command-reference/fetch.md similarity index 100% rename from public/static/docs/command-reference/fetch.md rename to content/docs/command-reference/fetch.md diff --git a/public/static/docs/command-reference/gc.md b/content/docs/command-reference/gc.md similarity index 100% rename from public/static/docs/command-reference/gc.md rename to content/docs/command-reference/gc.md diff --git a/public/static/docs/command-reference/get-url.md b/content/docs/command-reference/get-url.md similarity index 100% rename from public/static/docs/command-reference/get-url.md rename to content/docs/command-reference/get-url.md diff --git a/public/static/docs/command-reference/get.md b/content/docs/command-reference/get.md similarity index 100% rename from public/static/docs/command-reference/get.md rename to content/docs/command-reference/get.md diff --git a/public/static/docs/command-reference/import-url.md b/content/docs/command-reference/import-url.md similarity index 100% rename from public/static/docs/command-reference/import-url.md rename to content/docs/command-reference/import-url.md diff --git a/public/static/docs/command-reference/import.md b/content/docs/command-reference/import.md similarity index 100% rename from public/static/docs/command-reference/import.md rename to content/docs/command-reference/import.md diff --git a/public/static/docs/command-reference/index.md b/content/docs/command-reference/index.md similarity index 100% rename from public/static/docs/command-reference/index.md rename to content/docs/command-reference/index.md diff --git a/public/static/docs/command-reference/init.md b/content/docs/command-reference/init.md similarity index 100% rename from public/static/docs/command-reference/init.md rename to content/docs/command-reference/init.md diff --git a/public/static/docs/command-reference/install.md b/content/docs/command-reference/install.md similarity index 100% rename from public/static/docs/command-reference/install.md rename to content/docs/command-reference/install.md diff --git a/public/static/docs/command-reference/lock.md b/content/docs/command-reference/lock.md similarity index 100% rename from public/static/docs/command-reference/lock.md rename to content/docs/command-reference/lock.md diff --git a/public/static/docs/command-reference/metrics/add.md b/content/docs/command-reference/metrics/add.md similarity index 100% rename from public/static/docs/command-reference/metrics/add.md rename to content/docs/command-reference/metrics/add.md diff --git a/public/static/docs/command-reference/metrics/diff.md b/content/docs/command-reference/metrics/diff.md similarity index 100% rename from public/static/docs/command-reference/metrics/diff.md rename to content/docs/command-reference/metrics/diff.md diff --git a/public/static/docs/command-reference/metrics/index.md b/content/docs/command-reference/metrics/index.md similarity index 100% rename from public/static/docs/command-reference/metrics/index.md rename to content/docs/command-reference/metrics/index.md diff --git a/public/static/docs/command-reference/metrics/modify.md b/content/docs/command-reference/metrics/modify.md similarity index 100% rename from public/static/docs/command-reference/metrics/modify.md rename to content/docs/command-reference/metrics/modify.md diff --git a/public/static/docs/command-reference/metrics/remove.md b/content/docs/command-reference/metrics/remove.md similarity index 100% rename from public/static/docs/command-reference/metrics/remove.md rename to content/docs/command-reference/metrics/remove.md diff --git a/public/static/docs/command-reference/metrics/show.md b/content/docs/command-reference/metrics/show.md similarity index 100% rename from public/static/docs/command-reference/metrics/show.md rename to content/docs/command-reference/metrics/show.md diff --git a/public/static/docs/command-reference/move.md b/content/docs/command-reference/move.md similarity index 100% rename from public/static/docs/command-reference/move.md rename to content/docs/command-reference/move.md diff --git a/public/static/docs/command-reference/pipeline/index.md b/content/docs/command-reference/pipeline/index.md similarity index 100% rename from public/static/docs/command-reference/pipeline/index.md rename to content/docs/command-reference/pipeline/index.md diff --git a/public/static/docs/command-reference/pipeline/list.md b/content/docs/command-reference/pipeline/list.md similarity index 100% rename from public/static/docs/command-reference/pipeline/list.md rename to content/docs/command-reference/pipeline/list.md diff --git a/public/static/docs/command-reference/pipeline/show.md b/content/docs/command-reference/pipeline/show.md similarity index 100% rename from public/static/docs/command-reference/pipeline/show.md rename to content/docs/command-reference/pipeline/show.md diff --git a/public/static/docs/command-reference/pull.md b/content/docs/command-reference/pull.md similarity index 100% rename from public/static/docs/command-reference/pull.md rename to content/docs/command-reference/pull.md diff --git a/public/static/docs/command-reference/push.md b/content/docs/command-reference/push.md similarity index 100% rename from public/static/docs/command-reference/push.md rename to content/docs/command-reference/push.md diff --git a/public/static/docs/command-reference/remote/add.md b/content/docs/command-reference/remote/add.md similarity index 100% rename from public/static/docs/command-reference/remote/add.md rename to content/docs/command-reference/remote/add.md diff --git a/public/static/docs/command-reference/remote/default.md b/content/docs/command-reference/remote/default.md similarity index 100% rename from public/static/docs/command-reference/remote/default.md rename to content/docs/command-reference/remote/default.md diff --git a/public/static/docs/command-reference/remote/index.md b/content/docs/command-reference/remote/index.md similarity index 100% rename from public/static/docs/command-reference/remote/index.md rename to content/docs/command-reference/remote/index.md diff --git a/public/static/docs/command-reference/remote/list.md b/content/docs/command-reference/remote/list.md similarity index 100% rename from public/static/docs/command-reference/remote/list.md rename to content/docs/command-reference/remote/list.md diff --git a/public/static/docs/command-reference/remote/modify.md b/content/docs/command-reference/remote/modify.md similarity index 100% rename from public/static/docs/command-reference/remote/modify.md rename to content/docs/command-reference/remote/modify.md diff --git a/public/static/docs/command-reference/remote/remove.md b/content/docs/command-reference/remote/remove.md similarity index 100% rename from public/static/docs/command-reference/remote/remove.md rename to content/docs/command-reference/remote/remove.md diff --git a/public/static/docs/command-reference/remove.md b/content/docs/command-reference/remove.md similarity index 100% rename from public/static/docs/command-reference/remove.md rename to content/docs/command-reference/remove.md diff --git a/public/static/docs/command-reference/repro.md b/content/docs/command-reference/repro.md similarity index 100% rename from public/static/docs/command-reference/repro.md rename to content/docs/command-reference/repro.md diff --git a/public/static/docs/command-reference/root.md b/content/docs/command-reference/root.md similarity index 100% rename from public/static/docs/command-reference/root.md rename to content/docs/command-reference/root.md diff --git a/public/static/docs/command-reference/run.md b/content/docs/command-reference/run.md similarity index 100% rename from public/static/docs/command-reference/run.md rename to content/docs/command-reference/run.md diff --git a/public/static/docs/command-reference/status.md b/content/docs/command-reference/status.md similarity index 100% rename from public/static/docs/command-reference/status.md rename to content/docs/command-reference/status.md diff --git a/public/static/docs/command-reference/unlock.md b/content/docs/command-reference/unlock.md similarity index 100% rename from public/static/docs/command-reference/unlock.md rename to content/docs/command-reference/unlock.md diff --git a/public/static/docs/command-reference/unprotect.md b/content/docs/command-reference/unprotect.md similarity index 100% rename from public/static/docs/command-reference/unprotect.md rename to content/docs/command-reference/unprotect.md diff --git a/public/static/docs/command-reference/update.md b/content/docs/command-reference/update.md similarity index 100% rename from public/static/docs/command-reference/update.md rename to content/docs/command-reference/update.md diff --git a/public/static/docs/command-reference/version.md b/content/docs/command-reference/version.md similarity index 100% rename from public/static/docs/command-reference/version.md rename to content/docs/command-reference/version.md diff --git a/public/static/docs/get-started/add-files.md b/content/docs/get-started/add-files.md similarity index 100% rename from public/static/docs/get-started/add-files.md rename to content/docs/get-started/add-files.md diff --git a/public/static/docs/get-started/agenda.md b/content/docs/get-started/agenda.md similarity index 97% rename from public/static/docs/get-started/agenda.md rename to content/docs/get-started/agenda.md index d1a6eeffee..1a61701c76 100644 --- a/public/static/docs/get-started/agenda.md +++ b/content/docs/get-started/agenda.md @@ -18,7 +18,7 @@ predicting tags for a given StackOverflow question. For example, we might want a classifier that can classify (or predict) posts about Python by tagging them with `python`. -![](/static/img/example-flow-2x.png) +![](/img/example-flow-2x.png) This is a natural language processing context, but NLP isn't the only area of data science where DVC can help. DVC is designed to be agnostic of frameworks, diff --git a/public/static/docs/get-started/compare-experiments.md b/content/docs/get-started/compare-experiments.md similarity index 100% rename from public/static/docs/get-started/compare-experiments.md rename to content/docs/get-started/compare-experiments.md diff --git a/public/static/docs/get-started/configure.md b/content/docs/get-started/configure.md similarity index 100% rename from public/static/docs/get-started/configure.md rename to content/docs/get-started/configure.md diff --git a/public/static/docs/get-started/connect-code-and-data.md b/content/docs/get-started/connect-code-and-data.md similarity index 100% rename from public/static/docs/get-started/connect-code-and-data.md rename to content/docs/get-started/connect-code-and-data.md diff --git a/public/static/docs/get-started/experiments.md b/content/docs/get-started/experiments.md similarity index 99% rename from public/static/docs/get-started/experiments.md rename to content/docs/get-started/experiments.md index 1f7fb337b8..b716872a2e 100644 --- a/public/static/docs/get-started/experiments.md +++ b/content/docs/get-started/experiments.md @@ -37,7 +37,7 @@ $ git commit -am "Reproduce model using bigrams" Now, we have a new `model.pkl` captured and saved. To get back to the initial version, we run `git checkout` along with `dvc checkout` command: -``` +```dvc $ git checkout baseline-experiment $ dvc checkout ``` diff --git a/public/static/docs/get-started/import-data.md b/content/docs/get-started/import-data.md similarity index 100% rename from public/static/docs/get-started/import-data.md rename to content/docs/get-started/import-data.md diff --git a/public/static/docs/get-started/index.md b/content/docs/get-started/index.md similarity index 100% rename from public/static/docs/get-started/index.md rename to content/docs/get-started/index.md diff --git a/public/static/docs/get-started/initialize.md b/content/docs/get-started/initialize.md similarity index 100% rename from public/static/docs/get-started/initialize.md rename to content/docs/get-started/initialize.md diff --git a/public/static/docs/get-started/metrics.md b/content/docs/get-started/metrics.md similarity index 100% rename from public/static/docs/get-started/metrics.md rename to content/docs/get-started/metrics.md diff --git a/public/static/docs/get-started/older-versions.md b/content/docs/get-started/older-versions.md similarity index 100% rename from public/static/docs/get-started/older-versions.md rename to content/docs/get-started/older-versions.md diff --git a/public/static/docs/get-started/pipeline.md b/content/docs/get-started/pipeline.md similarity index 100% rename from public/static/docs/get-started/pipeline.md rename to content/docs/get-started/pipeline.md diff --git a/public/static/docs/get-started/reproduce.md b/content/docs/get-started/reproduce.md similarity index 100% rename from public/static/docs/get-started/reproduce.md rename to content/docs/get-started/reproduce.md diff --git a/public/static/docs/get-started/retrieve-data.md b/content/docs/get-started/retrieve-data.md similarity index 100% rename from public/static/docs/get-started/retrieve-data.md rename to content/docs/get-started/retrieve-data.md diff --git a/public/static/docs/get-started/store-data.md b/content/docs/get-started/store-data.md similarity index 100% rename from public/static/docs/get-started/store-data.md rename to content/docs/get-started/store-data.md diff --git a/public/static/docs/get-started/visualize.md b/content/docs/get-started/visualize.md similarity index 100% rename from public/static/docs/get-started/visualize.md rename to content/docs/get-started/visualize.md diff --git a/public/static/docs/glossary.js b/content/docs/glossary.js similarity index 100% rename from public/static/docs/glossary.js rename to content/docs/glossary.js diff --git a/public/static/docs/install/completion.md b/content/docs/install/completion.md similarity index 99% rename from public/static/docs/install/completion.md rename to content/docs/install/completion.md index 4c139e3330..cd479916bd 100644 --- a/public/static/docs/install/completion.md +++ b/content/docs/install/completion.md @@ -134,7 +134,7 @@ $ exec $SHELL -l This step is optional but will make the DVC output look much nicer, by adding more colors to it. Add the following to your `~/.zshrc`: -```zsh +```bash # Case insensitive match zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}' 'r:|[._-]=* r:|=*' 'l:|=* r:|=*' diff --git a/public/static/docs/install/index.md b/content/docs/install/index.md similarity index 100% rename from public/static/docs/install/index.md rename to content/docs/install/index.md diff --git a/public/static/docs/install/linux.md b/content/docs/install/linux.md similarity index 100% rename from public/static/docs/install/linux.md rename to content/docs/install/linux.md diff --git a/public/static/docs/install/macos.md b/content/docs/install/macos.md similarity index 100% rename from public/static/docs/install/macos.md rename to content/docs/install/macos.md diff --git a/public/static/docs/install/plugins.md b/content/docs/install/plugins.md similarity index 100% rename from public/static/docs/install/plugins.md rename to content/docs/install/plugins.md diff --git a/public/static/docs/install/pre-release.md b/content/docs/install/pre-release.md similarity index 100% rename from public/static/docs/install/pre-release.md rename to content/docs/install/pre-release.md diff --git a/public/static/docs/install/windows.md b/content/docs/install/windows.md similarity index 100% rename from public/static/docs/install/windows.md rename to content/docs/install/windows.md diff --git a/public/static/docs/sidebar.json b/content/docs/sidebar.json similarity index 100% rename from public/static/docs/sidebar.json rename to content/docs/sidebar.json diff --git a/public/static/docs/tutorials/community.md b/content/docs/tutorials/community.md similarity index 100% rename from public/static/docs/tutorials/community.md rename to content/docs/tutorials/community.md diff --git a/public/static/docs/tutorials/deep/define-ml-pipeline.md b/content/docs/tutorials/deep/define-ml-pipeline.md similarity index 100% rename from public/static/docs/tutorials/deep/define-ml-pipeline.md rename to content/docs/tutorials/deep/define-ml-pipeline.md diff --git a/public/static/docs/tutorials/deep/index.md b/content/docs/tutorials/deep/index.md similarity index 94% rename from public/static/docs/tutorials/deep/index.md rename to content/docs/tutorials/deep/index.md index 2f2e22d222..da9493e990 100644 --- a/public/static/docs/tutorials/deep/index.md +++ b/content/docs/tutorials/deep/index.md @@ -13,7 +13,7 @@ and reuse. DVC has been built to address the reproducibility. -![](/static/img/reproducibility.png) +![](/img/reproducibility.png) Git branches should beautifully reflect the non-linear structure common to the ML process, where each hypothesis can be presented as a Git branch. However, @@ -28,4 +28,4 @@ and this approach will not require storing binary files in your Git repository. The diagram below describes all the DVC commands and relationships between a local cache and remote storage. -![](/static/img/flow-large.png) +![](/img/flow-large.png) diff --git a/public/static/docs/tutorials/deep/preparation.md b/content/docs/tutorials/deep/preparation.md similarity index 100% rename from public/static/docs/tutorials/deep/preparation.md rename to content/docs/tutorials/deep/preparation.md diff --git a/public/static/docs/tutorials/deep/reproducibility.md b/content/docs/tutorials/deep/reproducibility.md similarity index 100% rename from public/static/docs/tutorials/deep/reproducibility.md rename to content/docs/tutorials/deep/reproducibility.md diff --git a/public/static/docs/tutorials/deep/sharing-data.md b/content/docs/tutorials/deep/sharing-data.md similarity index 100% rename from public/static/docs/tutorials/deep/sharing-data.md rename to content/docs/tutorials/deep/sharing-data.md diff --git a/public/static/docs/tutorials/index.md b/content/docs/tutorials/index.md similarity index 100% rename from public/static/docs/tutorials/index.md rename to content/docs/tutorials/index.md diff --git a/public/static/docs/tutorials/interactive.md b/content/docs/tutorials/interactive.md similarity index 100% rename from public/static/docs/tutorials/interactive.md rename to content/docs/tutorials/interactive.md diff --git a/public/static/docs/tutorials/pipelines.md b/content/docs/tutorials/pipelines.md similarity index 99% rename from public/static/docs/tutorials/pipelines.md rename to content/docs/tutorials/pipelines.md index d6808bb074..9cc5fde18d 100644 --- a/public/static/docs/tutorials/pipelines.md +++ b/content/docs/tutorials/pipelines.md @@ -15,7 +15,7 @@ StackOverflow posts and trains the prediction model and saves it as an examples, tutorials, use cases if you want to cover other aspects of the DVC. The pipeline itself is a sequence of transformation we apply to the data file: -![](/static/img/example-flow-2x.png) +![](/img/example-flow-2x.png) DVC helps to describe these transformations and capture actual data involved - input dataset we are processing, intermediate results (useful if some diff --git a/public/static/docs/tutorials/versioning.md b/content/docs/tutorials/versioning.md similarity index 99% rename from public/static/docs/tutorials/versioning.md rename to content/docs/tutorials/versioning.md index 12e4de36c3..377fcab698 100644 --- a/public/static/docs/tutorials/versioning.md +++ b/content/docs/tutorials/versioning.md @@ -7,7 +7,7 @@ datasets and ML models using DVC commands. We'll work with a that [FranΓ§ois Chollet](https://twitter.com/fchollet) put together to show how to build a powerful image classifier using a pretty small dataset. -![](/static/img/cats-and-dogs.jpg) _Dataset to classify cats and dogs_ +![](/img/cats-and-dogs.jpg) _Dataset to classify cats and dogs_ > We highly recommend reading the FranΓ§ois' tutorial itself. It's a great > demonstration of how a general pre-trained model can be leveraged to build a @@ -95,7 +95,7 @@ This command downloads and extracts our raw dataset, consisting of 1000 labeled images for training and 800 labeled images for validation. In total, it's a 43 MB dataset, with a directory structure like this: -```sh +```bash data β”œβ”€β”€ train β”‚ β”œβ”€β”€ dogs @@ -199,7 +199,7 @@ For simplicity's sake, we keep the validation subset the same. Now our dataset has 2000 images for training and 800 images for validation, with a total size of 67 MB: -```sh +```bash data β”œβ”€β”€ train β”‚ β”œβ”€β”€ dogs @@ -248,7 +248,7 @@ to be similar to `git checkout`. All we need to do in our case is to additionally run `dvc checkout` to get the right data into the workspace. -![](/static/img/versioning.png) +![](/img/versioning.png) There are two ways of doing this: a full workspace checkout or checkout of a specific data or model file. Let's consider the full checkout first. It's pretty diff --git a/public/static/docs/understanding-dvc/collaboration-issues.md b/content/docs/understanding-dvc/collaboration-issues.md similarity index 100% rename from public/static/docs/understanding-dvc/collaboration-issues.md rename to content/docs/understanding-dvc/collaboration-issues.md diff --git a/public/static/docs/understanding-dvc/core-features.md b/content/docs/understanding-dvc/core-features.md similarity index 100% rename from public/static/docs/understanding-dvc/core-features.md rename to content/docs/understanding-dvc/core-features.md diff --git a/public/static/docs/understanding-dvc/existing-tools.md b/content/docs/understanding-dvc/existing-tools.md similarity index 100% rename from public/static/docs/understanding-dvc/existing-tools.md rename to content/docs/understanding-dvc/existing-tools.md diff --git a/public/static/docs/understanding-dvc/how-it-works.md b/content/docs/understanding-dvc/how-it-works.md similarity index 100% rename from public/static/docs/understanding-dvc/how-it-works.md rename to content/docs/understanding-dvc/how-it-works.md diff --git a/public/static/docs/understanding-dvc/related-technologies.md b/content/docs/understanding-dvc/related-technologies.md similarity index 100% rename from public/static/docs/understanding-dvc/related-technologies.md rename to content/docs/understanding-dvc/related-technologies.md diff --git a/public/static/docs/understanding-dvc/resources.md b/content/docs/understanding-dvc/resources.md similarity index 100% rename from public/static/docs/understanding-dvc/resources.md rename to content/docs/understanding-dvc/resources.md diff --git a/public/static/docs/understanding-dvc/what-is-dvc.md b/content/docs/understanding-dvc/what-is-dvc.md similarity index 100% rename from public/static/docs/understanding-dvc/what-is-dvc.md rename to content/docs/understanding-dvc/what-is-dvc.md diff --git a/public/static/docs/use-cases/data-registries.md b/content/docs/use-cases/data-registries.md similarity index 99% rename from public/static/docs/use-cases/data-registries.md rename to content/docs/use-cases/data-registries.md index 5d258b54f7..558cdcbcbd 100644 --- a/public/static/docs/use-cases/data-registries.md +++ b/content/docs/use-cases/data-registries.md @@ -8,7 +8,7 @@ with commands such as `dvc add`. With the aim to enable reusability of these depend on data from an external DVC repository, **similar to package management systems, but for data science projects**. -![](/static/img/data-registry.png) _Data and models as code_ +![](/img/data-registry.png) _Data and models as code_ Keeping this in mind, we could build a DVC project dedicated to tracking and versioning _datasets_ (or any large data, even ML models). This way diff --git a/public/static/docs/use-cases/index.md b/content/docs/use-cases/index.md similarity index 100% rename from public/static/docs/use-cases/index.md rename to content/docs/use-cases/index.md diff --git a/public/static/docs/use-cases/shared-development-server.md b/content/docs/use-cases/shared-development-server.md similarity index 98% rename from public/static/docs/use-cases/shared-development-server.md rename to content/docs/use-cases/shared-development-server.md index a96a19150a..4827163ae4 100644 --- a/public/static/docs/use-cases/shared-development-server.md +++ b/content/docs/use-cases/shared-development-server.md @@ -7,7 +7,7 @@ storage on a server accessed by several users, in a way that enables almost instantaneous workspace restoration/switching speed for everyone – similar to `git checkout` for your code. -![](/static/img/shared-server.png) +![](/img/shared-server.png) ## Preparation diff --git a/public/static/docs/use-cases/sharing-data-and-model-files.md b/content/docs/use-cases/sharing-data-and-model-files.md similarity index 98% rename from public/static/docs/use-cases/sharing-data-and-model-files.md rename to content/docs/use-cases/sharing-data-and-model-files.md index a354c9988e..77c583e562 100644 --- a/public/static/docs/use-cases/sharing-data-and-model-files.md +++ b/content/docs/use-cases/sharing-data-and-model-files.md @@ -9,7 +9,7 @@ supports Amazon S3, Microsoft Azure Blob Storage, Google Drive, Google Cloud Storage, SSH, HDFS, and other remote locations. The list is constantly growing. (For a complete list and configuration instructions, refer to `dvc remote add`.) -![](/static/img/model-sharing-digram.png) +![](/img/model-sharing-digram.png) As an example, let's take a look at how you could setup an S3 [remote storage](/doc/command-reference/remote) for a DVC project, diff --git a/public/static/docs/use-cases/versioning-data-and-model-files.md b/content/docs/use-cases/versioning-data-and-model-files.md similarity index 98% rename from public/static/docs/use-cases/versioning-data-and-model-files.md rename to content/docs/use-cases/versioning-data-and-model-files.md index 8c4c3b4e29..dbf45e37ce 100644 --- a/public/static/docs/use-cases/versioning-data-and-model-files.md +++ b/content/docs/use-cases/versioning-data-and-model-files.md @@ -13,7 +13,7 @@ for versioning. To actually store the data, DVC supports various types of [remote storage](/doc/command-reference/remote). This allows easily saving and sharing data alongside code. -![](/static/img/model-versioning-diagram.png) +![](/img/model-versioning-diagram.png) In this basic scenario, DVC is a better replacement for `git-lfs` (see [Related Technologies](/doc/understanding-dvc/related-technologies)) and for @@ -113,7 +113,7 @@ If you run `git status` you will see that `data.dvc` is modified and currently points to the `v1.0` version of the cached data. Meanwhile, code and model files are their latest versions. -![](/static/img/versioning.png) +![](/img/versioning.png) To share your data with others you need to setup a [data storage](/doc/command-reference/remote). See the diff --git a/public/static/docs/user-guide/analytics.md b/content/docs/user-guide/analytics.md similarity index 100% rename from public/static/docs/user-guide/analytics.md rename to content/docs/user-guide/analytics.md diff --git a/public/static/docs/user-guide/contributing/core.md b/content/docs/user-guide/contributing/core.md similarity index 100% rename from public/static/docs/user-guide/contributing/core.md rename to content/docs/user-guide/contributing/core.md diff --git a/public/static/docs/user-guide/contributing/docs.md b/content/docs/user-guide/contributing/docs.md similarity index 93% rename from public/static/docs/user-guide/contributing/docs.md rename to content/docs/user-guide/contributing/docs.md index bdb41f0301..49f43a5239 100644 --- a/public/static/docs/user-guide/contributing/docs.md +++ b/content/docs/user-guide/contributing/docs.md @@ -7,16 +7,15 @@ website. ## Structure of the project -To contribute documentation, these are the relevant locations under -`public/static/`: +To contribute documentation, these are the relevant locations: -- [Content](https://github.com/iterative/dvc.org/tree/master/public/static/docs) +- [Content](https://github.com/iterative/dvc.org/tree/master/content/docs) (`docs/`): [Markdown](https://guides.github.com/features/mastering-markdown/) files of the different pages to render dynamically in the browser. -- [Images](https://github.com/iterative/dvc.org/tree/master/public/static/img) +- [Images](https://github.com/iterative/dvc.org/tree/master/static/img) (`img/`): Add new images (png, svg, etc.) here. Use them in Markdown files - like this: `![](/static/img/.gif)`. -- [Sections](https://github.com/iterative/dvc.org/tree/master/public/static/docs/sidebar.json) + like this: `![](/img/.gif)`. +- [Sections](https://github.com/iterative/dvc.org/tree/master/content/docs/sidebar.json) (`docs/sidebar.json`): Edit it to register a new section for the navigation menu. @@ -153,7 +152,7 @@ pre-commit hook that is integrated when `yarn` installs the project dependencies > Check out the `.md` source code of any command reference to get a better idea, > for example in -> [this very file](https://raw.githubusercontent.com/iterative/dvc.org/master/public/static/docs/user-guide/contributing/docs.md). +> [this very file](https://raw.githubusercontent.com/iterative/dvc.org/master/content/docs/user-guide/contributing/docs.md). ## General language guidelines diff --git a/public/static/docs/user-guide/dvc-file-format.md b/content/docs/user-guide/dvc-file-format.md similarity index 100% rename from public/static/docs/user-guide/dvc-file-format.md rename to content/docs/user-guide/dvc-file-format.md diff --git a/public/static/docs/user-guide/dvc-files-and-directories.md b/content/docs/user-guide/dvc-files-and-directories.md similarity index 100% rename from public/static/docs/user-guide/dvc-files-and-directories.md rename to content/docs/user-guide/dvc-files-and-directories.md diff --git a/public/static/docs/user-guide/dvcignore.md b/content/docs/user-guide/dvcignore.md similarity index 100% rename from public/static/docs/user-guide/dvcignore.md rename to content/docs/user-guide/dvcignore.md diff --git a/public/static/docs/user-guide/external-dependencies.md b/content/docs/user-guide/external-dependencies.md similarity index 100% rename from public/static/docs/user-guide/external-dependencies.md rename to content/docs/user-guide/external-dependencies.md diff --git a/public/static/docs/user-guide/index.md b/content/docs/user-guide/index.md similarity index 100% rename from public/static/docs/user-guide/index.md rename to content/docs/user-guide/index.md diff --git a/public/static/docs/user-guide/large-dataset-optimization.md b/content/docs/user-guide/large-dataset-optimization.md similarity index 100% rename from public/static/docs/user-guide/large-dataset-optimization.md rename to content/docs/user-guide/large-dataset-optimization.md diff --git a/public/static/docs/user-guide/managing-external-data.md b/content/docs/user-guide/managing-external-data.md similarity index 100% rename from public/static/docs/user-guide/managing-external-data.md rename to content/docs/user-guide/managing-external-data.md diff --git a/public/static/docs/user-guide/privacy.md b/content/docs/user-guide/privacy.md similarity index 100% rename from public/static/docs/user-guide/privacy.md rename to content/docs/user-guide/privacy.md diff --git a/public/static/docs/user-guide/running-dvc-on-windows.md b/content/docs/user-guide/running-dvc-on-windows.md similarity index 100% rename from public/static/docs/user-guide/running-dvc-on-windows.md rename to content/docs/user-guide/running-dvc-on-windows.md diff --git a/public/static/docs/user-guide/setup-google-drive-remote.md b/content/docs/user-guide/setup-google-drive-remote.md similarity index 97% rename from public/static/docs/user-guide/setup-google-drive-remote.md rename to content/docs/user-guide/setup-google-drive-remote.md index 2ed6530032..2b620bfd6f 100644 --- a/public/static/docs/user-guide/setup-google-drive-remote.md +++ b/content/docs/user-guide/setup-google-drive-remote.md @@ -24,7 +24,7 @@ API connections, and its ENABLE APIS AND SERVICES**. Find and select the "Google Drive API" in the API Library, and click on the **ENABLE** button. - ![](/static/img/gdrive-enable-apis-and-services.png) + ![](/img/gdrive-enable-apis-and-services.png) 4. Go back to **APIs & Services** in the left sidebar, and select **OAuth consent screen**. Chose a **User Type** and click **CREATE**. On the next @@ -35,7 +35,7 @@ API connections, and its credentials** dropdown to select **OAuth client ID**. Chose **Other** and click **Create** to proceed with a default client name. - ![](/static/img/gdrive-create-credentials.png) + ![](/img/gdrive-create-credentials.png) 6. The newly generated **client ID** and **client secret** should be shown to you now, and you can always come back to **Credentials** to fetch them. diff --git a/public/static/docs/user-guide/troubleshooting.md b/content/docs/user-guide/troubleshooting.md similarity index 100% rename from public/static/docs/user-guide/troubleshooting.md rename to content/docs/user-guide/troubleshooting.md diff --git a/public/static/docs/user-guide/updating-tracked-files.md b/content/docs/user-guide/updating-tracked-files.md similarity index 100% rename from public/static/docs/user-guide/updating-tracked-files.md rename to content/docs/user-guide/updating-tracked-files.md diff --git a/gatsby-browser.js b/gatsby-browser.js new file mode 100644 index 0000000000..8b0fea8d96 --- /dev/null +++ b/gatsby-browser.js @@ -0,0 +1,5 @@ +/* eslint-env node */ + +const PageWrapper = require('./src/components/PageWrapper').default + +exports.wrapPageElement = PageWrapper diff --git a/gatsby-config.js b/gatsby-config.js new file mode 100644 index 0000000000..9952819eaf --- /dev/null +++ b/gatsby-config.js @@ -0,0 +1,100 @@ +/* eslint-env node */ + +const path = require('path') + +require('./config/prismjs/dvc') +require('./config/prismjs/usage') + +const apiMiddleware = require('./middleware/api') +const redirectsMiddleware = require('./middleware/redirects') + +const title = 'Data Version Control Β· DVC' +const description = + 'Open-source version control system for Data Science and Machine Learning ' + + 'projects. Git-like experience to organize your data, models, and ' + + 'experiments.' + +const keywords = [ + 'data version control', + 'machine learning', + 'models management' +] + +const plugins = [ + { + resolve: 'gatsby-source-filesystem', + options: { + name: 'blog', + path: path.join(__dirname, 'content', 'docs') + } + }, + { + resolve: 'gatsby-transformer-remark', + options: { + plugins: [ + 'gatsby-remark-dvc-linker', + 'gatsby-remark-prismjs', + 'gatsby-remark-copy-linked-files', + 'gatsby-remark-smartypants', + { + resolve: 'gatsby-remark-external-links' + }, + { + resolve: 'gatsby-remark-autolink-headers', + options: { + enableCustomId: true, + isIconAfterHeader: true + } + } + ] + } + }, + 'gatsby-plugin-catch-links', + { + resolve: 'gatsby-plugin-manifest', + options: { + background_color: '#eff4f8', + display: 'minimal-ui', + icon: 'static/favicon-512x512.png', + name: 'dvc.org', + short_name: 'dvc.org', + start_url: '/', + theme_color: '#eff4f8' + } + }, + 'gatsby-plugin-react-helmet', + 'gatsby-plugin-styled-components', + 'gatsby-plugin-sitemap', + { + resolve: 'gatsby-plugin-sentry', + options: { + dsn: process.env.SENTRY_DSN, + environment: process.env.NODE_ENV, + enabled: process.env.NODE_ENV === 'production' + } + } +] + +if (process.env.CONTEXT === 'production') { + plugins.push({ + options: { + respectDNT: true, + trackingId: process.env.GA_ID + }, + resolve: 'gatsby-plugin-google-analytics' + }) +} + +module.exports = { + plugins, + siteMetadata: { + description, + keywords, + siteUrl: 'https://dvc.org', + title + }, + developMiddleware: app => { + app.use(redirectsMiddleware) + app.use('/api', apiMiddleware) + } +} diff --git a/gatsby-node.js b/gatsby-node.js new file mode 100644 index 0000000000..2c3a68763c --- /dev/null +++ b/gatsby-node.js @@ -0,0 +1,115 @@ +/* eslint-env node */ + +const path = require('path') +const GithubSlugger = require('github-slugger') + +const { getItemBySource } = require('./src/utils/sidebar') + +const slugger = new GithubSlugger() + +// Generate hedings data from markdown + +const SLUG_REGEXP = /\s+{#([a-z0-9-]*[a-z0-9]+)}\s*$/ + +function extractSlugFromTitle(title) { + // extracts expressions like {#too-many-files} from the end of a title + const meta = title.match(SLUG_REGEXP) + + if (meta) { + return [title.substring(0, meta.index), meta[1]] + } + return [title, slugger.slug(title)] +} + +const parseHeadings = text => { + const headingRegex = /\n(## \s*)(.*)/g + const matches = [] + let match + do { + match = headingRegex.exec(text) + if (match) { + const [title, slug] = extractSlugFromTitle(match[2]) + matches.push({ + text: title, + slug: slug + }) + } + } while (match) + + slugger.reset() + return matches +} + +exports.onCreateNode = ({ node, actions }) => { + const { createNodeField } = actions + + if (node.internal.type === 'MarkdownRemark') { + const docsPath = path.join(__dirname, 'content') + + const source = node.fileAbsolutePath.replace(docsPath, '') + + const { path: value } = getItemBySource(source) + + createNodeField({ + name: 'slug', + node, + value + }) + } +} + +exports.createPages = async ({ graphql, actions }) => { + const { createPage } = actions + + const docPage = path.resolve('./src/templates/doc.js') + + const result = await graphql( + ` + { + docs: allMarkdownRemark( + filter: { fileAbsolutePath: { regex: "/content/docs/" } } + limit: 9999 + ) { + edges { + node { + rawMarkdownBody + fields { + slug + } + } + } + } + } + ` + ) + + if (result.errors) { + throw result.errors + } + + const docs = result.data.docs.edges + + docs.forEach(doc => { + const headings = parseHeadings(doc.node.rawMarkdownBody) + + if (doc.node.fields.slug) { + createPage({ + component: docPage, + path: doc.node.fields.slug, + context: { + slug: doc.node.fields.slug, + headings + } + }) + } + }) +} + +exports.onCreatePage = ({ page, actions }) => { + if (/^\/404/.test(page.path)) { + const newPage = { ...page, context: { ...page.context, is404: true } } + + actions.deletePage(page) + actions.createPage(newPage) + } +} diff --git a/gatsby-ssr.js b/gatsby-ssr.js new file mode 100644 index 0000000000..8b0fea8d96 --- /dev/null +++ b/gatsby-ssr.js @@ -0,0 +1,5 @@ +/* eslint-env node */ + +const PageWrapper = require('./src/components/PageWrapper').default + +exports.wrapPageElement = PageWrapper diff --git a/jest.config.js b/jest.config.js index 118fc179d2..d344eca3cb 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,3 +1,5 @@ +/* eslint-env node */ + // For a detailed explanation regarding each configuration property, visit: // https://jestjs.io/docs/en/configuration.html @@ -5,5 +7,6 @@ module.exports = { testEnvironment: 'node', transform: { '^.+\\.js?$': 'babel-jest' - } + }, + testPathIgnorePatterns: ['/node_modules/', '/.cache', '/public/'] } diff --git a/pages/api/blog.js b/middleware/api/blog.js similarity index 66% rename from pages/api/blog.js rename to middleware/api/blog.js index ce1d3f4e33..9b0643f6cf 100644 --- a/pages/api/blog.js +++ b/middleware/api/blog.js @@ -1,6 +1,8 @@ -import fetch from 'isomorphic-fetch' +/* eslint-env node */ -export default async (_, res) => { +const fetch = require('isomorphic-fetch') + +module.exports = async (_, res) => { try { const response = await fetch(`https://blog.dvc.org/api/posts.json`) @@ -10,7 +12,7 @@ export default async (_, res) => { return } - const data = await response.text() + const data = await response.json() res.status(200).json(data) } catch { diff --git a/pages/api/comments.js b/middleware/api/comments.js similarity index 86% rename from pages/api/comments.js rename to middleware/api/comments.js index 1b131e8655..f177aff6d2 100644 --- a/pages/api/comments.js +++ b/middleware/api/comments.js @@ -9,11 +9,11 @@ * potential ability to cache comments count in the future. */ -import fetch from 'isomorphic-fetch' -import Cors from 'micro-cors' -import NodeCache from 'node-cache' +const fetch = require('isomorphic-fetch') +const Cors = require('micro-cors') +const NodeCache = require('node-cache') -import { BLOG_URL, FORUM_URL } from '../../src/consts' +const { BLOG_URL, FORUM_URL } = require('../../src/consts') const cache = new NodeCache({ stdTTL: 900 }) @@ -73,4 +73,4 @@ const getCommentCount = async (req, res) => { } } -export default cors(getCommentCount) +module.exports = cors(getCommentCount) diff --git a/pages/api/discourse.js b/middleware/api/discourse.js similarity index 85% rename from pages/api/discourse.js rename to middleware/api/discourse.js index ba5463c69a..9fbe2759a1 100644 --- a/pages/api/discourse.js +++ b/middleware/api/discourse.js @@ -1,15 +1,15 @@ /* eslint-env node */ -import fetch from 'isomorphic-fetch' -import NodeCache from 'node-cache' +const fetch = require('isomorphic-fetch') +const NodeCache = require('node-cache') -import { FORUM_URL } from '../../src/consts' +const { FORUM_URL } = require('../../src/consts') const cache = new NodeCache({ stdTTL: 900 }) const dev = process.env.NODE_ENV === 'development' -export default async (_, res) => { +module.exports = async (_, res) => { if (cache.get('topics')) { if (dev) console.log('Using cache for "topics"') diff --git a/pages/api/github.js b/middleware/api/github.js similarity index 92% rename from pages/api/github.js rename to middleware/api/github.js index 1a7165b0fe..cc239a8ab6 100644 --- a/pages/api/github.js +++ b/middleware/api/github.js @@ -1,13 +1,13 @@ /* eslint-env node */ -import { graphql } from '@octokit/graphql' -import NodeCache from 'node-cache' +const { graphql } = require('@octokit/graphql') +const NodeCache = require('node-cache') const cache = new NodeCache({ stdTTL: 900 }) const dev = process.env.NODE_ENV === 'development' -export default async (_, res) => { +module.exports = async (_, res) => { if (!process.env.GITHUB_TOKEN) { res.status(200).json({ issues: [] }) } else { diff --git a/middleware/api/index.js b/middleware/api/index.js new file mode 100644 index 0000000000..6fc73fbd95 --- /dev/null +++ b/middleware/api/index.js @@ -0,0 +1,15 @@ +/* eslint-env node */ + +const routes = require('express').Router() + +const blog = require('./blog') +const comments = require('./comments') +const discourse = require('./discourse') +const github = require('./github') + +routes.get('/blog', blog) +routes.get('/comments', comments) +routes.get('/discourse', discourse) +routes.get('/github', github) + +module.exports = routes diff --git a/middleware/notFound/index.js b/middleware/notFound/index.js new file mode 100644 index 0000000000..677c77e159 --- /dev/null +++ b/middleware/notFound/index.js @@ -0,0 +1,7 @@ +/* eslint-env node */ + +const path = require('path') + +module.exports = (req, res) => { + res.sendFile(path.join(`${__dirname}`, '..', '..', 'public', '404.html')) +} diff --git a/middleware/redirects/index.js b/middleware/redirects/index.js new file mode 100644 index 0000000000..5fffc9df93 --- /dev/null +++ b/middleware/redirects/index.js @@ -0,0 +1,36 @@ +/* eslint-env node */ + +const { getRedirect } = require('../../src/utils/redirects') +const { parse } = require('url') +const { stringify } = require('querystring') + +const dev = process.env.NODE_ENV !== 'production' + +module.exports = (req, res, next) => { + const parsedUrl = parse(req.url, true) + const { pathname, query } = parsedUrl + const host = req.headers.host + + let [redirectCode, redirectLocation] = getRedirect(host, pathname, { + req, + dev + }) + + if (redirectLocation) { + // HTTP redirects + + const queryStr = stringify(query) + if (queryStr) { + redirectLocation += '?' + queryStr + } + res.writeHead(redirectCode, { + Location: redirectLocation + }) + + res.end() + + return + } + + next() +} diff --git a/next.config.js b/next.config.js deleted file mode 100644 index c1a8c1a98c..0000000000 --- a/next.config.js +++ /dev/null @@ -1,14 +0,0 @@ -/* eslint-env node */ - -const withSourceMaps = require('@zeit/next-source-maps') - -const settings = withSourceMaps({ - webpack(config) { - return config - }, - env: { - SENTRY_DSN: process.env.SENTRY_DSN - } -}) - -module.exports = settings diff --git a/package.json b/package.json index 4d8fe4ebd8..b698963263 100644 --- a/package.json +++ b/package.json @@ -4,15 +4,15 @@ "description": "dvc.org – website source code", "main": "index.js", "scripts": { - "dev": "node server.js", + "develop": "gatsby develop", "debug": "node --inspect-brk server.js", - "build": "next build", + "build": "gatsby build", "test": "jest", "start": "./scripts/clear-cloudflare-cache.js; NODE_ENV=production node server.js", "format-staged": "pretty-quick --staged --no-restage --bail", - "format-check": "prettier --check '{.,pages/**,public/static/docs/**,src/**}/*.{js,md,json}'", - "lint-check": "eslint --ext .json,.js src pages", - "format-all": "prettier --write '{.,pages/**,public/static/docs/**,src/**}/*.{js,md,json}'", + "format-check": "prettier --check '{.,pages/**,content/docs/**,src/**}/*.{js,md,json}'", + "lint-check": "eslint --ext .json,.js src middleware", + "format-all": "prettier --write '{.,pages/**,content/docs/**,src/**}/*.{js,md,json}'", "format": "prettier --write", "link-check": "scripts/link-check-git-all.sh", "link-check-diff": "scripts/link-check-git-diff.sh" @@ -29,11 +29,15 @@ "homepage": "https://github.com/iterative/dvc.org#readme", "dependencies": { "@octokit/graphql": "^4.3.1", + "@reach/router": "^1.3.1", "@sentry/browser": "^5.12.1", - "@zeit/next-source-maps": "^0.0.3", "color": "^3.1.2", "date-fns": "^2.8.1", + "docsearch.js": "^2.6.3", "dom-scroll-into-view": "^2.0.1", + "express": "^4.17.1", + "gatsby": "^2.19.21", + "gatsby-link": "^2.2.29", "github-markdown-css": "^3.0.1", "isomorphic-fetch": "^2.2.1", "lodash.fill": "^3.4.0", @@ -43,22 +47,24 @@ "lodash.throttle": "^4.1.1", "lodash.topairs": "^4.3.0", "micro-cors": "^0.1.1", - "next": "^9.1.6", "node-cache": "^5.1.0", "perfect-scrollbar": "^1.4.0", + "prismjs": "^1.19.0", "prop-types": "^15.7.2", "react": "^16.12.0", "react-collapse": "^5.0.1", "react-collapsible": "^2.6.2", "react-dom": "^16.12.0", "react-ga": "^2.7.0", + "react-helmet": "^5.2.1", "react-markdown": "^4.2.2", "react-popover": "^0.5.10", "react-scroll": "^1.7.13", "react-slick": "^0.25.2", - "react-syntax-highlighter": "^11.0.2", "react-use": "^13.24.0", + "rehype-react": "^4.0.1", "request": "^2.88.0", + "slick-carousel": "^1.8.1", "styled-components": "^4.4.1", "styled-reset": "^4.0.8", "unist-util-visit": "2.0.1" @@ -67,6 +73,7 @@ "@babel/core": "^7.7.7", "babel-eslint": "^10.0.3", "babel-jest": "^24.9.0", + "babel-plugin-styled-components": "^1.10.7", "babel-plugin-transform-define": "^2.0.0", "babel-plugin-transform-object-assign": "^6.22.0", "eslint": "^6.7.2", @@ -75,6 +82,20 @@ "eslint-plugin-jsx-a11y": "^6.2.3", "eslint-plugin-prettier": "^3.1.1", "eslint-plugin-react": "^7.17.0", + "gatsby-plugin-catch-links": "^2.1.26", + "gatsby-plugin-google-analytics": "^2.1.36", + "gatsby-plugin-manifest": "^2.2.42", + "gatsby-plugin-react-helmet": "^3.1.22", + "gatsby-plugin-sentry": "^1.0.1", + "gatsby-plugin-sitemap": "^2.2.27", + "gatsby-plugin-styled-components": "^3.1.19", + "gatsby-remark-autolink-headers": "^2.1.24", + "gatsby-remark-copy-linked-files": "^2.1.37", + "gatsby-remark-external-links": "^0.0.4", + "gatsby-remark-prismjs": "^3.3.31", + "gatsby-remark-smartypants": "^2.1.21", + "gatsby-source-filesystem": "^2.1.48", + "gatsby-transformer-remark": "^2.6.53", "husky": "^4.0.10", "jest": "^24.9.0", "lint-staged": "^10.0.0", diff --git a/pages/_app.js b/pages/_app.js deleted file mode 100644 index 10f9f70d27..0000000000 --- a/pages/_app.js +++ /dev/null @@ -1,31 +0,0 @@ -/* global process */ - -import React from 'react' -import App from 'next/app' -import * as Sentry from '@sentry/browser' - -Sentry.init({ - dsn: process.env.SENTRY_DSN -}) - -class MyApp extends App { - componentDidCatch(error, errorInfo) { - Sentry.withScope(scope => { - Object.keys(errorInfo).forEach(key => { - scope.setExtra(key, errorInfo[key]) - }) - - Sentry.captureException(error) - }) - - super.componentDidCatch(error, errorInfo) - } - - render() { - const { Component, pageProps } = this.props - - return - } -} - -export default MyApp diff --git a/pages/_document.js b/pages/_document.js deleted file mode 100644 index c9e36105e5..0000000000 --- a/pages/_document.js +++ /dev/null @@ -1,145 +0,0 @@ -/* eslint-env node */ - -import React from 'react' -import Document, { Head, Main, NextScript } from 'next/document' -import { ServerStyleSheet } from 'styled-components' -import * as Sentry from '@sentry/browser' - -process.on('unhandledRejection', err => { - Sentry.captureException(err) -}) - -process.on('uncaughtException', err => { - Sentry.captureException(err) -}) - -import { - META_BASE_TITLE, - META_DESCRIPTION, - META_KEYWORDS, - META_SOCIAL_IMAGE -} from '../src/consts' - -const inject = str => ( -
-) - -export default class Page extends Document { - static getInitialProps({ renderPage }) { - const sheet = new ServerStyleSheet() - const page = renderPage(App => props => - sheet.collectStyles() - ) - const styleTags = sheet.getStyleElement() - return { ...page, styleTags } - } - - render() { - return ( - <> - - - - - - - - - - - - - - - - - - - - - - - ` - )} - - - - ) - } -} diff --git a/pages/community.js b/pages/community.js deleted file mode 100644 index 2553720e5a..0000000000 --- a/pages/community.js +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react' -import Head from 'next/head' - -import Community from '../src/components/Community' - -import { META_BASE_TITLE } from '../src/consts' - -export default function CommunityPage() { - return ( - <> - - - - Community | {META_BASE_TITLE} - - - - ) -} diff --git a/pages/doc.js b/pages/doc.js deleted file mode 100644 index 0521bf3258..0000000000 --- a/pages/doc.js +++ /dev/null @@ -1,65 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' -import fetch from 'isomorphic-fetch' - -import Error from 'next/error' -import Head from 'next/head' - -import Documentation from '../src/components/Documentation' - -import { getItemByPath } from '../src/utils/sidebar' -import { makeAbsoluteURL } from '../src/utils/api' - -import { META_BASE_TITLE } from '../src/consts' - -export default function DocumentationPage({ item, markdown, errorCode }) { - if (errorCode) { - return - } - - return ( - <> - - - {item.label} | {META_BASE_TITLE} - - - - - ) -} - -DocumentationPage.propTypes = { - item: PropTypes.object, - markdown: PropTypes.string, - errorCode: PropTypes.number -} - -DocumentationPage.getInitialProps = async ({ asPath, req }) => { - const item = getItemByPath(asPath.split(/[?#]/)[0]) - - if (!item) { - return { - errorCode: 404 - } - } - - try { - const res = await fetch(makeAbsoluteURL(req, item.source)) - - if (res.status !== 200) { - return { - errorCode: res.status - } - } - - const markdown = await res.text() - - return { - item, - markdown - } - } catch { - window.location.reload() - } -} diff --git a/pages/features.js b/pages/features.js deleted file mode 100644 index e8d0145e79..0000000000 --- a/pages/features.js +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react' - -import Head from 'next/head' - -import Features from '../src/components/Features' - -import { META_BASE_TITLE } from '../src/consts' - -export default function FeaturesPage() { - return ( - <> - - Features | {META_BASE_TITLE} - - - - ) -} diff --git a/pages/index.js b/pages/index.js deleted file mode 100644 index 73c2c0faa3..0000000000 --- a/pages/index.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react' - -import Head from 'next/head' - -import Home from '../src/components/Home' - -import { META_BASE_TITLE } from '../src/consts' - -export default function HomePage() { - return ( - <> - - - - {META_BASE_TITLE} - - - - ) -} diff --git a/pages/support.js b/pages/support.js deleted file mode 100644 index 79a80ce0b8..0000000000 --- a/pages/support.js +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react' - -import Head from 'next/head' - -import Support from '../src/components/Support' - -import { META_BASE_TITLE } from '../src/consts' - -export default function SupportPage() { - return ( - <> - - Support | {META_BASE_TITLE} - - - - ) -} diff --git a/plugins/gatsby-remark-dvc-linker/index.js b/plugins/gatsby-remark-dvc-linker/index.js new file mode 100644 index 0000000000..9a6f13a937 --- /dev/null +++ b/plugins/gatsby-remark-dvc-linker/index.js @@ -0,0 +1,43 @@ +/* eslint-env node */ + +const visit = require('unist-util-visit') +const { getItemByPath } = require('../../src/utils/sidebar') + +const DVC_REGEXP = /dvc\s+[a-z][a-z-.]*/ +const COMMAND_REGEXP = /^[a-z][a-z-]*$/ +const COMMAND_ROOT = '/doc/command-reference/' + +module.exports = ({ markdownAST }) => { + visit(markdownAST, 'inlineCode', function(node, index, parent) { + if (parent.type !== 'link' && DVC_REGEXP.test(node.value)) { + let parts = node.value.split(/\s+/) + let url + + const hasThirdSegment = parts[2] && COMMAND_REGEXP.test(parts[2]) + const isCommandPageExists = getItemByPath(`${COMMAND_ROOT}${parts[1]}`) + const isSubcommandPageExists = + isCommandPageExists && + hasThirdSegment && + getItemByPath(`${COMMAND_ROOT}${parts[1]}/${parts[2]}`) + + if (isSubcommandPageExists) { + url = `${COMMAND_ROOT}${parts[1]}/${parts[2]}` + } else if (isCommandPageExists && hasThirdSegment) { + url = `${COMMAND_ROOT}${parts[1]}#${parts[2]}` + } else if (isCommandPageExists) { + url = `${COMMAND_ROOT}${parts[1]}` + } + + if (url) { + parent.children[index] = { + type: 'link', + url: url, + children: [node], + position: node.position + } + } + } + }) + + return markdownAST +} diff --git a/plugins/gatsby-remark-dvc-linker/package.json b/plugins/gatsby-remark-dvc-linker/package.json new file mode 100644 index 0000000000..f4227d784e --- /dev/null +++ b/plugins/gatsby-remark-dvc-linker/package.json @@ -0,0 +1,7 @@ +{ + "name": "gatsby-remark-dvc-linker", + "version": "1.0.0", + "main": "index.js", + "author": "Ivan Shcheklein", + "license": "Apache-2.0" +} diff --git a/redirects-list.json b/redirects-list.json index b8f64af146..2f3bcb6ab8 100644 --- a/redirects-list.json +++ b/redirects-list.json @@ -9,5 +9,9 @@ "^/doc/commands-reference(/.*)?$ /doc/command-reference$1", "^/doc/tutorial/?$ /doc/tutorials", "^/doc/tutorial/(.*)? /doc/tutorials/deep/$1", - "^/doc/use-cases/data-and-model-files-versioning/?$ /doc/use-cases/versioning-data-and-model-files" + "^/doc/use-cases/data-and-model-files-versioning/?$ /doc/use-cases/versioning-data-and-model-files", + "^/doc/?$ /doc/get-started 307", + "^/doc/understanding-dvc/?$ /doc/understanding-dvc/collaboration-issues 307", + "^/doc/changelog/?$ /doc/changelog/0.18 307", + "^/doc/user-guide/contributing/?$ /doc/user-guide/contributing/core 307" ] diff --git a/scripts/exclude-links.txt b/scripts/exclude-links.txt index d9f10dcbea..37933688b8 100644 --- a/scripts/exclude-links.txt +++ b/scripts/exclude-links.txt @@ -16,7 +16,7 @@ https://drive.google.com/drive/folders/0AIac4JZqHhKmUk9PDA https://dvc.org$ https://dvc.org/doc/command-reference/foo https://dvc.org/foo -https://dvc.org/static/img/.gif +https://dvc.org/img/.gif https://example.com/data.txt https://example.com/foo https://dvc.org/foo/bar?baz diff --git a/scripts/link-check-git-all.sh b/scripts/link-check-git-all.sh index 2251fb36e5..fe7e7227c4 100755 --- a/scripts/link-check-git-all.sh +++ b/scripts/link-check-git-all.sh @@ -1,3 +1,3 @@ #!/usr/bin/env bash -(find pages/ public/static/docs/ src/ .github/ -name '*.md' -o -name '*.js' && ls *.md *.js) \ +(find pages/ content/docs/ src/ .github/ -name '*.md' -o -name '*.js' && ls *.md *.js) \ | xargs -n1 -P8 $(dirname "$0")/link-check.sh diff --git a/server.js b/server.js index 673efcab86..467723dff0 100644 --- a/server.js +++ b/server.js @@ -1,68 +1,19 @@ /* eslint-env node */ -/* - * Custom server (with custom routes) See - * https://nextjs.org/docs/advanced-features/custom-server - * - * NOTE: This file doesn't go through babel or webpack. Make sure the syntax and - * sources this file requires are compatible with the current node version you - * are running. - */ +const express = require('express') +const app = express() -const { createServer } = require('http') -const { parse } = require('url') -const { stringify } = require('querystring') -const next = require('next') +const apiMiddleware = require('./middleware/api') +const redirectsMiddleware = require('./middleware/redirects') +const notFoundMiddleware = require('./middleware/notFound') -const { getItemByPath } = require('./src/utils/sidebar') -const { getRedirect } = require('./src/utils/redirects') - -const dev = process.env.NODE_ENV !== 'production' -const app = next({ dev }) -const handle = app.getRequestHandler() const port = process.env.PORT || 3000 -app.prepare().then(() => { - createServer((req, res) => { - const parsedUrl = parse(req.url, true) - const { pathname, query } = parsedUrl - const host = req.headers.host - - res.setHeader('Cache-Control', 'public, max-age=0, s-maxage=99999') - - let [redirectCode, redirectLocation] = getRedirect(host, pathname, { - req, - dev - }) - - if (redirectLocation) { - // HTTP redirects - - const queryStr = stringify(query) - if (queryStr) { - redirectLocation += '?' + queryStr - } - res.writeHead(redirectCode, { - Location: redirectLocation - }) - res.end() - } else if (/^\/doc(\/.*)?$/.test(pathname)) { - // Docs Engine handler +app.use(redirectsMiddleware) +app.use('/api', apiMiddleware) - // Force 404 response code for any inexistent /doc item. - if (!getItemByPath(pathname)) { - res.statusCode = 404 - } +app.use(express.static('public', { cacheControl: true, maxAge: 0 })) - // Custom route for all docs - app.render(req, res, '/doc', query) - } else { - // Regular Next.js handler +app.use(notFoundMiddleware) - handle(req, res, parsedUrl) - } - }).listen(port, err => { - if (err) throw err - console.info(`> Ready on localhost:${port}`) - }) -}) +app.listen(port, () => console.log(`Ready on localhost:${port}!`)) diff --git a/src/components/404/index.js b/src/components/404/index.js new file mode 100644 index 0000000000..c2869a7ce5 --- /dev/null +++ b/src/components/404/index.js @@ -0,0 +1,20 @@ +import React from 'react' +import Subscribe from '../Subscribe' + +import { Wrapper, Title, Content } from './styles' + +function Page404() { + return ( + <> + + Not Found + + You just hit a route that doesn't exist... the sadness. + + + + + ) +} + +export default Page404 diff --git a/src/components/404/styles.js b/src/components/404/styles.js new file mode 100644 index 0000000000..97dc2bcc75 --- /dev/null +++ b/src/components/404/styles.js @@ -0,0 +1,38 @@ +import styled from 'styled-components' +import { media } from '../../styles' + +export const Wrapper = styled.div` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + margin: 100px auto 150px; +` + +export const Title = styled.h1` + ${media.desktop` + font-weight: 500; + font-size: 30px; + line-height: 40px; + `} + + font-family: BrandonGrotesqueMed; + font-size: 40px; + line-height: 60px; + margin-top: 0.67em; + margin-bottom: 0.67em; +` + +export const Content = styled.div` + ${media.desktop` + padding: 0 15px; + text-align: center; + font-size: 20px; + line-height: 30px; + `} + + padding: 0; + text-align: left; + font-size: 24px; + line-height: 34px; +` diff --git a/src/components/Community/Button/index.js b/src/components/Community/Button/index.js deleted file mode 100644 index 97df73f6ff..0000000000 --- a/src/components/Community/Button/index.js +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' - -import { Wrapper } from './styles' - -function CommunityButton({ theme, children, forwardedRef, ...props }) { - return ( - - {children} - - ) -} - -CommunityButton.propTypes = { - children: PropTypes.node, - theme: PropTypes.shape({ - backgroundColor: PropTypes.string, - color: PropTypes.string - }), - forwardedRef: PropTypes.func -} - -// eslint-disable-next-line react/display-name -export default React.forwardRef((props, ref) => ( - -)) diff --git a/src/components/Community/Button/styles.js b/src/components/Community/Button/styles.js deleted file mode 100644 index dd7fe14fa9..0000000000 --- a/src/components/Community/Button/styles.js +++ /dev/null @@ -1,19 +0,0 @@ -import styled from 'styled-components' - -export const Wrapper = styled.a` - display: block; - height: 38px; - border-radius: 4px; - font-size: 16px; - font-family: BrandonGrotesqueMed; - line-height: 38px; - text-decoration: none; - text-align: center; - color: ${({ color }) => (color ? color : '#999')}; - background-color: ${({ backgroundColor }) => - backgroundColor ? backgroundColor : '#ddd'}; - - &:hover { - opacity: 0.7; - } -` diff --git a/src/components/Community/Contribute/index.js b/src/components/Community/Contribute/index.js index de93153a38..ea3323df83 100644 --- a/src/components/Community/Contribute/index.js +++ b/src/components/Community/Contribute/index.js @@ -3,13 +3,12 @@ import PropTypes from 'prop-types' import { logEvent } from '../../../utils/ga' -import CommunityButton from '../Button' import CommunityBlock from '../Block' import CommunitySection from '../Section' import data from '../data' -import { Item, Items, Wrapper } from '../styles' +import { Button, Item, Items, Wrapper } from '../styles' const { description, mobileDescription, title } = data.section.contribute @@ -23,10 +22,10 @@ export default function CommunityContribute({ theme }) { @@ -35,7 +34,7 @@ export default function CommunityContribute({ theme }) { Go to Github - + } > Let's build something great together. Become a DVC @@ -54,7 +53,7 @@ export default function CommunityContribute({ theme }) { Let’s talk! - + } > We're always interested in guest writers for our blog. If you @@ -73,7 +72,7 @@ export default function CommunityContribute({ theme }) { Let’s talk! - + } > We support speakers all over the world and help with preparation, @@ -92,7 +91,7 @@ export default function CommunityContribute({ theme }) { Let’s talk! - + } > Get perks and benefits for contributing to the code base, writing diff --git a/src/components/Community/Events/index.js b/src/components/Community/Events/index.js index c63900ecf0..5ce5e13c55 100644 --- a/src/components/Community/Events/index.js +++ b/src/components/Community/Events/index.js @@ -6,12 +6,11 @@ import fill from 'lodash.fill' import { logEvent } from '../../../utils/ga' import CommunityBlock from '../Block' -import CommunityButton from '../Button' import CommunitySection from '../Section' import data from '../data' -import { Item, Items, Line, Link, Wrapper } from '../styles' +import { Button, Item, Items, Line, Link, Wrapper } from '../styles' import { Image, ImageWrapper, Meta } from './styles' @@ -39,7 +38,7 @@ function CommunityEvent({ Event Info - + } > @@ -101,7 +100,7 @@ export default function CommunityEvents({ theme }) { anchor="events" color={theme.color} description={description} - icon="/static/img/community/events.svg" + icon="/img/community/events.svg" mobileDescription={mobileDescription} title={title} > diff --git a/src/components/Community/Learn/index.js b/src/components/Community/Learn/index.js index 39862c2bcd..16fc3fc229 100644 --- a/src/components/Community/Learn/index.js +++ b/src/components/Community/Learn/index.js @@ -5,15 +5,16 @@ import format from 'date-fns/format' import LocalLink from '../../LocalLink' import { logEvent } from '../../../utils/ga' +import { getFirstPage } from '../../../utils/sidebar' import CommunityBlock from '../Block' -import CommunityButton from '../Button' import CommunitySection from '../Section' import { usePosts, useCommentsCount } from '../../../utils/api' import { pluralizeComments } from '../../../utils/i18n' import { + Button, Comments, HeaderLink, ImageLine, @@ -32,6 +33,7 @@ import { Image } from './styles' import data from '../data' +const docsPage = getFirstPage() const { description, mobileDescription, title } = data.section.learn const { documentation, userContent } = data @@ -160,7 +162,7 @@ function CommunityDocumentation({ url, title, description, color }) { href={url} as={Link} color={color} - large + large="true" onClick={logDocumentation} > {title} @@ -184,10 +186,10 @@ export default function CommunityLearn({ theme }) { @@ -196,7 +198,7 @@ export default function CommunityLearn({ theme }) { @@ -205,8 +207,8 @@ export default function CommunityLearn({ theme }) { } action={ @@ -237,7 +239,7 @@ export default function CommunityLearn({ theme }) { } action={ posts && ( - See all Posts - + ) } > diff --git a/src/components/Community/Meet/index.js b/src/components/Community/Meet/index.js index 8b682a94af..98c12383ac 100644 --- a/src/components/Community/Meet/index.js +++ b/src/components/Community/Meet/index.js @@ -3,7 +3,6 @@ import PropTypes from 'prop-types' import formatDistanceToNow from 'date-fns/formatDistanceToNow' import CommunityBlock from '../Block' -import CommunityButton from '../Button' import CommunitySection from '../Section' import { pluralizeComments } from '../../../utils/i18n' @@ -17,6 +16,7 @@ const { description, mobileDescription, title } = data.section.meet import { Stats, StatLabel, StatLine, StatValue } from './styles' import { + Button, Comments, HeaderLink, Item, @@ -119,11 +119,11 @@ export default function CommunityMeet({ theme }) { @@ -141,7 +141,7 @@ export default function CommunityMeet({ theme }) { } action={ - Open Chat - + } - icon="/static/img/community/discord.svg" + icon="/img/community/discord.svg" > Need urgent help? Ask advice from experienced developers online @@ -182,7 +182,7 @@ export default function CommunityMeet({ theme }) { } action={ topics && ( - Read All Topics - + ) } - icon="/static/img/community/discourse.svg" + icon="/img/community/discourse.svg" > {!topicsReady && Loading...} {topicsError && ( @@ -223,7 +223,7 @@ export default function CommunityMeet({ theme }) { } action={ issues && ( - Read All Issues - + ) } - icon="/static/img/community/github.svg" + icon="/img/community/github.svg" > {!issuesReady && Loading...} {issuesError && ( diff --git a/src/components/Community/Section/index.js b/src/components/Community/Section/index.js index 8cc4871144..c13a6ff357 100644 --- a/src/components/Community/Section/index.js +++ b/src/components/Community/Section/index.js @@ -1,10 +1,9 @@ import PropTypes from 'prop-types' import React, { useCallback, useEffect, useState } from 'react' +import { useLocation } from '@reach/router' import { Collapse } from 'react-collapse' import { useWindowSize } from 'react-use' -import Router from 'next/router' - import { DesktopDescription, Header, @@ -36,24 +35,13 @@ export default function CommunitySection({ ) const { width } = useWindowSize() + const location = useLocation() useEffect(() => { - const updateVisibility = () => { - const { hash } = window.location - - if (anchor && hash === `#${anchor}`) { - setIsContentVisible(true) - } - } - - updateVisibility() - - Router.events.on('hashChangeComplete', updateVisibility) - - return () => { - Router.events.off('hashChangeComplete', updateVisibility) + if (anchor && location.hash === `#${anchor}`) { + setIsContentVisible(true) } - }, []) + }, [location.hash]) useEffect(() => setIsTablet(width <= sizes.tablet), [width]) diff --git a/src/components/Community/data.json b/src/components/Community/data.json index da37d8f93a..6f550868a2 100644 --- a/src/components/Community/data.json +++ b/src/components/Community/data.json @@ -1,7 +1,7 @@ { "hero": { - "pictureDesktop": "/static/img/community/banner.png", - "pictureMobile": "/static/img/community/banner-mobile.png", + "pictureDesktop": "/img/community/banner.png", + "pictureMobile": "/img/community/banner-mobile.png", "url": "https://www.mlprague.com/#schedule-saturday" }, "section": { @@ -49,21 +49,21 @@ "title": "Remote training with GitLab-CI and DVC", "author": "Marcel Mikl and Bert Besser", "date": "2020-01-28", - "pictureUrl": "/static/img/community/ugc/codecentric.png" + "pictureUrl": "/img/community/ugc/codecentric.png" }, { "url": "https://martinfowler.com/articles/cd4ml.html", "title": "Continuous Delivery for Machine Learning", "author": "Danilo Sato, Arif Wider and Christoph Windheuser", "date": "2019-09-20", - "pictureUrl": "/static/img/community/ugc/fowler_icon.ico" + "pictureUrl": "/img/community/ugc/fowler_icon.ico" }, { "url": "https://towardsdatascience.com/mlops-reducing-the-technical-debt-of-machine-learning-dac528ef39de", "title": "MLOps: Reducing the Technical Debt of Machine Learning", "author": "Saurav Chakravorty", "date": "2019-12-21", - "pictureUrl": "/static/img/community/ugc/tds_logo.png" + "pictureUrl": "/img/community/ugc/tds_logo.png" } ], "events": [ @@ -80,7 +80,7 @@ "description": "PaweΕ‚ RedzyΕ„ski will talk about open source tools for versioning machine learning projects", "city": "Prague", "date": "2020-03-20", - "pictureUrl": "/static/img/community/events/mlprague.jpg" + "pictureUrl": "/img/community/events/mlprague.jpg" }, { "url": "https://divops.org", @@ -88,7 +88,7 @@ "description": "Elle O'Brien is talking about open source software in the growing field of MLOps.", "city": "Remote", "date": "2020-03-25", - "pictureUrl": "/static/img/community/events/divops.jpg" + "pictureUrl": "/img/community/events/divops.jpg" } ], "stats": { diff --git a/src/components/Community/index.js b/src/components/Community/index.js index 07b2b61fdb..e711d01f63 100644 --- a/src/components/Community/index.js +++ b/src/components/Community/index.js @@ -1,6 +1,5 @@ import React from 'react' -import Page from '../Page' import Subscribe from '../Subscribe' import CommunityContribute from './Contribute' @@ -19,7 +18,7 @@ const themes = { export default function Community() { return ( - + <> @@ -28,6 +27,6 @@ export default function Community() { - + ) } diff --git a/src/components/Community/styles.js b/src/components/Community/styles.js index 8515ab1524..e9d76436d8 100644 --- a/src/components/Community/styles.js +++ b/src/components/Community/styles.js @@ -120,3 +120,21 @@ export const PageWrapper = styled.div` padding-bottom: 0; `} ` + +export const Button = styled.a` + display: block; + height: 38px; + border-radius: 4px; + font-size: 16px; + font-family: BrandonGrotesqueMed; + line-height: 38px; + text-decoration: none; + text-align: center; + color: ${({ theme: { color } }) => (color ? color : '#999')}; + background-color: ${({ theme: { backgroundColor } }) => + backgroundColor ? backgroundColor : '#ddd'}; + + &:hover { + opacity: 0.7; + } +` diff --git a/src/components/Diagram/index.js b/src/components/Diagram/index.js index 6148dc1338..cdfcc069c6 100644 --- a/src/components/Diagram/index.js +++ b/src/components/Diagram/index.js @@ -5,6 +5,9 @@ import PropTypes from 'prop-types' import { Element } from 'react-scroll' import Slider from 'react-slick' +import 'slick-carousel/slick/slick.css' +import 'slick-carousel/slick/slick-theme.css' + import LocalLink from '../LocalLink' import { OnlyDesktop, OnlyMobile } from '../../styles' @@ -29,12 +32,7 @@ const LearnMore = ({ href }) => ( Learn more - + ) @@ -130,7 +128,7 @@ export default class DiagramSection extends Component { - + @@ -144,23 +142,17 @@ export default class DiagramSection extends Component { ML project version control - ML experiment management + ML experiment management - Deployment & Collaboration + Deployment & Collaboration diff --git a/src/components/Documentation/SidebarMenu/index.js b/src/components/DocLayout/SidebarMenu/index.js similarity index 87% rename from src/components/Documentation/SidebarMenu/index.js rename to src/components/DocLayout/SidebarMenu/index.js index 7253437034..bbbd346214 100644 --- a/src/components/Documentation/SidebarMenu/index.js +++ b/src/components/DocLayout/SidebarMenu/index.js @@ -5,10 +5,15 @@ import scrollIntoView from 'dom-scroll-into-view' import PropTypes from 'prop-types' import includes from 'lodash.includes' +import 'perfect-scrollbar/css/perfect-scrollbar.css' + import DownloadButton from '../../DownloadButton' import LocalLink from '../../LocalLink' -import { getParentsListFromPath } from '../../../utils/sidebar' +import { + getParentsListFromPath, + getPathWithSoruce +} from '../../../utils/sidebar' import { OnlyDesktop } from '../../../styles' @@ -22,7 +27,7 @@ function SidebarMenuItem({ children, label, path, activePaths, onClick }) { return ( <> { psRef.current.update() - scrollIntoView(node, parent, { onlyScrollIfNeeded: true }) + + if (node && parent) { + scrollIntoView(node, parent, { onlyScrollIfNeeded: true }) + } + setIsScrollHidden(false) }, 400) diff --git a/src/components/Documentation/SidebarMenu/styles.js b/src/components/DocLayout/SidebarMenu/styles.js similarity index 95% rename from src/components/Documentation/SidebarMenu/styles.js rename to src/components/DocLayout/SidebarMenu/styles.js index 9a0f7bedaf..aea066423c 100644 --- a/src/components/Documentation/SidebarMenu/styles.js +++ b/src/components/DocLayout/SidebarMenu/styles.js @@ -81,7 +81,7 @@ export const SectionLink = styled.a` position: absolute; width: 8px; height: 5px; - background: url('/static/img/triangle_dark.svg') no-repeat center center; + background: url('/img/triangle_dark.svg') no-repeat center center; left: 0px; top: 10px; diff --git a/src/components/DocLayout/index.js b/src/components/DocLayout/index.js new file mode 100644 index 0000000000..49b989aba5 --- /dev/null +++ b/src/components/DocLayout/index.js @@ -0,0 +1,77 @@ +/* global docsearch:readonly */ + +import React, { useCallback, useEffect, useState } from 'react' +import PropTypes from 'prop-types' +import Hamburger from '../Hamburger' +import SearchForm from '../SearchForm' +import MainLayout from '../MainLayout' +import SidebarMenu from './SidebarMenu' + +import { Container, Backdrop, SearchArea, Side, SideToggle } from './styles' + +import { structure } from '../../utils/sidebar' + +const SIDEBAR_MENU = 'sidebar-menu' + +function DocLayout({ children, ...restProps }) { + const [isMenuOpen, setIsMenuOpen] = useState(false) + const [isSearchAvaible, setIsSearchAvaible] = useState(false) + + const toggleMenu = useCallback(() => setIsMenuOpen(!isMenuOpen), [isMenuOpen]) + + useEffect(() => { + try { + docsearch + + setIsSearchAvaible(true) + + if (docsearch && isSearchAvaible) { + docsearch({ + apiKey: '755929839e113a981f481601c4f52082', + indexName: 'dvc', + inputSelector: '#doc-search', + debug: false // Set to `true` if you want to inspect the dropdown + }) + } + } catch (ReferenceError) { + // nothing there + } + }, [isSearchAvaible]) + + return ( + + + + + + + + + + {isSearchAvaible && ( + + + + )} + + + + {children} + + + ) +} + +DocLayout.propTypes = { + children: PropTypes.element.isRequired, + location: PropTypes.shape({ + pathname: PropTypes.string.isRequired + }) +} + +export default DocLayout diff --git a/src/components/DocLayout/styles.js b/src/components/DocLayout/styles.js new file mode 100644 index 0000000000..a1a7d38bbc --- /dev/null +++ b/src/components/DocLayout/styles.js @@ -0,0 +1,128 @@ +import styled from 'styled-components' + +import { media } from '../../styles' + +export const Container = styled.div` + display: flex; + flex-direction: row; + max-width: 1200px; + margin: 0 auto; + background: white; + z-index: 2; + + &:before { + content: ''; + display: block; + position: fixed; + top: 0; + left: 0; + bottom: 0; + width: 50%; + background-color: #eef4f8; + z-index: -1; + pointer-events: none; + } +` + +export const Backdrop = styled.div` + display: none; + + ${media.phablet` + display: block; + opacity: 0; + pointer-events: none; + transition: opacity .3s linear; + + ${props => + props.visible && + ` + content: ''; + position: fixed; + top: 0; + left: 0; + bottom: 0; + right: 0; + background-color: rgba(0, 0, 0, 0.4); + z-index: 1; + opacity: 1; + pointer-events: all; + `} + `}; +` + +export const Side = styled.div` + width: 280px; + background-color: #eef4f8; + + @media only screen and (max-width: 1200px) { + padding-left: 15px; + } + + ${media.phablet` + position: fixed; + display: block; + z-index: 2; + top: 78px; + bottom: 0; + left: 0; + right: 60px; + box-shadow: rgba(0, 0, 0, 0.14) 0px 0px 4px, rgba(0, 0, 0, 0.28) 0px 4px 8px; + transform: translateX(-110%); + transition: transform .35s ease; + + ${props => + props.isOpen && + ` + transform: translateX(0); + `} + `}; +` + +export const SearchArea = styled.div` + height: 60px; + display: flex; + align-items: center; + background-color: #eef4f8; + z-index: 10; + position: sticky; + top: 0; + + ${media.phablet` + position: relative; + padding: 0 20px; + `}; + + form { + height: 40px; + } +` + +export const SideToggle = styled.div` + display: none; + position: fixed; + z-index: 2; + left: 8px; + bottom: 20px; + width: 45px; + height: 45px; + border-radius: 50%; + background-color: rgba(255, 255, 255, 0.9); + box-shadow: 0 0px 9px 0 rgba(0, 0, 0, 0.15); + transition: transform 0.3s ease; + justify-content: center; + align-items: center; + + ${media.phablet` + display: flex; + + > div { + transform: scale(0.75); + } + `}; + + ${({ isMenuOpen }) => + isMenuOpen && + ` + transform: translateX(calc(100vw - 60px)); + `}; +` diff --git a/src/components/Documentation/Markdown/index.js b/src/components/Documentation/Markdown/index.js index 3ea4ab591c..e23898a27e 100644 --- a/src/components/Documentation/Markdown/index.js +++ b/src/components/Documentation/Markdown/index.js @@ -1,279 +1,147 @@ -import React from 'react' +import React, { useCallback, useEffect, useRef } from 'react' +import rehypeReact from 'rehype-react' import PropTypes from 'prop-types' -import ReactMarkdown from 'react-markdown' import Collapsible from 'react-collapsible' -import kebabCase from 'lodash.kebabcase' -import Router from 'next/router' +import 'github-markdown-css/github-markdown.css' + +import { navigate } from '@reach/router' + +import { getPathWithSoruce } from '../../../utils/sidebar' import LocalLink from '../../LocalLink' import Tooltip from '../../Tooltip' import Tutorials from '../Tutorials' -import { Light as SyntaxHighlighter } from 'react-syntax-highlighter' -import { docco } from 'react-syntax-highlighter/dist/cjs/styles/hljs' -import python from 'react-syntax-highlighter/dist/cjs/languages/hljs/python' -import yaml from 'react-syntax-highlighter/dist/cjs/languages/hljs/yaml' -import ini from 'react-syntax-highlighter/dist/cjs/languages/hljs/ini' -import bash from 'react-syntax-highlighter/dist/cjs/languages/hljs/bash' -import diff from 'react-syntax-highlighter/dist/cjs/languages/hljs/diff' -import vim from 'react-syntax-highlighter/dist/cjs/languages/hljs/vim' -import usage from './lang/usage' -import dvc from './lang/dvc' -import linker from './utils/remark-linker' - -import { PAGE_DOC } from '../../../consts' - import { Button, Content, - ExternalLink, GithubLink, NavigationButtons, TutorialsWrapper } from './styles' -SyntaxHighlighter.registerLanguage('dvc', dvc) -SyntaxHighlighter.registerLanguage('python', python) -SyntaxHighlighter.registerLanguage('usage', usage) -SyntaxHighlighter.registerLanguage('yaml', yaml) -SyntaxHighlighter.registerLanguage('ini', ini) -SyntaxHighlighter.registerLanguage('bash', bash) -SyntaxHighlighter.registerLanguage('vim', vim) -SyntaxHighlighter.registerLanguage('diff', diff) - -function flatten(text, child) { - return typeof child === 'string' - ? text + child - : React.Children.toArray(child.props.children).reduce(flatten, text) -} - -const SLUG_REGEXP = /\s+{#([a-z0-9-]*[a-z0-9]+)}\s*$/ - -function isTitleHasSlug(title) { - return typeof title === 'string' && SLUG_REGEXP.test(title) -} - -export function extractSlugFromTitle(title) { - // extracts expressions like {#too-many-files} from the end of a title - const meta = title.match(SLUG_REGEXP) - - if (meta) { - return [title.substring(0, meta.index), meta[1]] +const isInsideCodeBlock = elem => { + for (let el = elem; el && el !== document; el = el.parentNode) { + if (el.tagName === 'PRE') return true + if (el.tagName === 'ARTICLE') return false } - return [title, kebabCase(title)] + return false } -const HeadingRenderer = ({ level, children }) => { - const content = React.Children.toArray(children) - const text = children.reduce(flatten, '') - let slug = kebabCase(text) +function Details({ children }) { + const filteredChildren = children.filter(child => child !== '\n') - const lastElement = content[content.length - 1].props.children - if (isTitleHasSlug(lastElement)) { - const [newValue, newSlug] = extractSlugFromTitle(lastElement) - content.push(React.cloneElement(content.pop(), [], newValue)) - slug = newSlug - } - - const anchor = - level !== 1 ? ( - - ) : null - return React.createElement('h' + level, { id: slug }, anchor, content) -} - -HeadingRenderer.propTypes = { - level: PropTypes.number.isRequired, - children: PropTypes.node.isRequired -} - -const HtmlRenderer = props => { - if (props.tag !== 'details' && props.tag !== 'abbr') { - return React.createElement(props.tag, {}, props.children) - } else if (props.tag === 'details') { - const text = props.children[0].props.children[0] - return ( - - {props.children.slice(1)} - - ) - } else if (props.tag === 'abbr') { - const text = props.children[0] - const key = props.children[0].key - return - } -} - -const CodeBlock = ({ value, language }) => { - const dvcStyle = Object.assign({}, docco) - dvcStyle['hljs-comment'] = { color: '#999' } - dvcStyle['hljs-meta'] = { color: '#333', fontSize: '14px' } - dvcStyle['hljs']['padding'] = '0.5em 0.5em 0.5em 2em' - dvcStyle['hljs-skipped'] = { userSelect: 'none' } + const text = filteredChildren[0].props.children[0] return ( - - {value} - + + {filteredChildren.slice(1)} + ) } -CodeBlock.propTypes = { - language: PropTypes.string.isRequired, - value: PropTypes.node.isRequired +Details.propTypes = { + children: PropTypes.node } -const Link = ({ children, href, ...props }) => { - const externalLink = href.match(/^(\/\/|http(s)?:\/\/)/) - const showIcon = - externalLink && children && typeof children[0].props.children === 'string' - - const modifiedProps = externalLink - ? { ...props, target: '_blank', rel: 'noreferrer noopener' } - : props - - if (showIcon) { - return ( - - {children} - - ) - } - - return ( - - {children} - - ) +function ABBR({ children }) { + return } -Link.propTypes = { - children: PropTypes.node.isRequired, - href: PropTypes.string.isRequired +ABBR.propTypes = { + children: PropTypes.node } -export default class Markdown extends React.PureComponent { - constructor() { - super() - this.touchstartX = 0 - this.touchendX = 0 - this.isCodeBlock = false - } - - componentDidMount() { - document.addEventListener('touchstart', this.onTouchStart, false) - document.addEventListener('touchend', this.onTouchEnd, false) - } - - componentWillUnmount() { - document.removeEventListener('touchstart', this.onTouchStart) - document.removeEventListener('touchend', this.onTouchEnd) - } - - isInsideCodeBlock = elem => { - for (let el = elem; el && el !== document; el = el.parentNode) { - if (el.tagName === 'PRE') return true - if (el.tagName === 'ARTICLE') return false +const renderAst = new rehypeReact({ + createElement: React.createElement, + components: { details: Details, abbr: ABBR } +}).Compiler + +export default function Markdown({ + htmlAst, + prev, + next, + tutorials, + githubLink +}) { + const touchstartXRef = useRef(0) + const touchendXRef = useRef(0) + const isCodeBlockRef = useRef(false) + + const handleSwipeGesture = useCallback(() => { + if (isCodeBlockRef.current) return + + if (touchstartXRef.current - touchendXRef.current > 100) { + navigate(next) } - return false - } - onTouchStart = e => { - this.isCodeBlock = this.isInsideCodeBlock(e.target) - this.touchstartX = event.changedTouches[0].screenX - } + if (touchendXRef.current - touchstartXRef.current > 100) { + navigate(prev) + } + }, [prev, next]) - onTouchEnd = () => { - this.touchendX = event.changedTouches[0].screenX - this.handleSwipeGesture() - } + const onTouchStart = useCallback(e => { + isCodeBlockRef.current = isInsideCodeBlock(e.target) + touchstartXRef.current = event.changedTouches[0].screenX + }, []) - handleSwipeGesture = () => { - if (this.isCodeBlock) return - const { prev, next } = this.props + const onTouchEnd = useCallback(() => { + touchendXRef.current = event.changedTouches[0].screenX + handleSwipeGesture() + }, []) - if (this.touchstartX - this.touchendX > 100) { - Router.push({ asPath: PAGE_DOC, pathname: next }) - } + useEffect(() => { + document.addEventListener('touchstart', onTouchStart, false) + document.addEventListener('touchend', onTouchEnd, false) - if (this.touchendX - this.touchstartX > 100) { - Router.push({ asPath: PAGE_DOC, pathname: prev }) + return () => { + document.removeEventListener('touchstart', onTouchStart) + document.removeEventListener('touchend', onTouchEnd) } - } + }, []) - render() { - const { markdown, githubLink, prev, next, tutorials } = this.props - - return ( - - {tutorials && ( - - - + return ( + + {tutorials && ( + + + + )} + + Edit on GitHub + +
{renderAst(htmlAst)}
+ + {prev ? ( + + + Prev + + ) : ( + )} - - Edit on GitHub - - - - {prev ? ( - - - Prev - - ) : ( - - )} - {next ? ( - - Next - - - ) : ( - - )} - -
- ) - } + {next ? ( + + Next + + + ) : ( + + )} + +
+ ) } Markdown.propTypes = { - markdown: PropTypes.string.isRequired, + htmlAst: PropTypes.object.isRequired, githubLink: PropTypes.string.isRequired, tutorials: PropTypes.object, prev: PropTypes.string, diff --git a/src/components/Documentation/Markdown/styles.js b/src/components/Documentation/Markdown/styles.js index 4fe58c8603..4dc7316a12 100644 --- a/src/components/Documentation/Markdown/styles.js +++ b/src/components/Documentation/Markdown/styles.js @@ -31,6 +31,131 @@ export const Content = styled.article` animation-duration: 1s; animation-fill-mode: both; animation-name: fadeIn; + + a[target='_blank']:after { + position: relative; + top: 1px; + right: 0; + width: 12px; + height: 12px; + margin-left: 1px; + content: url(/img/external-link.svg); + } + + pre[class*='language-'] { + background: #40354d; + color: #ccc; + + .token.line { + font-weight: bold; + color: #a0a0a0; + } + + .token.comment { + font-weight: normal; + color: #a0a0a0; + } + + .token.input { + user-select: none; + } + + .token.comment, + .token.block-comment, + .token.prolog, + .token.doctype, + .token.cdata { + color: #999; + } + + .token.url, + .token.constant, + .token.operator, + .token.punctuation { + color: #a0a0a0; + } + + .token.property, + .token.tag, + .token.boolean, + .token.function-name, + .token.symbol, + .token.deleted { + color: #4badd2; + } + + .token.function { + color: #ae41bb; + } + + .token.number, + .token.attr-name, + .token.string, + .token.char, + .token.builtin, + .token.inserted { + color: #219161; + } + + .token.entity, + .token.variable { + color: #a67f59; + } + + .token.class-name { + color: #0086b3; + } + + .token.dvc { + color: #56b1d0; + } + + .token.usage, + .token.git { + color: #e9836e; + } + + .token.command, + .token.selector, + .token.atrule, + .token.attr-value, + .token.keyword { + color: #e4b872; + } + + .token.regex, + .token.important { + color: #b68; + } + + .token.parameter { + color: #a0a0a0; + } + + .token.function-variable { + color: #7ece42; + } + + .token.important { + font-weight: normal; + } + + .token.bold { + font-weight: bold; + } + + .token.italic { + font-style: italic; + } + + .token.entity { + cursor: help; + } + + .token.namespace { + opacity: 0.7; + } + } } .Collapsible { @@ -55,7 +180,7 @@ export const Content = styled.article` right: 0; width: 20px; height: 20px; - background-image: url('/static/img/click.png'); + background-image: url('/img/click.png'); content: ''; font-family: monospace; transition: transform 200ms; @@ -126,7 +251,7 @@ export const Button = styled.a` i { display: inline-block; - background-image: url(/static/img/arrow.svg); + background-image: url(/img/arrow.svg); background-size: contain; background-position: center; background-repeat: no-repeat; @@ -185,7 +310,7 @@ export const GithubLink = styled(LightButton)` } i { - background-image: url(/static/img/github_icon.svg); + background-image: url(/img/github_icon.svg); } ` @@ -197,6 +322,6 @@ export const ExternalLink = styled.a` width: 12px; height: 12px; margin-left: 1px; - content: url(/static/img/external-link.svg); + content: url(/img/external-link.svg); } ` diff --git a/src/components/Documentation/Markdown/utils/remark-linker.js b/src/components/Documentation/Markdown/utils/remark-linker.js deleted file mode 100644 index 36a9d24371..0000000000 --- a/src/components/Documentation/Markdown/utils/remark-linker.js +++ /dev/null @@ -1,49 +0,0 @@ -;`use strict` - -import visit from 'unist-util-visit' - -import { getItemByPath } from '../../../../utils/sidebar' - -const DVC_REGEXP = /dvc\s+[a-z][a-z-.]*/ -const COMMAND_REGEXP = /^[a-z][a-z-]*$/ -const COMMAND_ROOT = '/doc/command-reference/' - -function linker() { - function transformer(tree) { - visit(tree, 'inlineCode', function(node, index, parent) { - if (parent.type !== 'link' && DVC_REGEXP.test(node.value)) { - let parts = node.value.split(/\s+/) - let url - - const hasThirdSegment = parts[2] && COMMAND_REGEXP.test(parts[2]) - const isCommandPageExists = getItemByPath(`${COMMAND_ROOT}${parts[1]}`) - const isSubcommandPageExists = - isCommandPageExists && - hasThirdSegment && - getItemByPath(`${COMMAND_ROOT}${parts[1]}/${parts[2]}`) - - if (isSubcommandPageExists) { - url = `${COMMAND_ROOT}${parts[1]}/${parts[2]}` - } else if (isCommandPageExists && hasThirdSegment) { - url = `${COMMAND_ROOT}${parts[1]}#${parts[2]}` - } else if (isCommandPageExists) { - url = `${COMMAND_ROOT}${parts[1]}` - } - - if (url) { - parent.children[index] = { - type: 'link', - url: url, - children: [node], - position: node.position - } - } - } - }) - return tree - } - - return transformer -} - -export default linker diff --git a/src/components/Documentation/RightPanel/index.js b/src/components/Documentation/RightPanel/index.js index 804c868042..e270a3805e 100644 --- a/src/components/Documentation/RightPanel/index.js +++ b/src/components/Documentation/RightPanel/index.js @@ -91,7 +91,9 @@ export default class RightPanel extends React.PureComponent { updateHeadingsPosition = () => { const coordinates = this.props.headings.reduce((result, { slug }) => { - return { ...result, [document.getElementById(slug).offsetTop]: slug } + const headingElement = document.getElementById(slug) + + return { ...result, [headingElement && headingElement.offsetTop]: slug } }, {}) const height = this.root.offsetHeight diff --git a/src/components/Documentation/RightPanel/styles.js b/src/components/Documentation/RightPanel/styles.js index bcebe20874..0827aa721a 100644 --- a/src/components/Documentation/RightPanel/styles.js +++ b/src/components/Documentation/RightPanel/styles.js @@ -58,13 +58,13 @@ export const ExternalButton = styled(LightButton)` export const GithubButton = styled(ExternalButton)` i { - background-image: url(/static/img/github_icon.svg); + background-image: url(/img/github_icon.svg); } ` export const DiscordButton = styled(ExternalButton)` i { - background-image: url(/static/img/discord.svg); + background-image: url(/img/discord.svg); width: 1.2em; height: 1.2em; } diff --git a/src/components/Documentation/Tutorials/styles.js b/src/components/Documentation/Tutorials/styles.js index 1a92f74cc3..9071315bac 100644 --- a/src/components/Documentation/Tutorials/styles.js +++ b/src/components/Documentation/Tutorials/styles.js @@ -30,7 +30,7 @@ export const KatacodaButton = styled(ExternalButton)` white-space: nowrap; i { - background-image: url(/static/img/katacoda_grey_small.png); + background-image: url(/img/katacoda_grey_small.png); width: 24px; height: 24px; } diff --git a/src/components/Documentation/index.js b/src/components/Documentation/index.js index 6e2c279064..dc735ea771 100644 --- a/src/components/Documentation/index.js +++ b/src/components/Documentation/index.js @@ -1,137 +1,35 @@ -/* global docsearch:readonly */ - -import React, { useCallback, useEffect, useMemo, useState } from 'react' +import React from 'react' import PropTypes from 'prop-types' -import Router from 'next/router' -import Page from '../Page' -import Hamburger from '../Hamburger' -import SearchForm from '../SearchForm' -import SidebarMenu from './SidebarMenu' -import Markdown, { extractSlugFromTitle } from './Markdown' +import Markdown from './Markdown' import RightPanel from './RightPanel' -import { structure } from '../../utils/sidebar' - -import { Backdrop, Container, SearchArea, Side, SideToggle } from './styles' - -const ROOT_ELEMENT = 'bodybag' -const SIDEBAR_MENU = 'sidebar-menu' - -const parseHeadings = text => { - const headingRegex = /\n(## \s*)(.*)/g - const matches = [] - let match - do { - match = headingRegex.exec(text) - if (match) { - const [title, slug] = extractSlugFromTitle(match[2]) - matches.push({ - text: title, - slug: slug - }) - } - } while (match) - - return matches -} - -export default function Documentation({ - source, - path, - next, - prev, - tutorials, - markdown -}) { - const headings = useMemo(() => parseHeadings(markdown)) - const [isMenuOpen, setIsMenuOpen] = useState(false) - const [isSearchAvaible, setIsSearchAvaible] = useState(false) - - const toggleMenu = useCallback(() => setIsMenuOpen(!isMenuOpen), [isMenuOpen]) - - useEffect(() => { - try { - docsearch - - setIsSearchAvaible(true) +import { getItemByPath } from '../../utils/sidebar' - if (isSearchAvaible) { - docsearch({ - apiKey: '755929839e113a981f481601c4f52082', - indexName: 'dvc', - inputSelector: '#doc-search', - debug: false // Set to `true` if you want to inspect the dropdown - }) - } - } catch (ReferenceError) { - // nothing there - } - }, [isSearchAvaible]) - - useEffect(() => { - const handleRouteChange = () => { - const rootElement = document.getElementById(ROOT_ELEMENT) - if (rootElement) { - rootElement.scrollTop = 0 - } - } - - Router.events.on('routeChangeComplete', handleRouteChange) - - return () => Router.events.off('routeChangeComplete', handleRouteChange) - }, []) - - const githubLink = `https://github.com/iterative/dvc.org/blob/master/public${source}` +export default function Documentation({ htmlAst, path, headings }) { + const { source, prev, next, tutorials } = getItemByPath(path) + const githubLink = `https://github.com/iterative/dvc.org/blob/master/сontent${source}` return ( - - - - - - - - - - {isSearchAvaible && ( - - - - )} - - - - - - - - - + <> + + + ) } Documentation.propTypes = { - source: PropTypes.string, path: PropTypes.string, - next: PropTypes.string, - prev: PropTypes.string, - tutorials: PropTypes.object, - markdown: PropTypes.string, - errorCode: PropTypes.number + headings: PropTypes.array, + htmlAst: PropTypes.object } diff --git a/src/components/Documentation/styles.js b/src/components/Documentation/styles.js index 0332167b22..48213b3f65 100644 --- a/src/components/Documentation/styles.js +++ b/src/components/Documentation/styles.js @@ -1,132 +1,5 @@ import styled from 'styled-components' -import { media } from '../../styles' - -export const Container = styled.div` - display: flex; - flex-direction: row; - max-width: 1200px; - margin: 0 auto; - background: white; - z-index: 2; - - &:before { - content: ''; - display: block; - position: fixed; - top: 0; - left: 0; - bottom: 0; - width: 50%; - background-color: #eef4f8; - z-index: -1; - pointer-events: none; - } -` - -export const Backdrop = styled.div` - display: none; - - ${media.phablet` - display: block; - opacity: 0; - pointer-events: none; - transition: opacity .3s linear; - - ${props => - props.visible && - ` - content: ''; - position: fixed; - top: 0; - left: 0; - bottom: 0; - right: 0; - background-color: rgba(0, 0, 0, 0.4); - z-index: 1; - opacity: 1; - pointer-events: all; - `} - `}; -` - -export const Side = styled.div` - width: 280px; - background-color: #eef4f8; - - @media only screen and (max-width: 1200px) { - padding-left: 15px; - } - - ${media.phablet` - position: fixed; - display: block; - z-index: 2; - top: 78px; - bottom: 0; - left: 0; - right: 60px; - box-shadow: rgba(0, 0, 0, 0.14) 0px 0px 4px, rgba(0, 0, 0, 0.28) 0px 4px 8px; - transform: translateX(-110%); - transition: transform .35s ease; - - ${props => - props.isOpen && - ` - transform: translateX(0); - `} - `}; -` - -export const SearchArea = styled.div` - height: 60px; - display: flex; - align-items: center; - background-color: #eef4f8; - z-index: 10; - position: sticky; - top: 0; - - ${media.phablet` - position: relative; - padding: 0 20px; - `}; - - form { - height: 40px; - } -` - -export const SideToggle = styled.div` - display: none; - position: fixed; - z-index: 2; - left: 8px; - bottom: 20px; - width: 45px; - height: 45px; - border-radius: 50%; - background-color: rgba(255, 255, 255, 0.9); - box-shadow: 0 0px 9px 0 rgba(0, 0, 0, 0.15); - transition: transform 0.3s ease; - justify-content: center; - align-items: center; - - ${media.phablet` - display: flex; - - > div { - transform: scale(0.75); - } - `}; - - ${({ isMenuOpen }) => - isMenuOpen && - ` - transform: translateX(calc(100vw - 60px)); - `}; -` - export const LightButton = styled.a` display: inline-flex; justify-content: center; diff --git a/src/components/DownloadButton/index.js b/src/components/DownloadButton/index.js index 75138f79a3..675921dc77 100644 --- a/src/components/DownloadButton/index.js +++ b/src/components/DownloadButton/index.js @@ -168,7 +168,7 @@ export default class DownloadButton extends Component { diff --git a/src/components/Features/index.js b/src/components/Features/index.js index 316d695c96..b762bbebca 100644 --- a/src/components/Features/index.js +++ b/src/components/Features/index.js @@ -1,6 +1,5 @@ import React from 'react' -import Page from '../Page' import Hero from '../Hero' import FeaturesHero from '../FeaturesHero' import TrySection from '../TrySection' @@ -9,7 +8,7 @@ import { Container, Description, Feature, Features, Icon, Name } from './styles' export default function FeaturesPage() { return ( - + <> @@ -18,7 +17,7 @@ export default function FeaturesPage() { Git compatible @@ -35,7 +34,7 @@ export default function FeaturesPage() { Storage agnostic @@ -49,10 +48,7 @@ export default function FeaturesPage() { - Reproducibility + Reproducibility Reproducible @@ -65,7 +61,7 @@ export default function FeaturesPage() { Low-friction branching @@ -81,7 +77,7 @@ export default function FeaturesPage() { - + Metric tracking @@ -93,7 +89,7 @@ export default function FeaturesPage() { ML pipelines framework @@ -108,7 +104,7 @@ export default function FeaturesPage() { Language & framework agnostic @@ -124,7 +120,7 @@ export default function FeaturesPage() { HDFS, Hive & Apache Spark @@ -140,7 +136,7 @@ export default function FeaturesPage() { Failure tracking @@ -155,6 +151,6 @@ export default function FeaturesPage() {
- + ) } diff --git a/src/components/Footer/index.js b/src/components/Footer/index.js index 38f8443f6d..78acc87068 100644 --- a/src/components/Footer/index.js +++ b/src/components/Footer/index.js @@ -3,6 +3,8 @@ import PropTypes from 'prop-types' import LocalLink from '../LocalLink' +import { getFirstPage } from '../../utils/sidebar' + import { Column, Columns, @@ -16,6 +18,8 @@ import { Wrapper } from './styles' +const docsPage = getFirstPage() + const SocialLink = ({ src, href, children }) => ( {children} @@ -35,7 +39,7 @@ export default function Footer(props) { site logo Community - + Documentation @@ -75,10 +79,7 @@ export default function Footer(props) { Company Blog - + Iterative.ai Privacy Policy @@ -88,18 +89,18 @@ export default function Footer(props) { Social Twitter GitHub - + Discord diff --git a/src/components/GithubLine/index.js b/src/components/GithubLine/index.js index 8a9db20dba..8094c93da4 100644 --- a/src/components/GithubLine/index.js +++ b/src/components/GithubLine/index.js @@ -17,14 +17,10 @@ export default function GithubLine() { return ( - + We’re on GitHub - {' '} + {' '} {count} ) diff --git a/src/components/HamburgerMenu/index.js b/src/components/HamburgerMenu/index.js index 44d0ea2f53..1dcc20da50 100644 --- a/src/components/HamburgerMenu/index.js +++ b/src/components/HamburgerMenu/index.js @@ -5,6 +5,8 @@ import LocalLink from '../LocalLink' import { logEvent } from '../../utils/ga' +import { getFirstPage } from '../../utils/sidebar' + import { Button, Image, @@ -20,6 +22,8 @@ import { Wrapper } from './styles' +const docsPage = getFirstPage() + export default function HamburgerMenu() { const [menu, setMenu] = useState(false) const [clicked, setClicked] = useState(false) @@ -52,7 +56,7 @@ export default function HamburgerMenu() { - dvc.org + dvc.org @@ -66,7 +70,7 @@ export default function HamburgerMenu() {
- + Doc
@@ -89,7 +93,7 @@ export default function HamburgerMenu() { as={ImageLink} onClick={itemClick('community')} > - + Meet Us - + Contribute - + Learn - + Events @@ -129,7 +133,7 @@ export default function HamburgerMenu() { rel="noreferrer noopener" click={itemClick('mail')} > - + E-Mail - + GitHub - + Discord - + Twitter diff --git a/src/components/Home/index.js b/src/components/Home/index.js index 2593eabbc4..331a2affc5 100644 --- a/src/components/Home/index.js +++ b/src/components/Home/index.js @@ -1,7 +1,6 @@ import React from 'react' import LearnMore from '../LearnMore' -import Page from '../Page' import Hero from '../Hero' import LandingHero from '../LandingHero' import Diagram from '../Diagram' @@ -13,7 +12,7 @@ import { LearnMoreSection } from './styles' export default function HomePage() { return ( - + <> @@ -25,6 +24,6 @@ export default function HomePage() { - + ) } diff --git a/src/components/LandingHero/index.js b/src/components/LandingHero/index.js index ef9ca7f04c..a76338ced2 100644 --- a/src/components/LandingHero/index.js +++ b/src/components/LandingHero/index.js @@ -81,7 +81,7 @@ export default class LandingHero extends Component { Watch video { + const location = useLocation() useEffect(() => { - if (!window.GA_INITIALIZED) { - initGA() - window.GA_INITIALIZED = true + if (location.hash) { + const node = document.querySelector(location.hash) + + if (node) { + node.scrollIntoView() + } + } else { + document + .getElementById('bodybag') + .scrollTo({ top: 0, behavior: 'smooth' }) } + }, [location.href]) +} + +export default function Layout(props) { + let LayoutComponent = MainLayout + + useAnchorNavigation() - // Apperently next/head is using promises and because of that - // it updates after page is already rendered and useEffect is called, - // because of that we use rAF to place GA call after head update - requestAnimationFrame(() => logPageView()) - }, [router.asPath]) + if (!props.pageContext.is404 && /^\/doc/.test(props.location.pathname)) { + LayoutComponent = DocLayout + } return ( - - - - - {children} -