Skip to content

Commit 180825c

Browse files
committed
chore: initial commit + syringe animation
0 parents  commit 180825c

File tree

11 files changed

+3467
-0
lines changed

11 files changed

+3467
-0
lines changed

.babelrc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"presets": ["next/babel"],
3+
"plugins": [["styled-components", { "ssr": true }]]
4+
}

.eslintrc.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
module.exports = {
2+
root: true, // Make sure eslint picks up the config at the root of the directory
3+
parserOptions: {
4+
ecmaVersion: 2020, // Use the latest ecmascript standard
5+
sourceType: "module", // Allows using import/export statements
6+
ecmaFeatures: {
7+
jsx: true // Enable JSX since we're using React
8+
}
9+
},
10+
settings: {
11+
react: {
12+
version: "detect" // Automatically detect the react version
13+
}
14+
},
15+
env: {
16+
browser: true, // Enables browser globals like window and document
17+
amd: true, // Enables require() and define() as global variables as per the amd spec.
18+
node: true // Enables Node.js global variables and Node.js scoping.
19+
},
20+
extends: [
21+
"eslint:recommended",
22+
"plugin:react/recommended",
23+
"plugin:jsx-a11y/recommended",
24+
"plugin:prettier/recommended" // Make this the last element so prettier config overrides other formatting rules
25+
],
26+
rules: {
27+
"prettier/prettier": ["error", { endOfLine: "auto" }, { usePrettierrc: true }], // Use our .prettierrc file as source
28+
"react/react-in-jsx-scope": "off"
29+
}
30+
};

.gitignore

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# next.js
12+
/.next/
13+
/out/
14+
15+
# production
16+
/build
17+
18+
# misc
19+
.DS_Store
20+
*.pem
21+
22+
# debug
23+
npm-debug.log*
24+
yarn-debug.log*
25+
yarn-error.log*
26+
27+
# local env files
28+
.env.local
29+
.env.development.local
30+
.env.test.local
31+
.env.production.local
32+
33+
# vercel
34+
.vercel

.prettierrc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"semi": true,
3+
"tabWidth": 2,
4+
"printWidth": 100,
5+
"singleQuote": false,
6+
"trailingComma": "none",
7+
"jsxBracketSameLine": true,
8+
"endOfLine":"auto"
9+
}

README.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Example app with styled-components
2+
3+
This example features how you use a different styling solution than [styled-jsx](https://github.com/zeit/styled-jsx) that also supports universal styles. That means we can serve the required styles for the first render within the HTML and then load the rest in the client. In this case we are using [styled-components](https://github.com/styled-components/styled-components).
4+
5+
For this purpose we are extending the `<Document />` and injecting the server side rendered styles into the `<head>`, and also adding the `babel-plugin-styled-components` (which is required for server side rendering). Additionally we set up a global [theme](https://www.styled-components.com/docs/advanced#theming) for styled-components using NextJS custom [`<App>`](https://nextjs.org/docs/advanced-features/custom-app) component.
6+
7+
## Deploy your own
8+
9+
Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example):
10+
11+
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-styled-components&project-name=with-styled-components&repository-name=with-styled-components)
12+
13+
## How to use
14+
15+
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example:
16+
17+
```bash
18+
npx create-next-app --example with-styled-components with-styled-components-app
19+
# or
20+
yarn create next-app --example with-styled-components with-styled-components-app
21+
```
22+
23+
Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).
24+
25+
### Try it on CodeSandbox
26+
27+
[Open this example on CodeSandbox](https://codesandbox.io/s/github/vercel/next.js/tree/canary/examples/with-styled-components)
28+
29+
### Notes
30+
31+
When wrapping a [Link](https://nextjs.org/docs/api-reference/next/link) from `next/link` within a styled-component, the [as](https://styled-components.com/docs/api#as-polymorphic-prop) prop provided by `styled` will collide with the Link's `as` prop and cause styled-components to throw an `Invalid tag` error. To avoid this, you can either use the recommended [forwardedAs](https://styled-components.com/docs/api#forwardedas-prop) prop from styled-components or use a different named prop to pass to a `styled` Link.
32+
33+
<details>
34+
<summary>Click to expand workaround example</summary>
35+
<br />
36+
37+
**components/StyledLink.js**
38+
39+
```javascript
40+
import Link from 'next/link'
41+
import styled from 'styled-components'
42+
43+
const StyledLink = ({ as, children, className, href }) => (
44+
<Link href={href} as={as} passHref>
45+
<a className={className}>{children}</a>
46+
</Link>
47+
)
48+
49+
export default styled(StyledLink)`
50+
color: #0075e0;
51+
text-decoration: none;
52+
transition: all 0.2s ease-in-out;
53+
54+
&:hover {
55+
color: #40a9ff;
56+
}
57+
58+
&:focus {
59+
color: #40a9ff;
60+
outline: none;
61+
border: 0;
62+
}
63+
`
64+
```
65+
66+
**pages/index.js**
67+
68+
```javascript
69+
import StyledLink from '../components/StyledLink'
70+
71+
export default () => (
72+
<StyledLink href="/post/[pid]" forwardedAs="/post/abc">
73+
First post
74+
</StyledLink>
75+
)
76+
```
77+
78+
</details>

components/charts/syringe.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import * as React from "react";
2+
import styled from "styled-components";
3+
import PropTypes from "prop-types";
4+
5+
const BorderPath = styled.path`
6+
stroke: #5a60ab;
7+
stroke-miterlimit: 10;
8+
stroke-width: 2px;
9+
`;
10+
11+
const SyringeColor = styled(BorderPath)`
12+
fill: ${(props) => props.color};
13+
`;
14+
15+
const SyringeTop = styled(BorderPath)`
16+
fill: #fff;
17+
`;
18+
19+
const BlueFillPath = styled.path`
20+
fill: #5a60ab;
21+
`;
22+
23+
const MovingPath = styled.path`
24+
fill: #9cb2f8;
25+
stroke: #5a60ab;
26+
strokemiterlimit: 10;
27+
strokewidth: 2px;
28+
transition: all linear 1s;
29+
`;
30+
31+
const Text = styled.text`
32+
fill: #5a60ab;
33+
font-size: 40px;
34+
font-family: Roboto-Regular, Roboto;
35+
`;
36+
37+
export const Syringe = ({ percentage, length = 1000, country, index = 0, color = "#dce4fc" }) => {
38+
const calculatedLength = percentage * length;
39+
const path = `M1035.7 20.24h-${calculatedLength}v60h${calculatedLength}v-60z`;
40+
41+
return (
42+
<>
43+
<g transform={`translate(0, ${200 + index * -100})`}>
44+
<SyringeColor
45+
transform="rotate(90 536.2 49.59)"
46+
color={color}
47+
d="M506.2-449.91h60v999h-60z"
48+
/>
49+
<BorderPath d="M1235.7 50.24H35.7" />
50+
<BlueFillPath transform="rotate(180 277.25 50.235)" d="M4.25 46.24h546v8h-546z" />
51+
<MovingPath d={path} />
52+
<BorderPath d="M37 10.24h4v80h-4zM1 25.24h4v50H1z" />
53+
<SyringeTop d="M1036.04 32.98h10V67.5h-10zM1046.54 45.94h7v12.55h-7z" />
54+
<BlueFillPath d="M1025.5 19.59h2v17.42h-2zM1015.5 19.59h2V30.5h-2zM1005.5 19.59h2v17.42h-2zM995.5 19.59h2V30.5h-2zM985.5 19.59h2v17.42h-2zM975.5 19.59h2V30.5h-2zM965.5 19.59h2v17.42h-2zM955.5 19.59h2V30.5h-2zM945.5 19.59h2v17.42h-2zM935.5 19.59h2V30.5h-2zM925.5 19.59h2v17.42h-2zM915.5 19.59h2V30.5h-2zM905.5 19.59h2v17.42h-2zM895.5 19.59h2V30.5h-2zM885.5 19.59h2v17.42h-2zM875.5 19.59h2V30.5h-2zM865.5 19.59h2v17.42h-2zM855.5 19.59h2V30.5h-2zM845.5 19.59h2v17.42h-2zM835.5 19.59h2V30.5h-2zM825.5 19.59h2v17.42h-2zM815.5 19.59h2V30.5h-2zM805.5 19.59h2v17.42h-2zM795.5 19.59h2V30.5h-2zM785.5 19.59h2v17.42h-2zM775.5 19.59h2V30.5h-2zM765.5 19.59h2v17.42h-2zM755.5 19.59h2V30.5h-2zM745.5 19.59h2v17.42h-2zM735.5 19.59h2V30.5h-2zM725.5 19.59h2v17.42h-2zM715.5 19.59h2V30.5h-2zM705.5 19.59h2v17.42h-2zM695.5 19.59h2V30.5h-2zM685.5 19.59h2v17.42h-2zM675.5 19.59h2V30.5h-2zM665.5 19.59h2v17.42h-2zM655.5 19.59h2V30.5h-2zM645.5 19.59h2v17.42h-2zM635.5 19.59h2V30.5h-2zM625.5 19.59h2v17.42h-2zM615.5 19.59h2V30.5h-2zM605.5 19.59h2v17.42h-2zM595.5 19.59h2V30.5h-2zM585.5 19.59h2v17.42h-2zM575.5 19.59h2V30.5h-2zM565.5 19.59h2v17.42h-2zM555.5 19.59h2V30.5h-2zM545.5 19.59h2v17.42h-2zM535.5 19.59h2V30.5h-2zM525.5 19.59h2v17.42h-2zM515.5 19.59h2V30.5h-2zM505.5 19.59h2v17.42h-2zM495.5 19.59h2V30.5h-2zM485.5 19.59h2v17.42h-2zM475.5 19.59h2V30.5h-2zM465.5 19.59h2v17.42h-2zM455.5 19.59h2V30.5h-2zM445.5 19.59h2v17.42h-2zM435.5 19.59h2V30.5h-2zM425.5 19.59h2v17.42h-2zM415.5 19.59h2V30.5h-2zM405.5 19.59h2v17.42h-2zM395.5 19.59h2V30.5h-2zM385.5 19.59h2v17.42h-2zM375.5 19.59h2V30.5h-2zM365.5 19.59h2v17.42h-2zM355.5 19.59h2V30.5h-2zM345.5 19.59h2v17.42h-2zM335.5 19.59h2V30.5h-2zM325.5 19.59h2v17.42h-2zM315.5 19.59h2V30.5h-2zM305.5 19.59h2v17.42h-2zM295.5 19.59h2V30.5h-2zM285.5 19.59h2v17.42h-2zM275.5 19.59h2V30.5h-2zM265.5 19.59h2v17.42h-2zM255.5 19.59h2V30.5h-2zM245.5 19.59h2v17.42h-2zM235.5 19.59h2V30.5h-2zM225.5 19.59h2v17.42h-2zM215.5 19.59h2V30.5h-2zM205.5 19.59h2v17.42h-2zM195.5 19.59h2V30.5h-2zM185.5 19.59h2v17.42h-2zM175.5 19.59h2V30.5h-2zM165.5 19.59h2v17.42h-2zM155.5 19.59h2V30.5h-2zM145.5 19.59h2v17.42h-2zM135.5 19.59h2V30.5h-2zM125.5 19.59h2v17.42h-2zM115.5 19.59h2V30.5h-2zM105.5 19.59h2v17.42h-2zM95.5 19.59h2V30.5h-2zM85.5 19.59h2v17.42h-2zM75.5 19.59h2V30.5h-2zM65.5 19.59h2v17.42h-2z" />
55+
<Text className="cls-7" transform="translate(1084.62 37.22)">
56+
{country}
57+
</Text>
58+
</g>
59+
</>
60+
);
61+
};
62+
63+
Syringe.propTypes = {
64+
percentage: PropTypes.number,
65+
length: PropTypes.number,
66+
country: PropTypes.string,
67+
index: PropTypes.number,
68+
color: PropTypes.string
69+
};

package.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "with-styled-components",
3+
"version": "1.0.0",
4+
"scripts": {
5+
"dev": "next",
6+
"build": "next build",
7+
"start": "next start"
8+
},
9+
"dependencies": {
10+
"next": "latest",
11+
"prop-types": "^15.7.2",
12+
"react": "^16.8.0",
13+
"react-dom": "^16.8.0",
14+
"react-is": "^16.8.0",
15+
"styled-components": "^5.0.0"
16+
},
17+
"devDependencies": {
18+
"babel-plugin-styled-components": "^1.8.0",
19+
"eslint": "^7.20.0",
20+
"eslint-config-prettier": "^8.1.0",
21+
"eslint-plugin-jsx-a11y": "^6.4.1",
22+
"eslint-plugin-prettier": "^3.3.1",
23+
"eslint-plugin-react": "^7.22.0",
24+
"eslint-plugin-react-hooks": "^4.2.0",
25+
"prettier": "^2.2.1"
26+
},
27+
"license": "MIT"
28+
}

pages/_app.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { createGlobalStyle, ThemeProvider } from "styled-components";
2+
3+
const GlobalStyle = createGlobalStyle`
4+
body {
5+
margin: 0;
6+
padding: 0;
7+
box-sizing: border-box;
8+
}
9+
`;
10+
11+
const theme = {
12+
colors: {
13+
primary: "#0070f3"
14+
}
15+
};
16+
17+
// eslint-disable-next-line react/prop-types
18+
export default function App({ Component, pageProps }) {
19+
return (
20+
<>
21+
<GlobalStyle />
22+
<ThemeProvider theme={theme}>
23+
<Component {...pageProps} />
24+
</ThemeProvider>
25+
</>
26+
);
27+
}

pages/_document.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import Document from "next/document";
2+
import { ServerStyleSheet } from "styled-components";
3+
4+
export default class MyDocument extends Document {
5+
static async getInitialProps(ctx) {
6+
const sheet = new ServerStyleSheet();
7+
const originalRenderPage = ctx.renderPage;
8+
9+
try {
10+
ctx.renderPage = () =>
11+
originalRenderPage({
12+
enhanceApp: (App) => (props) => sheet.collectStyles(<App {...props} />)
13+
});
14+
15+
const initialProps = await Document.getInitialProps(ctx);
16+
return {
17+
...initialProps,
18+
styles: (
19+
<>
20+
{initialProps.styles}
21+
{sheet.getStyleElement()}
22+
</>
23+
)
24+
};
25+
} finally {
26+
sheet.seal();
27+
}
28+
}
29+
}

pages/index.js

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import * as React from "react";
2+
import styled from "styled-components";
3+
import { Syringe } from "../components/charts/syringe";
4+
5+
const Title = styled.h1`
6+
font-size: 50px;
7+
color: ${({ theme }) => theme.colors.primary};
8+
`;
9+
10+
export const Index = () => {
11+
const [israel, setIsrael] = React.useState(1);
12+
const [unitedKingdom, setUnitedKingdom] = React.useState(1);
13+
const [chile, setChile] = React.useState(1);
14+
const [US, setUS] = React.useState(1);
15+
const [turkey, setTurkey] = React.useState(1);
16+
const [EU, setEU] = React.useState(1);
17+
const [brazil, setBrazil] = React.useState(1);
18+
19+
React.useEffect(() => {
20+
setTimeout(() => {
21+
setIsrael(israel - Math.random() * 0.2);
22+
}, 2000);
23+
}, [israel]);
24+
25+
React.useEffect(() => {
26+
setTimeout(() => {
27+
setUnitedKingdom(unitedKingdom - Math.random() * 0.2);
28+
}, 2000);
29+
}, [unitedKingdom]);
30+
31+
React.useEffect(() => {
32+
setTimeout(() => {
33+
setChile(chile - Math.random() * 0.2);
34+
}, 2000);
35+
}, [chile]);
36+
37+
React.useEffect(() => {
38+
setTimeout(() => {
39+
setUS(US - Math.random() * 0.2);
40+
}, 2000);
41+
}, [US]);
42+
React.useEffect(() => {
43+
setTimeout(() => {
44+
setTurkey(turkey - Math.random() * 0.2);
45+
}, 2000);
46+
}, [turkey]);
47+
React.useEffect(() => {
48+
setTimeout(() => {
49+
setEU(EU - Math.random() * 0.2);
50+
}, 2000);
51+
}, [EU]);
52+
React.useEffect(() => {
53+
setTimeout(() => {
54+
setBrazil(brazil - Math.random() * 0.2);
55+
}, 2000);
56+
}, [brazil]);
57+
58+
return (
59+
<div style={{ margin: "20px" }}>
60+
<Title>My page</Title>;
61+
<svg width="440" height="440" viewBox="0 0 1235.7 91.24">
62+
<Syringe index={6} color="#f79fad" country="Israel" percentage={israel} />
63+
<Syringe index={5} color="#f7de9f" country="United Kingdom" percentage={unitedKingdom} />
64+
<Syringe index={4} country="Chile" percentage={chile} />
65+
<Syringe index={3} color="#9ff4e4" country="United States" percentage={US} />
66+
<Syringe index={2} color="#f79fad" country="Turkey" percentage={turkey} />
67+
<Syringe index={1} color="#f7de9f" country="European Union" percentage={EU} />
68+
<Syringe index={0} country="Brazil" percentage={brazil} />
69+
</svg>
70+
</div>
71+
);
72+
};
73+
74+
export default Index;

0 commit comments

Comments
 (0)