`
71 | display: inline-flex;
72 | justify-content: center;
73 | align-items: center;
74 | text-align: center;
75 | font-size: 1em;
76 | line-height: 1.15;
77 | font-family: -apple-system, BlinkMacSystemFont, sans-serif;
78 | text-decoration: none;
79 | margin: 0.2em 0;
80 |
81 | ${props =>
82 | props.dark &&
83 | css`
84 | color: #fff;
85 | `}
86 | `
87 |
88 | const dict = {
89 | en: {
90 | p1: "of",
91 | p2: "view",
92 | p3: "Cleaner than",
93 | p4: "Dirtier than",
94 | p5: "of pages tested",
95 | },
96 | fr: {
97 | p1: "de",
98 | p2: "vue",
99 | p3: "Page web plus légère que",
100 | p4: "Page web plus lourde que",
101 | p5: "des pages testées",
102 | },
103 | }
104 |
105 | const WebsiteCarbonBadge = (props: WebsiteCarbonBadgeProps) => {
106 | const [data, setData] = useState({ co2: "", percentage: "" })
107 |
108 | useEffect(() => {
109 | const fetchData = async (props: WebsiteCarbonBadgeProps) => {
110 | let url = props.url ? encodeURIComponent(props.url) : ""
111 | let data = localStorage.getItem(`wcb_${url}`)
112 |
113 | if (props.co2 && props.percentage) {
114 | setData({ co2: props.co2, percentage: props.percentage })
115 | } else if (data) {
116 | let parsed = JSON.parse(data)
117 | setData({ co2: parsed.c, percentage: parsed.p })
118 | } else {
119 | if (!props.url) {
120 | throw Error("Website carbon: url is null")
121 | }
122 |
123 | try {
124 | const res = await fetch("https://api.websitecarbon.com/b?url=" + url)
125 |
126 | if (!res.ok) throw Error(JSON.stringify(await res.json()))
127 | const data = await res.json()
128 |
129 | localStorage.setItem(`wcb_${url}`, JSON.stringify(data))
130 |
131 | setData({ co2: data.c, percentage: data.p })
132 | } catch (e) {
133 | console.error(e)
134 | localStorage.removeItem(`wcb_${url}`)
135 | }
136 | }
137 | }
138 |
139 | fetchData(props).catch(console.error)
140 | }, [props])
141 |
142 | let ps = props.lang == "fr" ? dict.fr : dict.en
143 |
144 | return (
145 |
146 |
147 |
152 | {data.co2 ? data.co2 : "-"}g {ps.p1} CO2 /{ps.p2}
153 |
154 |
160 | Website Carbon
161 |
162 |
163 |
164 | {data.percentage
165 | ? parseInt(data.percentage) > 50
166 | ? `${ps.p3} ${data.percentage}% ${ps.p5}`
167 | : `${ps.p4} ${data.percentage}% ${ps.p5}`
168 | : ""}
169 |
170 |
171 | )
172 | }
173 |
174 | export default WebsiteCarbonBadge
175 |
--------------------------------------------------------------------------------
/src/components/WebsiteCarbonBadge.types.ts:
--------------------------------------------------------------------------------
1 | export interface WebsiteCarbonBadgeProps {
2 | dark?: boolean;
3 | co2?: string;
4 | percentage?: string;
5 | url?: string | undefined;
6 | lang?: string;
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/__stories__/Introduction.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta } from '@storybook/addon-docs';
2 | import Code from './assets/code-brackets.svg';
3 | import Colors from './assets/colors.svg';
4 | import Comments from './assets/comments.svg';
5 | import Direction from './assets/direction.svg';
6 | import Flow from './assets/flow.svg';
7 | import Plugin from './assets/plugin.svg';
8 | import Repo from './assets/repo.svg';
9 | import StackAlt from './assets/stackalt.svg';
10 |
11 |
12 |
13 |
116 |
117 | # Welcome to Storybook
118 |
119 | Storybook helps you build UI components in isolation from your app's business logic, data, and context.
120 | That makes it easy to develop hard-to-reach states. Save these UI states as **stories** to revisit during development, testing, or QA.
121 |
122 | Browse example stories now by navigating to them in the sidebar.
123 | View their code in the `src/stories` directory to learn how they work.
124 | We recommend building UIs with a [**component-driven**](https://componentdriven.org) process starting with atomic components and ending with pages.
125 |
126 | Configure
127 |
128 |
174 |
175 | Learn
176 |
177 |
207 |
208 |
209 | Tip Edit the Markdown in{' '}
210 | src/stories/Introduction.stories.mdx
211 |
212 |
--------------------------------------------------------------------------------
/src/components/__stories__/WebsiteCarbonBadge.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ComponentStory, ComponentMeta } from '@storybook/react';
3 |
4 | import WebsiteCarbonBadge from '../WebsiteCarbonBadge';
5 |
6 | export default {
7 | title: 'WebsiteCarbonBadge',
8 | component: WebsiteCarbonBadge,
9 | argTypes: {},
10 | } as ComponentMeta;
11 |
12 | const Template: ComponentStory = (args) => ;
13 |
14 | export const Light = Template.bind({});
15 | Light.args = {
16 | dark: false,
17 | co2: '12',
18 | percentage: '90'
19 | };
20 |
21 | export const Dark = Template.bind({});
22 | Dark.args = {
23 | dark: true,
24 | co2: '12',
25 | percentage: '90'
26 | };
27 |
28 | export const English = Template.bind({});
29 | English.args = {
30 | dark: false,
31 | co2: '12',
32 | percentage: '90',
33 | lang: 'en'
34 | };
35 |
36 | export const EnglishDirtier = Template.bind({});
37 | EnglishDirtier.args = {
38 | dark: false,
39 | co2: '89',
40 | percentage: '49',
41 | lang: 'en'
42 | };
43 |
44 | export const French = Template.bind({});
45 | French.args = {
46 | dark: false,
47 | co2: '12',
48 | percentage: '90',
49 | lang: 'fr'
50 | };
51 |
52 | export const FrenchDirtier = Template.bind({});
53 | FrenchDirtier.args = {
54 | dark: false,
55 | co2: '89',
56 | percentage: '49',
57 | lang: 'fr'
58 | };
59 |
60 | export const Url = Template.bind({});
61 | Url.args = {
62 | dark: false,
63 | co2: '12',
64 | percentage: '90',
65 | lang: 'en',
66 | url: "www.example.com"
67 | };
68 |
69 | export const FetchData = Template.bind({});
70 | FetchData.args = {
71 | dark: false,
72 | lang: 'en',
73 | url: "www.google.com"
74 | };
75 |
76 |
--------------------------------------------------------------------------------
/src/components/__stories__/assets/code-brackets.svg:
--------------------------------------------------------------------------------
1 | illustration/code-brackets
--------------------------------------------------------------------------------
/src/components/__stories__/assets/colors.svg:
--------------------------------------------------------------------------------
1 | illustration/colors
--------------------------------------------------------------------------------
/src/components/__stories__/assets/comments.svg:
--------------------------------------------------------------------------------
1 | illustration/comments
--------------------------------------------------------------------------------
/src/components/__stories__/assets/direction.svg:
--------------------------------------------------------------------------------
1 | illustration/direction
--------------------------------------------------------------------------------
/src/components/__stories__/assets/flow.svg:
--------------------------------------------------------------------------------
1 | illustration/flow
--------------------------------------------------------------------------------
/src/components/__stories__/assets/plugin.svg:
--------------------------------------------------------------------------------
1 | illustration/plugin
--------------------------------------------------------------------------------
/src/components/__stories__/assets/repo.svg:
--------------------------------------------------------------------------------
1 | illustration/repo
--------------------------------------------------------------------------------
/src/components/__stories__/assets/stackalt.svg:
--------------------------------------------------------------------------------
1 | illustration/stackalt
--------------------------------------------------------------------------------
/src/components/__tests__/WebsiteCarbonBadge.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import '@testing-library/jest-dom';
3 | import { render } from '@testing-library/react';
4 |
5 | import WebsiteCarbonBadge from '../WebsiteCarbonBadge';
6 |
7 | describe('Running Test for WebsiteCarbonBadge', () => {
8 | it('renders the component', () => {
9 | render( );
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import WebsiteCarbonBadge from "./components/WebsiteCarbonBadge";
2 |
3 | export { WebsiteCarbonBadge };
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Language and Environment */
4 | "target": "es5", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
5 | "jsx": "react", /* Specify what JSX code is generated. */
6 |
7 | /* Modules */
8 | "module": "ESNext", /* Specify what module code is generated. */
9 | "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
10 |
11 | /* Emit */
12 | "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
13 | "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
14 | "sourceMap": true, /* Create source map files for emitted JavaScript files. */
15 | "outDir": "dist", /* Specify an output folder for all emitted files. */
16 | "declarationDir": "types", /* Specify the output directory for generated declaration files. */
17 |
18 | /* Interop Constraints */
19 | "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
20 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
21 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
22 |
23 | /* Type Checking */
24 | "strict": true, /* Enable all strict type-checking options. */
25 |
26 | /* Completeness */
27 | "skipLibCheck": true, /* Skip type checking all .d.ts files. */
28 | },
29 | "exclude": [
30 | "dist",
31 | "node_modules",
32 | "src/**/*.test.tsx",
33 | "src/**/*.stories.tsx",
34 | ],
35 | }
36 |
--------------------------------------------------------------------------------