docs: inline website theme ()

Inline @rocketseat theme for Gatsby
because we need a lot of changes.

Fix bad GitHub edit url, next/prev links,
    external links without target="_blank".
This commit is contained in:
Isaev Denis 2020-05-16 17:17:58 +03:00 committed by GitHub
parent e560b3f76e
commit 0d774cd24a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
43 changed files with 2003 additions and 72 deletions

2
docs/gatsby-browser.js Normal file
View file

@ -0,0 +1,2 @@
export { wrapRootElement } from "./src/@rocketseat/gatsby-theme-docs/gatsby/wrapRootElement";
export { wrapPageElement } from "./src/@rocketseat/gatsby-theme-docs/gatsby/wrapPageElement";

View file

@ -1,28 +1,73 @@
const withDefault = require(`./src/@rocketseat/gatsby-theme-docs-core/util/with-default`);
const siteUrl = `https://golangci-lint.run`;
const siteConfig = require(`./src/config/site.js`);
const { basePath, configPath, docsPath } = withDefault(siteConfig);
module.exports = {
siteMetadata: {
siteTitle: `golangci-lint`,
defaultTitle: ``,
siteTitleShort: `golangci-lint`,
siteDescription: `Fast Go linters runner golangci-lint.`,
siteUrl: siteUrl,
siteUrl,
siteAuthor: `@golangci`,
siteImage: `/logo.png`,
siteLanguage: `en`,
themeColor: `#7159c1`,
basePath: `/`,
basePath,
footer: `© ${new Date().getFullYear()}`,
},
plugins: [
`gatsby-alias-imports`,
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
{
resolve: `@rocketseat/gatsby-theme-docs`,
resolve: `gatsby-source-filesystem`,
options: {
configPath: `src/config`,
docsPath: `src/docs`,
githubUrl: `https://github.com/golangci/golangci-lint`,
baseDir: `docs`,
name: `docs`,
path: docsPath,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `config`,
path: configPath,
},
},
{
resolve: `gatsby-transformer-yaml`,
options: {
typeName: `SidebarItems`,
},
},
{
resolve: `gatsby-plugin-mdx`,
options: {
extensions: [`.mdx`, `.md`],
gatsbyRemarkPlugins: [
`gatsby-remark-autolink-headers`,
`gatsby-remark-external-links`,
`gatsby-remark-embedder`,
{
resolve: `gatsby-remark-images`,
options: {
maxWidth: 960,
withWebp: true,
linkImagesToOriginal: false,
},
},
`gatsby-remark-responsive-iframe`,
`gatsby-remark-copy-linked-files`,
],
plugins: [
`gatsby-remark-autolink-headers`,
`gatsby-remark-external-links`,
`gatsby-remark-images`,
],
},
},
{
@ -59,13 +104,11 @@ module.exports = {
},
},
},
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [`gatsby-remark-external-links`],
},
},
`gatsby-plugin-netlify`,
`gatsby-plugin-netlify-cache`,
`gatsby-plugin-catch-links`,
`gatsby-plugin-emotion`,
`gatsby-plugin-react-helmet`,
],
};

252
docs/gatsby-node.js Normal file
View file

@ -0,0 +1,252 @@
const path = require(`path`);
const { createFilePath } = require(`gatsby-source-filesystem`);
const fs = require(`fs`);
const {
normalizeBasePath,
resolveLink,
} = require(`./src/@rocketseat/gatsby-theme-docs-core/util/url`);
const withDefault = require(`./src/@rocketseat/gatsby-theme-docs-core/util/with-default`);
exports.createPages = ({ graphql, actions: { createPage }, reporter }) => {
reporter.success(`onCreateDocs`);
const siteConfig = require(`./src/config/site.js`);
const { basePath, baseDir, docsPath, githubUrl } = withDefault(siteConfig);
const docsTemplate = require.resolve(
`./src/@rocketseat/gatsby-theme-docs/src/templates/docs-query.js`
);
const homeTemplate = require.resolve(
`./src/@rocketseat/gatsby-theme-docs/src/templates/homepage-query.js`
);
return graphql(
`
{
files: allFile(filter: { extension: { in: ["md", "mdx"] } }) {
edges {
node {
id
relativePath
childMdx {
frontmatter {
next
}
fields {
slug
}
}
}
}
}
sidebar: allSidebarItems {
edges {
node {
label
link
items {
label
link
}
id
}
}
}
}
`
).then((result) => {
if (result.errors) {
reporter.panic(
`docs: there was an error loading the docs folder!`,
result.errors
);
return;
}
createPage({
path: basePath,
component: homeTemplate,
});
// Generate prev/next items based on sidebar.yml file
const sidebar = result.data.sidebar.edges;
const listOfItems = [];
sidebar.forEach(({ node: { label, link, items } }) => {
if (Array.isArray(items)) {
items.forEach((item) => {
listOfItems.push({
label: item.label,
link: resolveLink(item.link, basePath),
});
});
} else {
listOfItems.push({
label,
link: resolveLink(link, basePath),
});
}
});
// Generate docs pages
const docs = result.data.files.edges;
docs.forEach((doc) => {
const {
childMdx: {
frontmatter: { next },
fields: { slug },
},
relativePath,
} = doc.node;
const githubEditUrl =
githubUrl &&
`${githubUrl}/tree/master/${baseDir}/${docsPath}/${relativePath}`;
const currentPageIndex = listOfItems.findIndex(
(page) => page.link === slug
);
const prevItem = listOfItems[currentPageIndex - 1];
const nextItem = next
? listOfItems.find((item) => item.link === next)
: listOfItems[currentPageIndex + 1];
createPage({
path: slug,
component: docsTemplate,
context: {
slug,
prev: prevItem,
next: nextItem,
githubEditUrl,
},
});
});
reporter.success(`docs pages created`);
});
};
exports.createSchemaCustomization = ({ actions }) => {
actions.createTypes(`
type MdxFrontmatter @dontInfer {
title: String!
description: String
image: String
disableTableOfContents: Boolean
next: String
}
`);
actions.createTypes(`
type SidebarItems implements Node {
label: String!
link: String
items: [SidebarItemsItems]
}
type SidebarItemsItems {
label: String
link: String
}
`);
};
exports.onPreBootstrap = ({ store, reporter }, themeOptions) => {
const { configPath, docsPath } = withDefault(themeOptions);
const { program } = store.getState();
const dirs = [
path.join(program.directory, configPath),
path.join(program.directory, docsPath),
];
dirs.forEach((dir) => {
if (!fs.existsSync(dir)) {
reporter.success(`docs: intialized the ${dir} directory`);
fs.mkdirSync(dir);
}
});
};
exports.onCreateNode = (
{ node, actions: { createNodeField }, getNode },
themeOptions
) => {
if (node.internal.type !== `Mdx`) {
return;
}
const { basePath } = withDefault(themeOptions);
let value = createFilePath({ node, getNode });
if (value === "index") value = "";
createNodeField({
name: `slug`,
node,
value: normalizeBasePath(basePath, value),
});
createNodeField({
name: `id`,
node,
value: node.id,
});
};
/**
[
{
"node": {
"label": "Home",
"link": "/",
"items": null,
"id": "a2913be3-af3c-5fc9-967e-a058e86b20a9"
}
},
{
"node": {
"label": "With dropdown",
"link": null,
"items": [
{ "label": "My Example", "link": "/my-example" },
{ "label": "Teste 2", "link": "/teste-2" }
],
"id": "c7d9606c-4bda-5097-a0df-53108e9f4efd"
}
}
]
*/
// Ler todo o array e salvar em uma objeto chave/valor
/**
* {
* '/': {
* prev: null,
* next: {
* label: 'My example',
* link: '/my-example'
* }
* },
* '/my-example': {
* prev: {
* label: 'Home',
* link: '/'
* },
* next: {
* label: 'Teste 2',
* link: '/teste-2'
* }
* },
* '/teste-2': {
* prev: {
* label: 'My example',
* link: '/my-example'
* },
* next: null
* }
* }
*/

2
docs/gatsby-ssr.js Normal file
View file

@ -0,0 +1,2 @@
export { wrapRootElement } from "./src/@rocketseat/gatsby-theme-docs/gatsby/wrapRootElement";
export { wrapPageElement } from "./src/@rocketseat/gatsby-theme-docs/gatsby/wrapPageElement";

44
docs/package-lock.json generated
View file

@ -1,5 +1,5 @@
{
"name": "gatsby-starter-rocket-docs",
"name": "golangci-lint.run",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
@ -2139,48 +2139,6 @@
}
}
},
"@rocketseat/gatsby-theme-docs": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@rocketseat/gatsby-theme-docs/-/gatsby-theme-docs-2.1.2.tgz",
"integrity": "sha512-zC0fquMV+KmEjjCojqIrrSFHy0YJ+OBirF2I/PD/sQp0f9vCoaqu4tDfZiTWimJdHrHniDuE+E794k8av9Fv9Q==",
"requires": {
"@emotion/core": "^10.0.27",
"@emotion/styled": "^10.0.27",
"@mdx-js/react": "^1.5.5",
"@rocketseat/gatsby-theme-docs-core": "^1.1.0",
"emotion-theming": "^10.0.27",
"gatsby-plugin-catch-links": "^2.1.24",
"gatsby-plugin-emotion": "^4.1.21",
"gatsby-plugin-mdx": "^1.0.68",
"gatsby-plugin-react-helmet": "^3.1.16",
"polished": "^3.4.2",
"prism-react-renderer": "^1.0.2",
"prop-types": "^15.7.2",
"react-headroom": "^3.0.0",
"react-helmet": "^5.2.1",
"react-icons": "^3.8.0",
"react-live": "^2.2.2",
"url-join": "^4.0.1"
}
},
"@rocketseat/gatsby-theme-docs-core": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@rocketseat/gatsby-theme-docs-core/-/gatsby-theme-docs-core-1.1.0.tgz",
"integrity": "sha512-woha2nK4CKmI7NreW0tzdROgctIqDdcRs8OWdHx+iW+43wqwCj3p5caoPvKW0AbBQzJaiQKKOvCfILLLarbhBg==",
"requires": {
"@mdx-js/mdx": "^1.5.5",
"gatsby-plugin-mdx": "^1.0.67",
"gatsby-plugin-sharp": "^2.4.0",
"gatsby-remark-autolink-headers": "^2.1.23",
"gatsby-remark-copy-linked-files": "^2.1.36",
"gatsby-remark-embedder": "^1.8.0",
"gatsby-remark-images": "^3.1.42",
"gatsby-remark-responsive-iframe": "^2.2.31",
"gatsby-source-filesystem": "^2.1.46",
"gatsby-transformer-sharp": "^2.3.13",
"gatsby-transformer-yaml": "^2.2.23"
}
},
"@sindresorhus/is": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz",

View file

@ -1,36 +1,53 @@
{
"name": "gatsby-starter-rocket-docs",
"name": "golangci-lint.run",
"private": true,
"version": "1.0.0",
"description": "Out of the box Gatsby Starter for creating documentation websites easily and quickly. With support for MDX, code highlight, Analytics, SEO and more",
"author": "João Pedro Schmitz <oi@joaopedro.cc> (@joaopedro_cc)",
"description": "",
"author": "",
"license": "MIT",
"starter-name": "gatsby-starter-rocket-docs",
"dependencies": {
"@rocketseat/gatsby-theme-docs": "^2.1.1",
"gatsby": "^2.19.10",
"@emotion/core": "^10.0.27",
"@emotion/styled": "^10.0.27",
"@mdx-js/mdx": "^1.5.5",
"@mdx-js/react": "^1.5.5",
"emotion-theming": "^10.0.27",
"gatsby-alias-imports": "^1.0.4",
"gatsby-plugin-canonical-urls": "^2.1.19",
"gatsby-plugin-catch-links": "^2.1.24",
"gatsby-plugin-emotion": "^4.1.21",
"gatsby-plugin-google-analytics": "^2.1.34",
"gatsby-plugin-manifest": "^2.2.37",
"gatsby-plugin-netlify": "^2.3.2",
"gatsby-plugin-mdx": "^1.0.68",
"gatsby-plugin-netlify-cache": "^1.2.0",
"gatsby-plugin-netlify": "^2.3.2",
"gatsby-plugin-offline": "^3.0.32",
"gatsby-plugin-react-helmet": "^3.1.16",
"gatsby-plugin-react-svg": "^3.0.0",
"gatsby-plugin-sharp": "^2.4.0",
"gatsby-plugin-sitemap": "^2.2.26",
"gatsby-remark-autolink-headers": "^2.1.23",
"gatsby-remark-copy-linked-files": "^2.1.36",
"gatsby-remark-embedder": "^1.8.0",
"gatsby-remark-external-links": "0.0.4",
"gatsby-remark-images": "^3.1.42",
"gatsby-remark-responsive-iframe": "^2.2.31",
"gatsby-source-filesystem": "^2.1.46",
"gatsby-transformer-remark": "^2.8.8",
"gatsby-transformer-sharp": "^2.3.13",
"gatsby-transformer-yaml": "^2.2.23",
"gatsby": "^2.19.10",
"polished": "^3.4.2",
"prism-react-renderer": "^1.0.2",
"prop-types": "^15.7.2",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-icons": "^3.10.0"
"react-headroom": "^3.0.0",
"react-helmet": "^5.2.1",
"react-icons": "^3.10.0",
"react-live": "^2.2.2",
"react": "^16.12.0",
"url-join": "^4.0.1"
},
"devDependencies": {},
"keywords": [
"gatsby",
"rocketseat",
"gatsby-starter"
],
"scripts": {
"build": "make -C .. expand_website_templates && gatsby build",
"start": "gatsby develop",

View file

@ -0,0 +1 @@
export { useSidebar } from './src/hooks/useSidebar';

View file

@ -0,0 +1,59 @@
import { graphql, useStaticQuery } from 'gatsby';
import { resolveLink } from '../../util/url';
export function useSidebar() {
const data = useStaticQuery(graphql`
{
allSidebarItems {
edges {
node {
label
link
items {
label
link
}
id
}
}
}
site {
siteMetadata {
basePath
}
}
}
`);
const { basePath } = data.site.siteMetadata;
const {
allSidebarItems: { edges },
} = data;
if (basePath) {
const normalizedSidebar = edges.map(
({ node: { label, link, items, id } }) => {
if (Array.isArray(items)) {
items = items.map(item => ({
label: item.label,
link: resolveLink(item.link, basePath),
}));
}
return {
node: {
id,
label,
items,
link: resolveLink(link, basePath),
},
};
},
);
return normalizedSidebar;
}
return edges;
}

View file

@ -0,0 +1,13 @@
function normalizeBasePath(basePath, link) {
return `/${basePath}/${link}`.replace(/\/\/+/g, `/`);
}
function isExternalUrl(url) {
return new RegExp('^((https?:)?//)', 'i').test(url);
}
function resolveLink(link, basePath) {
return isExternalUrl(link) ? link : normalizeBasePath(basePath, link);
}
module.exports = { resolveLink, normalizeBasePath, isExternalUrl };

View file

@ -0,0 +1,15 @@
module.exports = themeOptions => {
const basePath = themeOptions.basePath || `/`;
const configPath = themeOptions.configPath || `config`;
const docsPath = themeOptions.docsPath || `docs`;
const baseDir = themeOptions.baseDir || ``;
const { githubUrl } = themeOptions;
return {
basePath,
configPath,
docsPath,
baseDir,
githubUrl,
};
};

View file

@ -0,0 +1,14 @@
/* eslint-disable */
import React from 'react';
import { MDXProvider } from '@mdx-js/react';
import Code from '../src/components/Code';
const components = {
code: Code,
inlineCode: props => <code className="inline-code" {...props} />,
};
export function wrapPageElement({ element }) {
return <MDXProvider components={components}>{element}</MDXProvider>;
}

View file

@ -0,0 +1,17 @@
/* eslint-disable */
import React from 'react';
import { ThemeProvider } from 'emotion-theming';
import defaultTheme from '../src/styles/theme';
import GlobalStyle from '../src/styles/global';
export function wrapRootElement({ element }) {
return (
<ThemeProvider theme={defaultTheme}>
<>
<GlobalStyle />
{element}
</>
</ThemeProvider>
);
}

File diff suppressed because one or more lines are too long

After

(image error) Size: 6.5 KiB

View file

@ -0,0 +1,108 @@
import React, { useState } from 'react';
import Highlight, { defaultProps } from 'prism-react-renderer';
import PropTypes from 'prop-types';
import theme from 'prism-react-renderer/themes/dracula';
import { LiveProvider, LiveEditor } from 'react-live';
import { mdx } from '@mdx-js/react';
import { copyToClipboard } from '../../util/copy-to-clipboard';
import {
CopyCode,
LineNo,
Pre,
PreHeader,
LiveWrapper,
LivePreview,
LiveError,
StyledEditor,
} from './styles';
export default function CodeHighlight({
children,
className,
live,
title,
lineNumbers,
}) {
const [copied, setCopied] = useState(false);
const codeString = children.trim();
const language = className.replace(/language-/, '');
if (live) {
return (
<LiveProvider
code={codeString}
noInline
theme={theme}
transformCode={code => `/** @jsx mdx */${code}`}
scope={{ mdx }}
>
<LiveWrapper>
<StyledEditor>
<LiveEditor />
</StyledEditor>
<LivePreview />
</LiveWrapper>
<LiveError />
</LiveProvider>
);
}
const handleClick = () => {
setCopied(true);
copyToClipboard(codeString);
};
return (
<>
{title && <PreHeader>{title}</PreHeader>}
<div className="gatsby-highlight">
<Highlight
{...defaultProps}
code={codeString}
language={language}
theme={theme}
>
{({
className: blockClassName,
style,
tokens,
getLineProps,
getTokenProps,
}) => (
<Pre className={blockClassName} style={style} hasTitle={title}>
<CopyCode onClick={handleClick}>
{copied ? 'Copied!' : 'Copy'}
</CopyCode>
<code>
{tokens.map((line, i) => (
<div {...getLineProps({ line, key: i })}>
{lineNumbers && <LineNo>{i + 1}</LineNo>}
{line.map((token, key) => (
<span {...getTokenProps({ token, key })} />
))}
</div>
))}
</code>
</Pre>
)}
</Highlight>
</div>
</>
);
}
CodeHighlight.propTypes = {
children: PropTypes.string.isRequired,
className: PropTypes.string.isRequired,
live: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
title: PropTypes.string,
lineNumbers: PropTypes.string,
};
CodeHighlight.defaultProps = {
live: false,
title: null,
lineNumbers: null,
};

View file

@ -0,0 +1,138 @@
import styled from '@emotion/styled';
import { css } from '@emotion/core';
import { darken } from 'polished';
import {
LiveError as AuxLiveError,
LivePreview as AuxLivePreview,
} from 'react-live';
export const Pre = styled.pre`
text-align: left;
margin: 0 0 16px 0;
box-shadow: 1px 1px 20px rgba(20, 20, 20, 0.27);
padding: 2rem 1rem 1rem 1rem;
overflow: auto;
word-wrap: normal;
border-radius: ${({ hasTitle }) => (hasTitle ? '0 0 3px 3px' : '3px')};
webkit-overflow-scrolling: touch;
& .token-line {
line-height: 1.3rem;
height: 1.3rem;
font-size: 15px;
}
`;
export const LiveWrapper = styled.div`
display: flex;
flex-direction: row;
justify-content: stretch;
align-items: stretch;
border-radius: 3px;
box-shadow: 1px 1px 20px rgba(20, 20, 20, 0.27);
overflow: hidden;
margin-bottom: 32px;
@media (max-width: 600px) {
flex-direction: column;
}
`;
const column = css`
flex-basis: 50%;
width: 50%;
max-width: 50%;
@media (max-width: 600px) {
flex-basis: auto;
width: 100%;
max-width: 100%;
}
`;
export const StyledEditor = styled.div`
font-family: SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono',
'Courier New', monospace;
font-variant: no-common-ligatures no-discretionary-ligatures
no-historical-ligatures no-contextual;
font-size: 16px;
line-height: 1.3rem;
height: 350px;
max-height: 350px;
overflow: auto;
${column};
> div {
height: 100%;
}
* > textarea:focus {
outline: none;
}
.token {
font-style: normal !important;
}
`;
export const LivePreview = styled(AuxLivePreview)`
position: relative;
padding: 0.5rem;
background: white;
color: black;
height: auto;
overflow: hidden;
${column};
`;
export const LiveError = styled(AuxLiveError)`
display: block;
color: rgb(248, 248, 242);
white-space: pre-wrap;
text-align: left;
font-size: 15px;
font-family: SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono',
'Courier New', monospace;
font-variant: no-common-ligatures no-discretionary-ligatures
no-historical-ligatures no-contextual;
padding: 0.5rem;
border-radius: 3px;
background: rgb(255, 85, 85);
margin-bottom: 32px;
`;
export const PreHeader = styled.div`
background-color: ${darken('0.05', '#282a36')};
color: rgba(248, 248, 242, 0.75);
font-size: 0.75rem;
margin-top: 0.5rem;
padding: 0.8rem 1rem;
border-radius: 3px 3px 0 0;
`;
export const LineNo = styled.span`
display: inline-block;
width: 2rem;
user-select: none;
opacity: 0.3;
`;
export const CopyCode = styled.button`
position: absolute;
right: 0.75rem;
top: 0.25rem;
border: 0;
background: none;
border: none;
cursor: pointer;
color: rgb(248, 248, 242);
border-radius: 4px;
margin: 0.25em;
transition: all 250ms cubic-bezier(0.4, 0, 0.2, 1) 0s;
&:hover {
box-shadow: rgba(46, 41, 51, 0.08) 0px 1px 2px,
rgba(71, 63, 79, 0.08) 0px 2px 4px;
opacity: 0.8;
}
`;

View file

@ -0,0 +1,7 @@
/* eslint-disable react/prop-types */
import React from "react";
import Docs from "./Docs";
export default function Docspage({ data: { mdx }, pageContext }) {
return <Docs mdx={mdx} pageContext={pageContext} />;
}

View file

@ -0,0 +1,37 @@
import React from 'react';
import PropTypes from 'prop-types';
import { MdEdit } from 'react-icons/md';
export default function EditGithub({ githubEditUrl }) {
if (githubEditUrl) {
return (
<a
href={githubEditUrl}
target="_blank"
rel="noopener noreferrer"
style={{
display: 'flex',
alignItems: 'center',
textDecoration: 'none',
marginTop: '48px',
color: '#78757a',
opacity: '0.8',
fontSize: '14px',
fontWeight: 'normal',
}}
>
<MdEdit style={{ marginRight: '5px' }} />
Edit this page on GitHub
</a>
);
}
return null;
}
EditGithub.propTypes = {
githubEditUrl: PropTypes.string,
};
EditGithub.defaultProps = {
githubEditUrl: null,
};

View file

@ -0,0 +1,51 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Link } from 'gatsby';
import { MdKeyboardArrowRight, MdKeyboardArrowLeft } from 'react-icons/md';
import { Container, Post } from './styles';
export default function Docs({ prev, next }) {
return (
<Container>
{prev && (
<Post isLeft>
<Link to={prev.link}>
<MdKeyboardArrowLeft />
<div>
<p>Prev</p>
<h3>{prev.label}</h3>
</div>
</Link>
</Post>
)}
{next && (
<Post>
<Link to={next.link}>
<div>
<p>Next</p>
<h3>{next.label}</h3>
</div>
<MdKeyboardArrowRight />
</Link>
</Post>
)}
</Container>
);
}
Docs.propTypes = {
prev: PropTypes.shape({
label: PropTypes.string,
link: PropTypes.string,
}),
next: PropTypes.shape({
label: PropTypes.string,
link: PropTypes.string,
}),
};
Docs.defaultProps = {
prev: null,
next: null,
};

View file

@ -0,0 +1,70 @@
import styled from '@emotion/styled';
export const Container = styled.section`
display: flex;
justify-content: space-between;
align-items: center;
padding: 48px 0;
width: 100%;
@media (max-width: 780px) {
flex-direction: column;
}
`;
export const Post = styled.div`
transition: all 200ms;
${({ isLeft }) => !isLeft && 'margin-left: auto;'}
a {
display: flex;
text-decoration: none;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
svg {
width: 25px;
height: 25px;
color: #737380;
${({ isLeft }) => (isLeft ? 'margin-right: 16px' : 'margin-left: 16px')};
}
p {
letter-spacing: 0.142em;
text-transform: uppercase;
font-size: 12px;
margin: 0;
color: #999;
}
h3 {
color: #737380;
border: none;
margin: 0;
padding: 0;
font-weight: normal;
font-size: 16px;
}
}
&:hover {
opacity: 0.8;
a svg {
opacity: 0.8;
}
}
@media (max-width: 780px) {
width: 100%;
${({ isLeft }) => isLeft && 'margin-bottom: 16px'};
a {
justify-content: ${({ isLeft }) => (isLeft ? 'flex-start' : 'flex-end')};
}
}
`;

View file

@ -0,0 +1,37 @@
import React from 'react';
import PropTypes from 'prop-types';
import slug from '../../../util/slug';
import { Container } from './styles';
export default function TableOfContents({ headings }) {
if (headings && headings.length !== 0) {
return (
<Container>
<h2>Table of Contents</h2>
<nav>
<ul>
{headings
.filter(heading => heading.depth === 2)
.map(heading => (
<li key={heading.value}>
<a href={`#${slug(heading.value)}`}>{heading.value}</a>
</li>
))}
</ul>
</nav>
</Container>
);
}
return null;
}
TableOfContents.propTypes = {
headings: PropTypes.array,
};
TableOfContents.defaultProps = {
headings: null,
};

View file

@ -0,0 +1,58 @@
import styled from '@emotion/styled';
import { darken } from 'polished';
export const Container = styled.div`
position: sticky;
order: 2;
margin-left: 3rem;
max-width: 18rem;
top: 4rem;
max-height: calc(100vh - 4rem - 2.5rem - 3rem - 3rem);
overflow: auto;
width: 100%;
max-width: 25%;
h2 {
color: #737380;
text-transform: uppercase;
font-size: 13px;
font-weight: bold;
letter-spacing: 0.142em;
margin-top: 0rem;
border: none;
margin: 0 0 24px 0;
}
nav ul {
padding-left: 0;
margin-bottom: 0;
list-style: none;
li {
margin-bottom: 12px;
line-height: 1.1;
a {
font-size: 13px;
color: #999999;
font-weight: 400;
text-decoration: none;
transition: all 0.2s;
&:hover {
color: ${({ theme }) => darken('0.2', theme.colors.sidebar.link)};
}
}
}
}
@media (max-width: 1200px) {
position: relative;
top: auto;
order: 0;
max-width: 100%;
margin: 0 0 24px 0;
padding-bottom: 16px;
border-bottom: 1px solid rgba(120, 117, 122, 0.2);
}
`;

View file

@ -0,0 +1,51 @@
import React from 'react';
import PropTypes from 'prop-types';
import { MDXRenderer } from 'gatsby-plugin-mdx';
import Layout from '../Layout';
import SEO from '../SEO';
import PostNav from './PostNav';
import EditGithub from './EditGithub';
export default function Docs({ mdx, pageContext }) {
const { prev, next, githubEditUrl } = pageContext;
const { title, description, image, disableTableOfContents } = mdx.frontmatter;
const { headings, body } = mdx;
const { slug } = mdx.fields;
return (
<>
<SEO title={title} description={description} slug={slug} image={image} />
<Layout
disableTableOfContents={disableTableOfContents}
title={title}
headings={headings}
>
<MDXRenderer>{body}</MDXRenderer>
<EditGithub githubEditUrl={githubEditUrl} />
<PostNav prev={prev} next={next} />
</Layout>
</>
);
}
Docs.propTypes = {
mdx: PropTypes.shape({
body: PropTypes.string,
headings: PropTypes.array,
frontmatter: PropTypes.shape({
title: PropTypes.string,
description: PropTypes.string,
image: PropTypes.string,
disableTableOfContents: PropTypes.bool,
}),
fields: PropTypes.shape({
slug: PropTypes.string,
}),
}).isRequired,
pageContext: PropTypes.shape({
prev: PropTypes.shape({}),
next: PropTypes.shape({}),
githubEditUrl: PropTypes.string,
}).isRequired,
};

View file

@ -0,0 +1,79 @@
import React from 'react';
import PropTypes from 'prop-types';
import Headroom from 'react-headroom';
import styled from '@emotion/styled';
import { GiHamburgerMenu } from 'react-icons/gi';
import { useStaticQuery, graphql } from 'gatsby';
const Container = styled.header`
display: flex;
justify-content: flex-start;
align-items: center;
height: 60px;
padding: 0 24px;
background: #fff;
transition: transform 0.5s;
transform: translate3d(
${({ isMenuOpen }) => (isMenuOpen ? '240px' : '0')},
0,
0
);
h2 {
margin: 0;
border: none;
padding: 0;
font-size: 18px;
color: #000;
}
button {
border: none;
background: #fff;
cursor: pointer;
margin-right: 16px;
}
@media (min-width: 780px) {
display: none;
}
`;
export default function Header({ handleMenuOpen, isMenuOpen }) {
const { site } = useStaticQuery(
graphql`
query {
site {
siteMetadata {
siteTitleShort
}
}
}
`,
);
const { siteTitleShort } = site.siteMetadata;
return (
<Headroom>
<Container isMenuOpen={isMenuOpen}>
<button
aria-label="Open sidebar"
type="button"
onClick={handleMenuOpen}
>
<GiHamburgerMenu size={23} />
</button>
<h2>{siteTitleShort}</h2>
</Container>
</Headroom>
);
}
Header.propTypes = {
handleMenuOpen: PropTypes.func.isRequired,
isMenuOpen: PropTypes.bool.isRequired,
};

View file

@ -0,0 +1,14 @@
import React from 'react';
import Index from '../text/index.mdx';
import Layout from './Layout';
import SEO from './SEO';
export default function Home() {
return (
<Layout>
<SEO />
<Index />
</Layout>
);
}

View file

@ -0,0 +1,52 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import TableOfContents from '../Docs/TOC';
import Sidebar from '../Sidebar';
import Header from '../Header';
import { Wrapper, Main, Title, Children } from './styles';
export default function Layout({
children,
disableTableOfContents,
title,
headings,
}) {
const [isMenuOpen, setMenuOpen] = useState(false);
const disableTOC =
disableTableOfContents === true || !headings || headings.length === 0;
function handleMenuOpen() {
setMenuOpen(!isMenuOpen);
}
return (
<>
<Sidebar isMenuOpen={isMenuOpen} />
<Header handleMenuOpen={handleMenuOpen} isMenuOpen={isMenuOpen} />
<Wrapper isMenuOpen={isMenuOpen}>
{title && <Title>{title}</Title>}
<Main disableTOC={disableTOC}>
{!disableTOC && <TableOfContents headings={headings} />}
<Children hasTitle={title}>{children}</Children>
</Main>
</Wrapper>
</>
);
}
Layout.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]).isRequired,
disableTableOfContents: PropTypes.bool,
title: PropTypes.string,
headings: PropTypes.array,
};
Layout.defaultProps = {
disableTableOfContents: false,
title: '',
headings: null,
};

View file

@ -0,0 +1,59 @@
import styled from '@emotion/styled';
import { css } from '@emotion/core';
export const Main = styled.main`
padding: 0 40px;
height: 100%;
${({ disableTOC }) =>
!disableTOC &&
css`
display: flex;
justify-content: flex-start;
align-items: flex-start;
position: relative;
@media (max-width: 1200px) {
flex-direction: column;
}
`}
@media (max-width: 780px) {
padding: 24px 24px 48px 24px;
}
`;
export const Children = styled.div`
width: 100%;
min-width: 75%;
max-width: 75%;
@media (max-width: 1200px) {
min-width: 100%;
max-width: 100%;
}
${({ hasTitle }) => !hasTitle && 'padding-top: 40px'};
`;
export const Wrapper = styled.div`
padding-left: 280px;
transition: transform 0.5s;
@media (max-width: 780px) {
padding-left: 0;
transform: translate3d(
${({ isMenuOpen }) => (isMenuOpen ? '240px' : '0')},
0,
0
);
}
`;
export const Title = styled.h1`
padding: 40px 0 0 40px;
@media (max-width: 780px) {
padding: 24px 0 0 24px;
}
`;

View file

@ -0,0 +1,119 @@
import React from 'react';
import PropTypes from 'prop-types';
import Helmet from 'react-helmet';
import urljoin from 'url-join';
import { useStaticQuery, graphql } from 'gatsby';
export default function SEO({ description, title, slug, image, children }) {
const { site } = useStaticQuery(
graphql`
query {
site {
siteMetadata {
defaultTitle
siteTitleShort
siteTitle
siteImage
siteDescription
siteLanguage
siteUrl
siteAuthor
}
}
}
`,
);
const {
siteTitle,
siteTitleShort,
siteUrl,
defaultTitle,
siteImage,
siteDescription,
siteLanguage,
siteAuthor,
siteIcon,
} = site.siteMetadata;
const metaTitle = title ? `${title} | ${siteTitle}` : defaultTitle;
const metaUrl = urljoin(siteUrl, slug);
const metaImage = urljoin(siteUrl, image || siteImage);
const metaDescription = description || siteDescription;
const schemaOrgJSONLD = [
{
'@context': 'http://schema.org',
'@type': 'WebSite',
url: metaUrl,
name: title,
alternateName: siteTitleShort,
},
];
return (
<Helmet
htmlAttributes={{
lang: siteLanguage,
}}
title={metaTitle}
>
{siteIcon && <link rel="icon" href={siteIcon} />}
<meta name="description" content={metaDescription} />
<meta name="image" content={metaImage} />
<meta httpEquiv="x-ua-compatible" content="IE=edge,chrome=1" />
<meta name="MobileOptimized" content="320" />
<meta name="HandheldFriendly" content="True" />
<meta name="google" content="notranslate" />
<meta name="referrer" content="no-referrer-when-downgrade" />
<meta property="og:url" content={metaUrl} />
<meta property="og:type" content="website" />
<meta property="og:title" content={metaTitle} />
<meta property="og:description" content={metaDescription} />
<meta property="og:locale" content={siteLanguage} />
<meta property="og:site_name" content={siteTitle} />
<meta property="og:image" content={metaImage} />
<meta property="og:image:secure_url" content={metaImage} />
<meta property="og:image:alt" content="Banner" />
<meta property="og:image:type" content="image/png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={metaTitle} />
<meta name="twitter:site" content={siteAuthor} />
<meta name="twitter:creator" content={siteAuthor} />
<meta name="twitter:image" content={metaImage} />
<meta name="twitter:image:src" content={metaImage} />
<meta name="twitter:image:alt" content="Banner" />
<meta name="twitter:image:width" content="1200" />
<meta name="twitter:image:height" content="630" />
<script type="application/ld+json">
{JSON.stringify(schemaOrgJSONLD)}
</script>
{children}
</Helmet>
);
}
SEO.propTypes = {
title: PropTypes.string,
description: PropTypes.string,
slug: PropTypes.string,
image: PropTypes.string,
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.element),
PropTypes.node,
]),
};
SEO.defaultProps = {
title: '',
description: '',
slug: '',
image: '',
children: '',
};

View file

@ -0,0 +1,19 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FiExternalLink } from 'react-icons/fi';
export default function ExternalLink({ link, label }) {
return (
<a href={link} rel="noopener noreferrer">
{label}
<FiExternalLink
style={{ width: '16px', height: '16px', marginLeft: '10px' }}
/>
</a>
);
}
ExternalLink.propTypes = {
link: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
};

View file

@ -0,0 +1,16 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Link } from 'gatsby';
export default function InternalLink({ link, label }) {
return (
<Link to={link} activeClassName="active-link">
{label}
</Link>
);
}
InternalLink.propTypes = {
link: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
};

View file

@ -0,0 +1,101 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useStaticQuery, graphql, Link } from 'gatsby';
import { useSidebar } from '@rocketseat/gatsby-theme-docs-core';
import {
Container,
LogoContainer,
List,
Heading,
Item,
SubItem,
} from './styles';
import { isExternalUrl } from '../../util/url';
import ExternalLink from './ExternalLink';
import InternalLink from './InternalLink';
import Logo from '../Logo';
function ListWithSubItems({ children, text }) {
return (
<>
<Heading>{text}</Heading>
<SubItem>{children}</SubItem>
</>
);
}
export default function Sidebar({ isMenuOpen }) {
const {
site: {
siteMetadata: { footer, basePath },
},
} = useStaticQuery(graphql`
{
site {
siteMetadata {
footer
basePath
}
}
}
`);
const data = useSidebar();
function renderLink(link, label) {
return isExternalUrl(link) ? (
<ExternalLink link={link} label={label} />
) : (
<InternalLink link={link} label={label} />
);
}
return (
<Container isMenuOpen={isMenuOpen}>
<LogoContainer>
<Link to={basePath}>
<Logo />
</Link>
</LogoContainer>
<nav>
<List>
{data.map(({ node: { label, link, items, id } }) => {
if (Array.isArray(items)) {
const subitems = items.map(item => {
return (
<Item key={item.link}>
{renderLink(item.link, item.label)}
</Item>
);
});
return (
<ListWithSubItems key={id} text={label}>
{subitems}
</ListWithSubItems>
);
}
return <Item key={id}>{renderLink(link, label)}</Item>;
})}
</List>
</nav>
<footer>
<p>{footer}</p>
</footer>
</Container>
);
}
ListWithSubItems.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.element),
PropTypes.node,
]).isRequired,
text: PropTypes.string.isRequired,
};
Sidebar.propTypes = {
isMenuOpen: PropTypes.bool.isRequired,
};

View file

@ -0,0 +1,142 @@
import styled from '@emotion/styled';
import { darken } from 'polished';
export const Container = styled.aside`
width: 20%;
max-width: 280px;
min-width: 280px;
background-color: ${({ theme }) => theme.colors.sidebar.background};
position: fixed;
overflow-y: auto;
left: 0;
display: flex;
justify-content: space-between;
align-items: center;
flex-direction: column;
transition: transform 0.5s;
height: 100vh;
nav {
width: 100%;
align-self: flex-start;
margin-bottom: 20px;
flex: 1;
}
footer {
padding: 24px 0 24px 30px;
width: 100%;
p {
color: ${({ theme }) => theme.colors.sidebar.footer};
font-size: 12px;
margin: 0;
}
}
@media (max-width: 780px) {
max-width: 240px;
min-width: 240px;
transform: translate3d(
${({ isMenuOpen }) => (isMenuOpen ? '0' : '-100%')},
0,
0
);
}
`;
export const LogoContainer = styled.div`
width: 100%;
height: 100%;
max-height: 100px;
min-height: 100px;
padding: 20px 0;
a {
width: 100%;
height: 100%;
padding-left: 30px;
display: flex;
justify-content: flex-start;
align-items: center;
}
`;
export const List = styled.ul`
list-style: none;
width: 100%;
padding-left: 0;
display: flex;
justify-content: flex-start;
align-items: center;
flex-direction: column;
`;
export const Heading = styled.li`
padding-left: 30px;
width: 100%;
text-transform: uppercase;
font-size: 13px;
font-weight: bold;
margin-top: 20px;
color: ${({ theme }) => theme.colors.primary};
letter-spacing: 0.142em;
`;
export const Item = styled.li`
font-size: 15px;
width: 100%;
transition: all 200ms ease-in-out;
padding: 0 20px;
a,
span {
display: block;
font-size: 15px;
color: ${({ theme }) => theme.colors.sidebar.link};
background-color: ${({ theme }) => theme.colors.sidebar.background};
padding: 4px 10px;
margin: 4px 0;
border-radius: 4px;
font-weight: normal;
text-decoration: none;
width: 100%;
height: 100%;
display: flex;
justify-content: flex-start;
align-items: center;
cursor: pointer;
margin: 0 auto;
transition: background-color 0.2s, color 0.2s, padding-left 0.2s;
svg {
width: 20px;
height: 20px;
margin-right: 10px;
}
&:not(.active-link):hover {
padding-left: 20px;
color: ${({ theme }) => darken('0.2', theme.colors.sidebar.link)};
}
&.active-link {
color: ${({ theme }) => darken('0.2', theme.colors.sidebar.link)};
background-color: ${({ theme }) => theme.colors.sidebar.itemActive};
}
}
`;
export const SubItem = styled(List)`
margin-top: 5px;
`;

View file

@ -0,0 +1,277 @@
import React from 'react';
import { Global, css } from '@emotion/core';
import { useTheme } from 'emotion-theming';
import { lighten } from 'polished';
export default function GlobalStyle() {
const theme = useTheme();
return (
<Global
styles={css`
@import url('https://fonts.googleapis.com/css?family=Roboto&display=swap');
*,
*::after,
*::before {
margin: 0;
padding: 0;
box-sizing: border-box;
}
*::selection {
background: ${lighten('0.35', '#737380')}!important;
}
body {
font-size: 16px;
font-family: 'Roboto', sans-serif;
background-color: ${theme.colors.background};
text-rendering: optimizelegibility;
}
h1 {
font-size: 32px;
color: #333;
font-weight: normal;
margin-bottom: 24px;
}
h2 {
font-size: 24px;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 16px;
}
h2,
h3,
h4,
h5,
h6 {
color: #737380;
margin: 24px 0 16px 0;
font-weight: normal;
}
p {
color: #737380;
font-size: 16px;
line-height: 28px;
margin-bottom: 16px;
font-weight: 400;
}
code.inline-code {
display: inline-block;
vertical-align: middle;
line-height: 1;
padding: 0.2em 0.2em 0.3em 0.2em;
background-color: #44475a;
color: rgba(248, 248, 242);
font-size: 14px;
border-radius: 3px;
font-feature-settings: 'clig' 0, 'calt' 0;
font-variant: no-common-ligatures no-discretionary-ligatures
no-historical-ligatures no-contextual;
}
a {
color: #737380;
font-weight: bold;
&:hover {
color: ${theme.colors.primary}!important;
transition: all 100ms cubic-bezier(0.4, 0, 0.2, 1) 0s;
opacity: 1 !important;
}
}
blockquote {
margin: 0;
p {
padding: 1rem;
background: #f5f5fa;
border-radius: 5px;
}
}
hr {
border: 0;
height: 0;
border-top: 1px solid rgba(0, 0, 0, 0.1);
border-bottom: 1px solid rgba(255, 255, 255, 0.3);
}
table {
border-collapse: collapse;
border-spacing: 0;
width: 100%;
margin-bottom: 16px;
color: #444;
}
th,
td {
text-align: left;
padding: 12px;
}
tr:nth-of-type(2n) td {
background-color: ${theme.colors.sidebar.itemActive};
}
tr {
background-color: #ffffff;
}
iframe {
margin-bottom: 16px;
}
img {
max-width: 100%;
}
ul,
ol {
color: #737380;
padding-left: 15px;
margin-bottom: 16px;
li {
line-height: 28px;
}
}
.gatsby-highlight {
position: relative;
.token {
font-style: normal !important;
}
}
pre[class*='language-']::before {
background: #d9d7e0;
border-radius: 0 0 4px 4px;
color: #232129;
font-size: 12px;
font-family: SFMono-Regular, Menlo, Monaco, Consolas,
'Liberation Mono', 'Courier New', monospace;
letter-spacing: 0.075em;
line-height: 1;
padding: 0.25rem 0.5rem;
position: absolute;
left: 1rem;
text-align: right;
text-transform: uppercase;
top: 0;
}
pre[class*='language-'] code {
font-family: SFMono-Regular, Menlo, Monaco, Consolas,
'Liberation Mono', 'Courier New', monospace;
font-variant: no-common-ligatures no-discretionary-ligatures
no-historical-ligatures no-contextual;
}
pre[class~='language-js']::before,
pre[class~='language-javascript']::before {
content: 'js';
background: #f7df1e;
}
pre[class~='language-jsx']::before {
content: 'jsx';
background: #61dafb;
}
pre[class~='language-typescript']::before,
pre[class~='language-ts']::before {
content: 'ts';
background: #294e80;
color: #fff;
}
pre[class~='language-tsx']::before {
content: 'tsx';
background: #294e80;
color: #fff;
}
pre[class~='language-graphql']::before {
content: 'GraphQL';
background: #e10098;
color: #fff;
}
pre[class~='language-html']::before {
content: 'html';
background: #005a9c;
color: #fff;
}
pre[class~='language-css']::before {
content: 'css';
background: #ff9800;
color: #fff;
}
pre[class~='language-mdx']::before {
content: 'mdx';
background: #f9ac00;
color: #fff;
}
pre[class~='language-shell']::before {
content: 'shell';
}
pre[class~='language-sh']::before {
content: 'sh';
}
pre[class~='language-bash']::before {
content: 'bash';
}
pre[class~='language-yaml']::before {
content: 'yaml';
background: #ffa8df;
}
pre[class~='language-markdown']::before {
content: 'md';
}
pre[class~='language-json']::before,
pre[class~='language-json5']::before {
content: 'json';
background: linen;
}
pre[class~='language-diff']::before {
content: 'diff';
background: #e6ffed;
}
pre[class~='language-text']::before {
content: 'text';
background: #fff;
}
pre[class~='language-flow']::before {
content: 'flow';
background: #e8bd36;
}
`}
/>
);
}

View file

@ -0,0 +1,14 @@
export default {
colors: {
primary: '#7159c1',
background: '#fff',
sidebar: {
background: '#ffffff',
link: '#999',
heading: '#aaa',
linkActive: '#13131A',
itemActive: '#F5F5FA',
footer: '#A8A8B3',
},
},
};

View file

@ -0,0 +1,27 @@
import { graphql } from "gatsby";
import DocsComponent from "../components/Docs-wrapper";
export default DocsComponent;
export const query = graphql`
query($slug: String!) {
mdx(fields: { slug: { eq: $slug } }) {
id
excerpt(pruneLength: 160)
fields {
slug
}
frontmatter {
title
description
image
disableTableOfContents
}
body
headings {
depth
value
}
}
}
`;

View file

@ -0,0 +1,3 @@
import HomepageComponent from '../components/Homepage';
export default HomepageComponent;

View file

@ -0,0 +1,5 @@
Welcome, this is the default page of `@rocketseat/gatsby-theme-docs` from Rocketseat! To
change this page just create a file named `index.mdx` inside `@rocketseat/gatsby-theme-docs/text`
and place there your text. Also, if you need help, feel free to open an issue with a
description of the problem you're facing or, if you prefer, you can chat with us
on our [Discord Community](https://rocketseat.com.br/comunidade) 👋🏻

View file

@ -0,0 +1,31 @@
/* eslint-disable */
// https://github.com/gatsbyjs/gatsby/blob/master/www/src/utils/copy-to-clipboard.js
export const copyToClipboard = str => {
const { clipboard } = window.navigator;
/*
* fallback to older browsers (including Safari)
* if clipboard API not supported
*/
if (!clipboard || typeof clipboard.writeText !== `function`) {
const textarea = document.createElement(`textarea`);
textarea.value = str;
textarea.setAttribute(`readonly`, true);
textarea.setAttribute(`contenteditable`, true);
textarea.style.position = `absolute`;
textarea.style.left = `-9999px`;
document.body.appendChild(textarea);
textarea.select();
const range = document.createRange();
const sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
textarea.setSelectionRange(0, textarea.value.length);
document.execCommand(`copy`);
document.body.removeChild(textarea);
return Promise.resolve(true);
}
return clipboard.writeText(str);
};

View file

@ -0,0 +1,11 @@
export default function(string) {
return string
.toString() // Cast to string
.toLowerCase() // Convert the string to lowercase letters
.trim() // Remove whitespace from both sides of a string
.replace(/\s/g, '-') // Replace each space with -
.replace(
/[^\w\-\u00b4\u00C0-\u00C3\u00c7\u00C9-\u00CA\u00CD\u00D3-\u00D5\u00DA\u00E0-\u00E3\u00E7\u00E9-\u00EA\u00ED\u00F3-\u00F5\u00FA]+/g,
'',
); // Removes all chars that aren't words, -, ´ or some latin characters (À Á Â Ã Ç É Ê Í Ó Ô Õ Ú à á â ã ç é ê í ó ô õ ú)
}

View file

@ -0,0 +1,5 @@
function isExternalUrl(url) {
return new RegExp('^((https?:)?//)', 'i').test(url);
}
module.exports = { isExternalUrl };

View file

@ -26,9 +26,9 @@
items:
- label: "Roadmap"
link: "/product/roadmap/"
- label: "GitHub"
link: "https://github.com/golangci/golangci-lint"
- label: "Trusted By"
link: "/product/trusted-by/"
- label: "Comparison"
link: "/product/comparison/"
- label: "GitHub"
link: "https://github.com/golangci/golangci-lint"

6
docs/src/config/site.js Normal file
View file

@ -0,0 +1,6 @@
module.exports = {
configPath: `src/config`,
docsPath: `src/docs`,
githubUrl: `https://github.com/golangci/golangci-lint`,
baseDir: `docs`,
};