This commit is contained in:
Sergey Yarkov 2020-03-16 21:17:35 +03:00
commit ca9c6e2aec
39 changed files with 22683 additions and 0 deletions

9
.dockerignore Normal file
View File

@ -0,0 +1,9 @@
/node_modules
/.next/
/build
npm-debug.log
yarn-debug.log*
yarn-error.log*

217
.eslintrc.json Normal file
View File

@ -0,0 +1,217 @@
{
"parserOptions": {
"ecmaVersion": 2020,
"ecmaFeatures": {
"jsx": true
},
"sourceType": "module"
},
"env": {
"es6": true,
"node": true
},
"plugins": [
"import",
"node",
"promise",
"standard",
"jsx-a11y"
],
"globals": {
"document": "readonly",
"navigator": "readonly",
"window": "readonly"
},
"rules": {
"accessor-pairs": "error",
"array-bracket-spacing": ["error", "never"],
"arrow-spacing": ["error", { "before": true, "after": true }],
"block-spacing": ["error", "always"],
"brace-style": ["error", "1tbs", { "allowSingleLine": true }],
"camelcase": ["error", { "properties": "never" }],
"comma-dangle": ["error", {
"arrays": "never",
"objects": "never",
"imports": "never",
"exports": "never",
"functions": "never"
}],
"comma-spacing": ["error", { "before": false, "after": true }],
"comma-style": ["error", "last"],
"computed-property-spacing": ["error", "never"],
"constructor-super": "error",
"curly": ["error", "multi-line"],
"dot-location": ["error", "property"],
"dot-notation": ["error", { "allowKeywords": true }],
"eol-last": "error",
"eqeqeq": ["error", "always", { "null": "ignore" }],
"func-call-spacing": ["error", "never"],
"generator-star-spacing": ["error", { "before": true, "after": true }],
"handle-callback-err": ["error", "^(err|error)$" ],
"indent": ["error", 2, {
"SwitchCase": 1,
"VariableDeclarator": 1,
"outerIIFEBody": 1,
"MemberExpression": 1,
"FunctionDeclaration": { "parameters": 1, "body": 1 },
"FunctionExpression": { "parameters": 1, "body": 1 },
"CallExpression": { "arguments": 1 },
"ArrayExpression": 1,
"ObjectExpression": 1,
"ImportDeclaration": 1,
"flatTernaryExpressions": false,
"ignoreComments": false,
"ignoredNodes": ["TemplateLiteral *"]
}],
"key-spacing": ["error", { "beforeColon": false, "afterColon": true }],
"keyword-spacing": ["error", { "before": true, "after": true }],
"lines-between-class-members": ["error", "always", { "exceptAfterSingleLine": true }],
"new-cap": ["error", { "newIsCap": true, "capIsNew": false, "properties": true }],
"new-parens": "error",
"no-array-constructor": "error",
"no-async-promise-executor": "error",
"no-caller": "error",
"no-case-declarations": "error",
"no-class-assign": "error",
"no-compare-neg-zero": "error",
"no-cond-assign": "error",
"no-const-assign": "error",
"no-constant-condition": ["error", { "checkLoops": false }],
"no-control-regex": "error",
"no-debugger": "error",
"no-delete-var": "error",
"no-dupe-args": "error",
"no-dupe-class-members": "error",
"no-dupe-keys": "error",
"no-duplicate-case": "error",
"no-empty-character-class": "error",
"no-empty-pattern": "error",
"no-eval": "error",
"no-ex-assign": "error",
"no-extend-native": "error",
"no-extra-bind": "error",
"no-extra-boolean-cast": "error",
"no-extra-parens": ["error", "functions"],
"no-fallthrough": "error",
"no-floating-decimal": "error",
"no-func-assign": "error",
"no-global-assign": "error",
"no-implied-eval": "error",
"no-inner-declarations": ["error", "functions"],
"no-invalid-regexp": "error",
"no-irregular-whitespace": "error",
"no-iterator": "error",
"no-labels": ["error", { "allowLoop": false, "allowSwitch": false }],
"no-lone-blocks": "error",
"no-misleading-character-class": "error",
"no-prototype-builtins": "error",
"no-useless-catch": "error",
"no-mixed-operators": ["error", {
"groups": [
["==", "!=", "===", "!==", ">", ">=", "<", "<="],
["&&", "||"],
["in", "instanceof"]
],
"allowSamePrecedence": true
}],
"no-mixed-spaces-and-tabs": "error",
"no-multi-spaces": "error",
"no-multi-str": "error",
"no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 0 }],
"no-negated-in-lhs": "error",
"no-new": "error",
"no-new-func": "error",
"no-new-object": "error",
"no-new-require": "error",
"no-new-symbol": "error",
"no-new-wrappers": "error",
"no-obj-calls": "error",
"no-octal": "error",
"no-octal-escape": "error",
"no-path-concat": "error",
"no-proto": "error",
"no-redeclare": ["error", { "builtinGlobals": false }],
"no-regex-spaces": "error",
"no-return-assign": ["error", "except-parens"],
"no-return-await": "error",
"no-self-assign": ["error", { "props": true }],
"no-self-compare": "error",
"no-sequences": "error",
"no-shadow-restricted-names": "error",
"no-sparse-arrays": "error",
"no-tabs": "error",
"no-template-curly-in-string": "error",
"no-this-before-super": "error",
"no-throw-literal": "error",
"no-trailing-spaces": "error",
"no-undef": "error",
"no-undef-init": "error",
"no-unexpected-multiline": "error",
"no-unmodified-loop-condition": "error",
"no-unneeded-ternary": ["error", { "defaultAssignment": false }],
"no-unreachable": "error",
"no-unsafe-finally": "error",
"no-unsafe-negation": "error",
"no-unused-expressions": ["error", { "allowShortCircuit": true, "allowTernary": true, "allowTaggedTemplates": true }],
"no-unused-vars": ["off", { "vars": "all", "args": "none", "ignoreRestSiblings": true }],
"no-use-before-define": ["error", { "functions": false, "classes": false, "variables": false }],
"no-useless-call": "error",
"no-useless-computed-key": "error",
"no-useless-constructor": "error",
"no-useless-escape": "error",
"no-useless-rename": "error",
"no-useless-return": "error",
"no-void": "error",
"no-whitespace-before-property": "error",
"no-with": "error",
"object-curly-newline": ["error", { "multiline": true, "consistent": true }],
"object-curly-spacing": ["error", "always"],
"object-property-newline": ["error", { "allowMultiplePropertiesPerLine": true }],
"one-var": ["error", { "initialized": "never" }],
"operator-linebreak": ["error", "after", { "overrides": { "?": "before", ":": "before", "|>": "before" } }],
"padded-blocks": ["error", { "blocks": "never", "switches": "never", "classes": "never" }],
"prefer-const": ["error", {"destructuring": "all"}],
"prefer-promise-reject-errors": "error",
"quote-props": ["error", "as-needed"],
"quotes": ["error", "single", { "avoidEscape": true, "allowTemplateLiterals": false }],
"rest-spread-spacing": ["error", "never"],
"semi": ["error", "never"],
"semi-spacing": ["error", { "before": false, "after": true }],
"space-before-blocks": ["error", "always"],
"space-before-function-paren": ["error", "always"],
"space-in-parens": ["error", "never"],
"space-infix-ops": "error",
"space-unary-ops": ["error", { "words": true, "nonwords": false }],
"spaced-comment": ["error", "always", {
"line": { "markers": ["*package", "!", "/", ",", "="] },
"block": { "balanced": true, "markers": ["*package", "!", ",", ":", "::", "flow-include"], "exceptions": ["*"] }
}],
"symbol-description": "error",
"template-curly-spacing": ["error", "never"],
"template-tag-spacing": ["error", "never"],
"unicode-bom": ["error", "never"],
"use-isnan": "error",
"valid-typeof": ["error", { "requireStringLiterals": true }],
"wrap-iife": ["error", "any", { "functionPrototypeMethods": true }],
"yield-star-spacing": ["error", "both"],
"yoda": ["error", "never"],
"import/export": "error",
"import/first": "error",
"import/no-absolute-path": ["error", { "esmodule": true, "commonjs": true, "amd": false }],
"import/no-duplicates": "error",
"import/no-named-default": "error",
"import/no-webpack-loader-syntax": "error",
"node/no-deprecated-api": "error",
"node/process-exit-as-throw": "error",
"promise/param-names": "error",
"standard/no-callback-literal": "error"
}
}

25
.gitignore vendored Normal file
View File

@ -0,0 +1,25 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
.env*
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

13
Dockerfile Normal file
View File

@ -0,0 +1,13 @@
FROM node:10
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
CMD ["npm", "start"]

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Sergey Yarkov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

75
README.md Normal file
View File

@ -0,0 +1,75 @@
### This is a next-apollo-graphql setup to start develop your web site. This setup uses server side rendering.
## 🚀 Getting Started
To start the development server, you need to run the following commands below.
```bash
npm install
npm run dev
```
Open http://localhost:3000 with your browser to see the result.
Our application runs on port `3000`, and GraphQL server also runs on `localhost:3000/api/graphql`.
## ⚡ Using Query
You can easily use `Query` component to send queries to the GraphQL server. Just pass your query to the `Query` component.
```jsx
<Query query={ARTICLES_QUERY}>
{({ data: { articles } }) => {
return <Articles articles={articles} />;
}}
</Query>
```
Use the `withData` HOC to wrap your pages.
```jsx
// ./frontend/pages/articles.js
import Layout from '../components/Layout/Layout'
import SEO from '../components/SEO/SEO'
import Query from '../components/Query/query'
import ARTICLES_QUERY from '../apollo/queries/articles/articles';
import withData from '../lib/apollo';
const Articles = () => {
return (
<>
<SEO pageTitle='Articles page' />
<Layout>
<h1>Articles page</h1>
<div>
<Query query={ARTICLES_QUERY}>
{({ data: { articles } }) => {
return articles.map(art => {
return (
<div key={art.id}>
<p>
title: {art.title} <br />
id: {art.id}
</p>
</div>
)
})
}}
</Query>
</div>
</Layout>
</>
)
}
export default withData(Articles)
```
## License:
[MIT](https://github.com/sergeyyarkov/next-apollo-graphql-setup/blob/master/LICENSE)

View File

@ -0,0 +1,12 @@
import gql from 'graphql-tag'
const ARTICLES_QUERY = gql`
query Articles {
articles {
id
title
}
}
`
export default ARTICLES_QUERY

10
assets/css/global.scss Normal file
View File

@ -0,0 +1,10 @@
/*
Put some global styles in this file.
*/
ul {
padding: 0;
& li {
list-style: none;
}
}

View File

@ -0,0 +1,26 @@
import Link from 'next/link'
import classes from './Header.module.scss'
const Header = () => (
<header className={classes.Header}>
<ul>
<li>
<Link href='/'>
<a>Index</a>
</Link>
</li>
<li>
<Link href='/about'>
<a>About</a>
</Link>
</li>
<li>
<Link href='/articles'>
<a>Articles</a>
</Link>
</li>
</ul>
</header>
)
export default Header

View File

@ -0,0 +1,9 @@
.Header {
& ul {
display: flex;
& li {
margin-left: 10px;
}
}
}

View File

@ -0,0 +1,14 @@
import Header from '../Header/Header'
const Layout = props => {
return (
<>
<Header />
<main>
{props.children}
</main>
</>
)
}
export default Layout

19
components/Query/query.js Normal file
View File

@ -0,0 +1,19 @@
import { useQuery } from '@apollo/react-hooks'
const Query = ({ children, query, id }) => {
const { data, loading, error } = useQuery(query, {
variables: { id }
})
if (loading) {
return (
<div className="uk-container">
<p>loading...</p>
</div>
)
}
if (error) return <p>Error: {JSON.stringify(error)}</p>
return children({ data })
}
export default Query

21
components/SEO/SEO.js Normal file
View File

@ -0,0 +1,21 @@
import Head from 'next/head'
/*
Put some SEO tags in Head component.
*/
const SEO = props => {
const { pageTitle } = props
return (
<Head>
<title>{pageTitle}</title>
<meta
name="description"
content="-"
/>
</Head>
)
}
export default SEO

14
docker-compose.yml Normal file
View File

@ -0,0 +1,14 @@
version: '3'
services:
app:
container_name: apollo-next-graphql
restart: always
build: .
ports:
- '3000'
webserver:
container_name: webserver
restart: unless-stopped
build: nginx
ports:
- '80:80'

11
graphql/data/index.js Normal file
View File

@ -0,0 +1,11 @@
const articles = [
{ id: 1, title: 'Article 1' },
{ id: 2, title: 'Article 2' },
{ id: 3, title: 'Article 3' },
{ id: 4, title: 'Article 4' },
{ id: 5, title: 'Article 5' }
]
module.exports = {
articles
}

8
graphql/index.js Normal file
View File

@ -0,0 +1,8 @@
import { makeExecutableSchema } from 'graphql-tools'
import { typeDefs } from './typeDefs'
import { resolvers } from './resolvers'
export const schema = makeExecutableSchema({
typeDefs,
resolvers
})

11
graphql/models/Article.js Normal file
View File

@ -0,0 +1,11 @@
const { articles } = require('../data')
class Article {
static all () {
return articles
}
}
module.exports = {
Article
}

5
graphql/models/index.js Normal file
View File

@ -0,0 +1,5 @@
const { Article } = require('./Article')
module.exports = {
Article
}

View File

@ -0,0 +1,11 @@
const { Article } = require('../models')
const articlesResolvers = {
Query: {
articles: () => Article.all()
}
}
module.exports = {
articlesResolvers
}

View File

@ -0,0 +1,7 @@
const { articlesResolvers } = require('./articlesResolvers')
const resolvers = [articlesResolvers]
module.exports = {
resolvers
}

View File

@ -0,0 +1,8 @@
const { query } = require('./query')
const { articleType } = require('./types')
const typeDefs = [query, articleType]
module.exports = {
typeDefs
}

11
graphql/typeDefs/query.js Normal file
View File

@ -0,0 +1,11 @@
const { gql } = require('apollo-boost')
const query = gql`
type Query {
articles: [Article]
}
`
module.exports = {
query
}

View File

@ -0,0 +1,12 @@
const { gql } = require('apollo-boost')
const articleType = gql`
type Article {
id: ID
title: String
}
`
module.exports = {
articleType
}

View File

@ -0,0 +1,5 @@
const { articleType } = require('./articleType')
module.exports = {
articleType
}

148
lib/apollo.js Normal file
View File

@ -0,0 +1,148 @@
import React from 'react'
import Head from 'next/head'
import { ApolloProvider } from '@apollo/react-hooks'
import { ApolloClient } from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
let globalApolloClient = null
/**
* Creates and provides the apolloContext
* to a next.js PageTree. Use it by wrapping
* your PageComponent via HOC pattern.
* @param {Function|Class} PageComponent
* @param {Object} [config]
* @param {Boolean} [config.ssr=true]
*/
export function withApollo (PageComponent, { ssr = true } = {}) {
const WithApollo = ({ apolloClient, apolloState, ...pageProps }) => {
const client = apolloClient || initApolloClient(apolloState)
return (
<ApolloProvider client={client}>
<PageComponent {...pageProps} />
</ApolloProvider>
)
}
// Set the correct displayName in development
if (process.env.NODE_ENV !== 'production') {
const displayName =
PageComponent.displayName || PageComponent.name || 'Component'
if (displayName === 'App') {
console.warn('This withApollo HOC only works with PageComponents.')
}
WithApollo.displayName = `withApollo(${displayName})`
}
if (ssr || PageComponent.getInitialProps) {
WithApollo.getInitialProps = async ctx => {
const { AppTree } = ctx
// Initialize ApolloClient, add it to the ctx object so
// we can use it in `PageComponent.getInitialProp`.
const apolloClient = (ctx.apolloClient = initApolloClient())
// Run wrapped getInitialProps methods
let pageProps = {}
if (PageComponent.getInitialProps) {
pageProps = await PageComponent.getInitialProps(ctx)
}
// Only on the server:
if (typeof window === 'undefined') {
// When redirecting, the response is finished.
// No point in continuing to render
if (ctx.res && ctx.res.finished) {
return pageProps
}
// Only if ssr is enabled
if (ssr) {
try {
// Run all GraphQL queries
const { getDataFromTree } = await import('@apollo/react-ssr')
await getDataFromTree(
<AppTree
pageProps={{
...pageProps,
apolloClient
}}
/>
)
} catch (error) {
// Prevent Apollo Client GraphQL errors from crashing SSR.
// Handle them in components via the data.error prop:
// https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-query-data-error
console.error('Error while running `getDataFromTree`', error)
}
// getDataFromTree does not call componentWillUnmount
// head side effect therefore need to be cleared manually
Head.rewind()
}
}
// Extract query data from the Apollo store
const apolloState = apolloClient.cache.extract()
return {
...pageProps,
apolloState
}
}
}
return WithApollo
}
/**
* Always creates a new apollo client on the server
* Creates or reuses apollo client in the browser.
* @param {Object} initialState
*/
function initApolloClient (initialState) {
// Make sure to create a new client for every server-side request so that data
// isn't shared between connections (which would be bad)
if (typeof window === 'undefined') {
return createApolloClient(initialState)
}
// Reuse client on the client-side
if (!globalApolloClient) {
globalApolloClient = createApolloClient(initialState)
}
return globalApolloClient
}
/**
* Creates and configures the ApolloClient
* @param {Object} [initialState={}]
*/
function createApolloClient (initialState = {}) {
const ssrMode = typeof window === 'undefined'
const cache = new InMemoryCache().restore(initialState)
// Check out https://github.com/zeit/next.js/pull/4611 if you want to use the AWSAppSyncClient
return new ApolloClient({
ssrMode,
link: createIsomorphLink(),
cache
})
}
function createIsomorphLink () {
if (typeof window === 'undefined') {
const { SchemaLink } = require('apollo-link-schema')
const { schema } = require('../graphql')
return new SchemaLink({ schema })
} else {
const { HttpLink } = require('apollo-link-http')
return new HttpLink({
uri: '/api/graphql',
credentials: 'same-origin'
})
}
}

13
next.config.js Normal file
View File

@ -0,0 +1,13 @@
const withSass = require('@zeit/next-sass')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
module.exports = withSass({
cssModules: true,
webpack: (config, { dev, isServer }) => {
if (isServer) return config
config.optimization.minimizer.push(new OptimizeCSSAssetsPlugin({}))
return config
}
})

5
nginx/Dockerfile Normal file
View File

@ -0,0 +1,5 @@
FROM nginx
RUN rm /etc/nginx/conf.d/default.conf
COPY default.conf /etc/nginx/conf.d/

20
nginx/default.conf Normal file
View File

@ -0,0 +1,20 @@
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://apollo-next-graphql:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

15632
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

36
package.json Normal file
View File

@ -0,0 +1,36 @@
{
"name": "apollo-next-graphql-setup",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"@apollo/react-hooks": "^3.1.3",
"@apollo/react-ssr": "^3.1.3",
"@zeit/next-sass": "^1.0.1",
"apollo-boost": "^0.4.7",
"apollo-link-schema": "^1.2.4",
"apollo-server-micro": "^2.10.1",
"graphql-tag": "^2.10.3",
"graphql-tools": "^4.0.7",
"next": "9.2.2",
"node-sass": "^4.13.1",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"react": "16.13.0",
"react-dom": "16.13.0"
},
"devDependencies": {
"eslint": "^6.8.0",
"eslint-config-node": "^4.0.0",
"eslint-config-standard-jsx": "^8.1.0",
"eslint-plugin-import": "^2.20.1",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-node": "^11.0.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-react": "^7.18.3",
"eslint-plugin-standard": "^4.0.1"
}
}

5
pages/_app.js Normal file
View File

@ -0,0 +1,5 @@
import '../assets/css/global.scss'
export default function Application ({ Component, pageProps }) {
return <Component {...pageProps} />
}

17
pages/_document.js Normal file
View File

@ -0,0 +1,17 @@
import Document, { Html, Head, Main, NextScript } from 'next/document'
class CustomDocument extends Document {
render () {
return (
<Html lang='en'>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default CustomDocument

13
pages/about.js Normal file
View File

@ -0,0 +1,13 @@
import Layout from '../components/Layout/Layout'
import SEO from '../components/SEO/SEO'
const About = () => (
<>
<SEO pageTitle='About page' />
<Layout>
<h1>About page</h1>
</Layout>
</>
)
export default About

7
pages/api/graphql.js Normal file
View File

@ -0,0 +1,7 @@
import { ApolloServer } from 'apollo-server-micro'
import { schema } from '../../graphql'
const apolloServer = new ApolloServer({ schema })
export const config = { api: { bodyParser: false } }
export default apolloServer.createHandler({ path: '/api/graphql' })

34
pages/articles.js Normal file
View File

@ -0,0 +1,34 @@
import Layout from '../components/Layout/Layout'
import SEO from '../components/SEO/SEO'
import Query from '../components/Query/query'
import ARTICLES_QUERY from '../apollo/queries/articles/articles'
import { withApollo } from '../lib/apollo'
const Articles = () => {
return (
<>
<SEO pageTitle='Articles page' />
<Layout>
<h1>Articles page</h1>
<div>
<Query query={ARTICLES_QUERY}>
{({ data: { articles } }) => {
return articles.map(art => {
return (
<div key={art.id}>
<p>
title: {art.title} <br />
id: {art.id}
</p>
</div>
)
})
}}
</Query>
</div>
</Layout>
</>
)
}
export default withApollo(Articles)

13
pages/index.js Normal file
View File

@ -0,0 +1,13 @@
import Layout from '../components/Layout/Layout'
import SEO from '../components/SEO/SEO'
const Index = () => (
<>
<SEO pageTitle='Index page' />
<Layout>
<h1>Index page</h1>
</Layout>
</>
)
export default Index

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

10
public/zeit.svg Normal file
View File

@ -0,0 +1,10 @@
<svg width="82" height="16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill="url(#prefix__paint0_linear)" d="M9.018 0l9.019 16H0L9.018 0z"/>
<path fill="#333" fill-rule="evenodd" d="M51.634 12.028h-6.492V2.052h6.492v1.256H46.61v3.007h4.37V7.57h-4.37v3.202h5.024v1.255zm-14.063 0h-7.235v-1.096l5.342-7.624h-5.253V2.052h7.058v1.097l-5.342 7.623h5.43v1.256zm21.88 0h6.333v-1.256h-2.423V3.308h2.423V2.052h-6.332v1.256h2.441v7.465h-2.441v1.255zm18.22 0h-1.468v-8.72h-3.36V2.052h8.225v1.256H77.67v8.72z" clip-rule="evenodd"/>
<defs>
<linearGradient id="prefix__paint0_linear" x1="28.022" x2="16.189" y1="22.991" y2="8.569" gradientUnits="userSpaceOnUse">
<stop stop-color="#fff"/>
<stop offset="1"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 794 B

6156
yarn.lock Normal file

File diff suppressed because it is too large Load Diff