├── .bitmap ├── .eslintrc.js ├── .gitignore ├── .prettierrc.js ├── README.md ├── favicon.ico ├── pnpm-lock.yaml ├── tsconfig.json ├── types ├── asset.d.ts └── style.d.ts ├── workspace.jsonc └── wurde.comic ├── apps └── comic │ ├── app.tsx │ ├── comic.app-root.tsx │ ├── comic.docs.mdx │ ├── comic.react-app.ts │ ├── comic.spec.tsx │ ├── index.css │ └── index.ts ├── envs └── main-react-env │ ├── index.ts │ ├── jest │ └── jest.config.js │ ├── main-react-env.aspect.ts │ ├── main-react-env.docs.mdx │ ├── main-react-env.main.runtime.ts │ ├── main-react-env.preview.runtime.ts │ ├── main-react-env.spec.ts │ ├── tailwindcss │ └── tailwind.config.js │ └── webpack │ ├── webpack-transformers.ts │ └── webpack.config.ts ├── pages └── viewer │ ├── images │ ├── chain_of_command.png │ ├── data_trap.png │ ├── git.png │ ├── logical.png │ ├── making_progress.png │ ├── million_billion_trillion.png │ ├── occam.png │ ├── product_launch.png │ ├── star_ratings.png │ └── worrying.png │ ├── index.ts │ ├── viewer.docs.mdx │ ├── viewer.spec.tsx │ └── viewer.tsx ├── style └── tokens │ ├── breakpoints │ ├── breakpoints.docs.mdx │ ├── breakpoints.spec.ts │ ├── breakpoints.ts │ └── index.ts │ ├── colors │ ├── colors.docs.mdx │ ├── colors.spec.ts │ ├── colors.ts │ └── index.ts │ ├── font-family │ ├── font-family.docs.mdx │ ├── font-family.spec.ts │ ├── font-family.ts │ └── index.ts │ └── spacing │ ├── index.ts │ ├── spacing.docs.mdx │ ├── spacing.spec.ts │ └── spacing.ts └── ui ├── forms └── button │ ├── button.docs.mdx │ ├── button.spec.tsx │ ├── button.tsx │ └── index.ts ├── hooks └── use-comic │ ├── index.ts │ ├── use-comic.docs.mdx │ ├── use-comic.spec.ts │ └── use-comic.ts ├── layout └── card │ ├── card.composition.tsx │ ├── card.docs.mdx │ ├── card.spec.tsx │ ├── card.tsx │ └── index.ts ├── media └── image │ ├── image.docs.mdx │ ├── image.spec.tsx │ ├── image.tsx │ └── index.ts └── typography ├── heading ├── heading.composition.tsx ├── heading.docs.mdx ├── heading.spec.tsx ├── heading.tsx └── index.ts └── text ├── index.ts ├── text.docs.mdx ├── text.spec.tsx └── text.tsx /.bitmap: -------------------------------------------------------------------------------- 1 | /* THIS IS A BIT-AUTO-GENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. */ 2 | 3 | /** 4 | * The Bitmap file is an auto generated file used by Bit to track all your Bit components. It maps the component to a folder in your file system. 5 | * This file should be committed to VCS(version control). 6 | * Components are listed using their component ID (https://bit.dev/docs/components/component-id). 7 | * If you want to delete components you can use the "bit remove " command. 8 | * See the docs (https://bit.dev/docs/components/removing-components) for more information, or use "bit remove --help". 9 | */ 10 | 11 | { 12 | "apps/comic": { 13 | "scope": "", 14 | "version": "0.0.1", 15 | "mainFile": "index.ts", 16 | "rootDir": "wurde.comic/apps/comic" 17 | }, 18 | "envs/main-react-env": { 19 | "scope": "", 20 | "version": "0.0.1", 21 | "mainFile": "index.ts", 22 | "rootDir": "wurde.comic/envs/main-react-env" 23 | }, 24 | "pages/viewer": { 25 | "scope": "", 26 | "version": "0.0.1", 27 | "mainFile": "index.ts", 28 | "rootDir": "wurde.comic/pages/viewer" 29 | }, 30 | "style/tokens/breakpoints": { 31 | "scope": "", 32 | "version": "0.0.1", 33 | "mainFile": "index.ts", 34 | "rootDir": "wurde.comic/style/tokens/breakpoints" 35 | }, 36 | "style/tokens/colors": { 37 | "scope": "", 38 | "version": "0.0.1", 39 | "mainFile": "index.ts", 40 | "rootDir": "wurde.comic/style/tokens/colors" 41 | }, 42 | "style/tokens/font-family": { 43 | "scope": "", 44 | "version": "0.0.1", 45 | "mainFile": "index.ts", 46 | "rootDir": "wurde.comic/style/tokens/font-family" 47 | }, 48 | "style/tokens/spacing": { 49 | "scope": "", 50 | "version": "0.0.1", 51 | "mainFile": "index.ts", 52 | "rootDir": "wurde.comic/style/tokens/spacing" 53 | }, 54 | "ui/forms/button": { 55 | "scope": "", 56 | "version": "0.0.1", 57 | "mainFile": "index.ts", 58 | "rootDir": "wurde.comic/ui/forms/button" 59 | }, 60 | "ui/hooks/use-comic": { 61 | "scope": "", 62 | "version": "0.0.1", 63 | "mainFile": "index.ts", 64 | "rootDir": "wurde.comic/ui/hooks/use-comic" 65 | }, 66 | "ui/layout/card": { 67 | "scope": "", 68 | "version": "0.0.1", 69 | "mainFile": "index.ts", 70 | "rootDir": "wurde.comic/ui/layout/card" 71 | }, 72 | "ui/media/image": { 73 | "scope": "", 74 | "version": "0.0.1", 75 | "mainFile": "index.ts", 76 | "rootDir": "wurde.comic/ui/media/image" 77 | }, 78 | "ui/typography/heading": { 79 | "scope": "", 80 | "version": "0.0.1", 81 | "mainFile": "index.ts", 82 | "rootDir": "wurde.comic/ui/typography/heading" 83 | }, 84 | "ui/typography/text": { 85 | "scope": "", 86 | "version": "0.0.1", 87 | "mainFile": "index.ts", 88 | "rootDir": "wurde.comic/ui/typography/text" 89 | }, 90 | "$schema-version": "14.9.0" 91 | } -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@teambit/eslint-config-bit-react'], 3 | parserOptions: { 4 | project: './tsconfig.json' 5 | }, 6 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Bit 2 | .bit 3 | public 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # Diagnostic reports (https://nodejs.org/api/report.html) 14 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 15 | 16 | # Runtime data 17 | pids 18 | *.pid 19 | *.seed 20 | *.pid.lock 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | lib-cov 24 | 25 | # Coverage directory used by tools like istanbul 26 | coverage 27 | *.lcov 28 | 29 | # nyc test coverage 30 | .nyc_output 31 | 32 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 33 | .grunt 34 | 35 | # Bower dependency directory (https://bower.io/) 36 | bower_components 37 | 38 | # node-waf configuration 39 | .lock-wscript 40 | 41 | # Compiled binary addons (https://nodejs.org/api/addons.html) 42 | build/Release 43 | 44 | # Dependency directories 45 | node_modules/ 46 | jspm_packages/ 47 | 48 | # TypeScript v1 declaration files 49 | typings/ 50 | 51 | # TypeScript cache 52 | *.tsbuildinfo 53 | 54 | # Optional npm cache directory 55 | .npm 56 | 57 | # Optional eslint cache 58 | .eslintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variables file 76 | .env 77 | .env.test 78 | 79 | # parcel-bundler cache (https://parceljs.org/) 80 | .cache 81 | 82 | # Next.js build output 83 | .next 84 | 85 | # Nuxt.js build / generate output 86 | .nuxt 87 | dist 88 | 89 | # Gatsby files 90 | .cache/ 91 | 92 | # vuepress build output 93 | .vuepress/dist 94 | 95 | # Serverless directories 96 | .serverless/ 97 | 98 | # FuseBox cache 99 | .fusebox/ 100 | 101 | # DynamoDB Local files 102 | .dynamodb/ 103 | 104 | # TernJS port file 105 | .tern-port 106 | 107 | .history 108 | 109 | .DS_Store 110 | 111 | # Logs 112 | logs 113 | *.log 114 | npm-debug.log* 115 | yarn-debug.log* 116 | yarn-error.log* 117 | lerna-debug.log* 118 | .pnpm-debug.log* 119 | 120 | # Diagnostic reports (https://nodejs.org/api/report.html) 121 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 122 | 123 | # Runtime data 124 | pids 125 | *.pid 126 | *.seed 127 | *.pid.lock 128 | 129 | # Directory for instrumented libs generated by jscoverage/JSCover 130 | lib-cov 131 | 132 | # Coverage directory used by tools like istanbul 133 | coverage 134 | *.lcov 135 | 136 | # nyc test coverage 137 | .nyc_output 138 | 139 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 140 | .grunt 141 | 142 | # Bower dependency directory (https://bower.io/) 143 | bower_components 144 | 145 | # node-waf configuration 146 | .lock-wscript 147 | 148 | # Compiled binary addons (https://nodejs.org/api/addons.html) 149 | build/Release 150 | 151 | # Dependency directories 152 | node_modules/ 153 | jspm_packages/ 154 | 155 | # Snowpack dependency directory (https://snowpack.dev/) 156 | web_modules/ 157 | 158 | # TypeScript cache 159 | *.tsbuildinfo 160 | 161 | # Optional npm cache directory 162 | .npm 163 | 164 | # Optional eslint cache 165 | .eslintcache 166 | 167 | # Optional stylelint cache 168 | .stylelintcache 169 | 170 | # Microbundle cache 171 | .rpt2_cache/ 172 | .rts2_cache_cjs/ 173 | .rts2_cache_es/ 174 | .rts2_cache_umd/ 175 | 176 | # Optional REPL history 177 | .node_repl_history 178 | 179 | # Output of 'npm pack' 180 | *.tgz 181 | 182 | # Yarn Integrity file 183 | .yarn-integrity 184 | 185 | # dotenv environment variable files 186 | .env 187 | .env.development.local 188 | .env.test.local 189 | .env.production.local 190 | .env.local 191 | 192 | # parcel-bundler cache (https://parceljs.org/) 193 | .cache 194 | .parcel-cache 195 | 196 | # Next.js build output 197 | .next 198 | out 199 | 200 | # Nuxt.js build / generate output 201 | .nuxt 202 | dist 203 | 204 | # Gatsby files 205 | .cache/ 206 | # Comment in the public line in if your project uses Gatsby and not Next.js 207 | # https://nextjs.org/blog/next-9-1#public-directory-support 208 | # public 209 | 210 | # vuepress build output 211 | .vuepress/dist 212 | 213 | # vuepress v2.x temp and cache directory 214 | .temp 215 | .cache 216 | 217 | # Docusaurus cache and generated files 218 | .docusaurus 219 | 220 | # Serverless directories 221 | .serverless/ 222 | 223 | # FuseBox cache 224 | .fusebox/ 225 | 226 | # DynamoDB Local files 227 | .dynamodb/ 228 | 229 | # TernJS port file 230 | .tern-port 231 | 232 | # Stores VSCode versions used for testing VSCode extensions 233 | .vscode-test 234 | 235 | # yarn v2 236 | .yarn/cache 237 | .yarn/unplugged 238 | .yarn/build-state.yml 239 | .yarn/install-state.gz 240 | .pnp.* 241 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | const baseConfig = require("@teambit/react/prettier/prettier.config"); 2 | module.exports = { 3 | ...baseConfig, 4 | }; 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Custom Elements 2 | 3 | An example of the Bit framework. https://bit.dev 4 | 5 | Bit stands at the intersection between product and 6 | engineering. It helps you take complex product 7 | requirements, and break them down into independent, and 8 | reusable pieces called "components". It allows you to 9 | create components and compose them with each other. 10 | Components are described by names and APIs, and contain 11 | source code implementation. They can be of different kinds 12 | like apps, pages, UI components, backend services and even 13 | content. You can think of almost anything in components. 14 | 15 | ## Prerequisites 16 | 17 | This project requires the `bit` CLI is installed. 18 | 19 | https://bit.dev/docs/getting-started/installing-bit/installing-bit 20 | 21 | ```bash 22 | npx @teambit/bvm install 23 | ``` 24 | 25 | ## Getting Started 26 | 27 | ```bash 28 | git clone https://github.com/wurde/custom-elements 29 | cd custom-elements 30 | 31 | # Start the development server (open localhost:3000) 32 | bit start 33 | 34 | # Or run the app in production mode 35 | bit run comic 36 | 37 | # Generate a dependencies graph 38 | bit graph 39 | 40 | # Print a list of other commands 41 | bit help 42 | ``` 43 | 44 | ## License 45 | 46 | This project is __FREE__ to use, reuse, remix, and resell. 47 | This is made possible by the [MIT license](/LICENSE). 48 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wurde/custom-elements/7803c0cf8e16458132ae1cac072c39270e8ec270/favicon.ico -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./node_modules/@teambit/react/typescript/tsconfig.json", 3 | // "include": [], 4 | "compilerOptions": { 5 | "noEmit": true 6 | }, 7 | "exclude": [ 8 | "dist" 9 | ] 10 | } -------------------------------------------------------------------------------- /types/asset.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.png' { 2 | const value: any; 3 | export = value; 4 | } 5 | declare module '*.svg' { 6 | import type { FunctionComponent, SVGProps } from 'react'; 7 | 8 | export const ReactComponent: FunctionComponent & { title?: string }>; 9 | const src: string; 10 | export default src; 11 | } 12 | declare module '*.jpg' { 13 | const value: any; 14 | export = value; 15 | } 16 | declare module '*.jpeg' { 17 | const value: any; 18 | export = value; 19 | } 20 | declare module '*.gif' { 21 | const value: any; 22 | export = value; 23 | } 24 | declare module '*.bmp' { 25 | const value: any; 26 | export = value; 27 | } 28 | -------------------------------------------------------------------------------- /types/style.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.module.css' { 2 | const classes: { readonly [key: string]: string }; 3 | export default classes; 4 | } 5 | declare module '*.module.scss' { 6 | const classes: { readonly [key: string]: string }; 7 | export default classes; 8 | } 9 | declare module '*.module.sass' { 10 | const classes: { readonly [key: string]: string }; 11 | export default classes; 12 | } 13 | 14 | declare module '*.module.less' { 15 | const classes: { readonly [key: string]: string }; 16 | export default classes; 17 | } 18 | 19 | declare module '*.less' { 20 | const classes: { readonly [key: string]: string }; 21 | export default classes; 22 | } 23 | 24 | declare module '*.css' { 25 | const classes: { readonly [key: string]: string }; 26 | export default classes; 27 | } 28 | 29 | declare module '*.sass' { 30 | const classes: { readonly [key: string]: string }; 31 | export default classes; 32 | } 33 | 34 | declare module '*.scss' { 35 | const classes: { readonly [key: string]: string }; 36 | export default classes; 37 | } 38 | 39 | declare module '*.mdx' { 40 | const component: any; 41 | export default component; 42 | } 43 | -------------------------------------------------------------------------------- /workspace.jsonc: -------------------------------------------------------------------------------- 1 | /** 2 | * This is the main configuration file of your bit workspace. 3 | * for full documentation, please see: https://bit.dev/docs/workspace/workspace-configuration 4 | **/{ 5 | "$schema": "https://static.bit.dev/teambit/schemas/schema.json", 6 | /** 7 | * Add the app to your workspace config. 8 | **/ 9 | "wurde.comic/apps/comic": {}, 10 | /** 11 | * main configuration of the Bit workspace. (required) 12 | **/ 13 | "teambit.workspace/workspace": { 14 | /** 15 | * the name of the component workspace. used for development purposes. 16 | **/ 17 | "name": "custom-elements", 18 | /** 19 | * set the icon to be shown on the Bit server. 20 | **/ 21 | "icon": "https://static.bit.dev/bit-logo.svg", 22 | /** 23 | * default directory to place a component during `bit import` and `bit create`. 24 | * the following placeholders are available: 25 | * name - component name includes namespace, e.g. 'ui/button'. 26 | * scopeId - full scope-id includes the owner, e.g. 'teambit.compilation'. 27 | * scope - scope name only, e.g. 'compilation'. 28 | * owner - owner name in bit.dev, e.g. 'teambit'. 29 | **/ 30 | "defaultDirectory": "{owner}.{scope}/{name}", 31 | /** 32 | * default scope for all components in workspace. 33 | **/ 34 | "defaultScope": "wurde.comic" 35 | }, 36 | /** 37 | * main configuration for component dependency resolution. (required) 38 | **/ 39 | "teambit.dependencies/dependency-resolver": { 40 | /** 41 | * choose the package manager for Bit to use. you can choose between 'yarn', 'pnpm' 42 | */ 43 | "packageManager": "teambit.dependencies/pnpm", 44 | "policy": { 45 | "dependencies": { 46 | "@bit-foundations/styling.tailwind.webpack-transformer": "0.0.6", 47 | "@teambit/eslint-config-bit-react": "~0.0.367", 48 | "@teambit/react": "0.0.714", 49 | "@typescript-eslint/eslint-plugin": "4.29.3", 50 | "eslint-import-resolver-node": "0.3.6", 51 | "eslint-plugin-import": "2.26.0", 52 | "eslint-plugin-jest": "24.4.0", 53 | "eslint-plugin-jsx-a11y": "6.5.1", 54 | "eslint-plugin-mdx": "1.17.0", 55 | "eslint-plugin-react": "7.29.4", 56 | "postcss-loader": "6.2.1" 57 | }, 58 | "peerDependencies": { 59 | "@testing-library/jest-dom": "5.16.4", 60 | "@testing-library/react": "12.0.0", 61 | "@testing-library/react-hooks": "7.0.2", 62 | "@testing-library/user-event": "14.0.4", 63 | "@types/jest": "27.4.1", 64 | "autoprefixer": "10.4.4", 65 | "postcss": "8.4.12", 66 | "react": "17.0.2", 67 | "react-dom": "17.0.2", 68 | "tailwindcss": "3.0.23" 69 | } 70 | } 71 | }, 72 | /** 73 | * workspace variants allow to set different subsets of configuration for components in your 74 | * workspace. this is extremely useful for upgrading, aligning and building components with a new 75 | * set of dependencies. a rule can be a directory or a component-id/namespace, in which case, 76 | * wrap the rule with curly brackets (e.g. `"{ui/*}": {}`) 77 | * see https://bit.dev/docs/workspace/variants for more info. 78 | **/ 79 | "teambit.workspace/variants": { 80 | "{apps/**}, {pages/**}, {ui/**}": { 81 | "wurde.comic/envs/main-react-env": {} 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /wurde.comic/apps/comic/app.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { Viewer } from '@wurde/comic.pages.viewer'; 4 | 5 | export function ComicApp() { 6 | return ; 7 | } 8 | -------------------------------------------------------------------------------- /wurde.comic/apps/comic/comic.app-root.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | import './index.css'; 5 | 6 | import { ComicApp } from './app'; 7 | 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | document.getElementById('root'), 13 | ); 14 | -------------------------------------------------------------------------------- /wurde.comic/apps/comic/comic.docs.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Comic application component. 3 | labels: ['app'] 4 | --- 5 | 6 | Configure the app plugin on your workspace: 7 | 8 | ```json 9 | "wurde.comic/apps/comic": {}, 10 | ``` 11 | 12 | ### Run the application 13 | 14 | You can run your application on a separate port to see it outside of the Bit workspace 15 | 16 | ```bash 17 | bit run comic 18 | ``` 19 | -------------------------------------------------------------------------------- /wurde.comic/apps/comic/comic.react-app.ts: -------------------------------------------------------------------------------- 1 | // https://www.npmjs.com/package/@teambit/react 2 | import { ReactAppOptions } from '@teambit/react'; 3 | 4 | // type ReactAppOptions = { 5 | // name: string; 6 | // entry: string[]; 7 | // ssr?: boolean; 8 | // bundler?: Bundler; 9 | // devServer?: DevServer; 10 | // webpackTransformers?: WebpackConfigTransformer[]; 11 | // prerender?: ReactAppPrerenderOptions; 12 | // deploy?: (context: ReactDeployContext) => Promise; 13 | // portRange?: number[]; 14 | // favicon?: string; 15 | // } 16 | export const ComicApp: ReactAppOptions = { 17 | // Name of the application. 18 | name: 'comic', 19 | 20 | // Path to entry files of the application. 21 | entry: [require.resolve('./comic.app-root')], 22 | 23 | // Use server-side rendering for the app. 24 | ssr: false, 25 | 26 | // Instance of bundler to use. default is Webpack. 27 | // bundler: {}, 28 | 29 | // Instance of dev server to use. default is Webpack. 30 | // devServer: {}, 31 | 32 | // Set webpack transformers 33 | webpackTransformers: [], 34 | 35 | // Prerender your app. Accepts an array of routes. 36 | // If none, prerender would not apply. 37 | prerender: { routes: [] }, 38 | 39 | // Deploy function. 40 | deploy: async function deployer() { 41 | // TODO: implement deployment script 42 | }, 43 | 44 | // Ranges of ports to use to run the app server. 45 | portRange: [3000, 3010], 46 | 47 | // Favicon for the app. 48 | favicon: './favicon.ico', 49 | }; 50 | 51 | export default ComicApp; 52 | -------------------------------------------------------------------------------- /wurde.comic/apps/comic/comic.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | 4 | import { ComicApp } from './app'; 5 | 6 | describe('apps/comic', () => { 7 | it('should render the image with alt text', () => { 8 | const { container, getByAltText } = render(); 9 | 10 | const img = container.querySelector('img'); 11 | expect(img).toBeVisible(); 12 | expect(img).toHaveClass('m-auto'); 13 | 14 | const altText = 'It\'s important to make sure your analysis destroys as much information as it produces.'; 15 | expect(getByAltText(altText)).toBeInTheDocument(); 16 | }); 17 | 18 | it('should render the title', () => { 19 | const { getByText } = render(); 20 | const rendered = getByText('Data Trap'); 21 | expect(rendered).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /wurde.comic/apps/comic/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /wurde.comic/apps/comic/index.ts: -------------------------------------------------------------------------------- 1 | export { ComicApp } from './app'; 2 | -------------------------------------------------------------------------------- /wurde.comic/envs/main-react-env/index.ts: -------------------------------------------------------------------------------- 1 | import { MainReactEnvAspect } from './main-react-env.aspect'; 2 | 3 | export type { MainReactEnvMain } from './main-react-env.main.runtime'; 4 | export default MainReactEnvAspect; 5 | export { MainReactEnvAspect }; 6 | -------------------------------------------------------------------------------- /wurde.comic/envs/main-react-env/jest/jest.config.js: -------------------------------------------------------------------------------- 1 | // Override the Jest config to ignore transpiling from specific folders 2 | // See the base Jest config: https://bit.cloud/teambit/react/react/~code/jest/jest.config.js 3 | 4 | const reactJestConfig = require('@teambit/react/jest/jest.config'); 5 | 6 | // uncomment the line below and install the package if you want to use this function 7 | // const { 8 | // generateNodeModulesPattern, 9 | // } = require('@teambit/dependencies.modules.packages-excluder'); 10 | // const packagesToExclude = ['@my-org', 'my-package-name']; 11 | // module.exports = { 12 | // ...reactJestConfig, 13 | // transformIgnorePatterns: [ 14 | // '^.+\.module\.(css|sass|scss)$', 15 | // generateNodeModulesPattern({ packages: packagesToExclude }), 16 | // ], 17 | // }; 18 | 19 | module.exports = { 20 | // https://bit.cloud/teambit/react/react/~code/jest/jest.base.config.js 21 | ...reactJestConfig, 22 | collectCoverageFrom: [ 23 | 'src/**/*.{ts,tsx}', 24 | '!src/**/*.d.ts', 25 | ], 26 | testMatch: [ 27 | '/**/*.spec.{ts,tsx}', 28 | ], 29 | transformIgnorePatterns: [ 30 | '^.+.module.(css|sass|scss)$', 31 | ], 32 | }; 33 | -------------------------------------------------------------------------------- /wurde.comic/envs/main-react-env/main-react-env.aspect.ts: -------------------------------------------------------------------------------- 1 | import { Aspect } from '@teambit/harmony'; 2 | 3 | export const MainReactEnvAspect = Aspect.create({ 4 | id: 'wurde.comic/envs/main-react-env', 5 | }); 6 | -------------------------------------------------------------------------------- /wurde.comic/envs/main-react-env/main-react-env.docs.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: 'A standard React component development environment' 3 | labels: ['react', 'typescript', 'env', 'extension'] 4 | --- 5 | 6 | ## Overview 7 | 8 | A customized version which extends the default React component development environment created by teambit. 9 | 10 | This environment can be applied to all your components or a set of components via the command `bit env set wurde.comic/envs/main-react-env`, or under the variants of your `workspace.json` file. 11 | That means they will use your custom environment instead of the default environment. Environment components are just like any other Bit components in that they can be 12 | exported and then shared and used in various projects which makes it easier to create standards when working with many teams. 13 | 14 | ### Usage instructions 15 | 16 | #### Recommended usage: 17 | 18 | Run the command `bit env set <"pattern" or component_id> wurde.comic/envs/main-react-env` where the pattern is a glob pattern to select multiple components. This will put the env 19 | config in your component's entry in the `.bitmap` file. 20 | 21 | :::Note - this will override any variants policy that tries to set an env for this component in the workspace.jsonc 22 | ::: 23 | 24 | #### Alternative Usage 25 | Under the **variant** section of your `workspace.json` file choose which components you want to have the custom environment set. You can find the id of the extension in the `main-react-env.aspect.ts` file. 26 | 27 | ```json 28 | { 29 | "teambit.workspace/variants": { 30 | "{ui/**}, {pages/**}": { 31 | "wurde.comic/envs/main-react-env": {} 32 | } 33 | } 34 | } 35 | ``` 36 | 37 | This usage may be deprecated in future in favour of the recommended usage above 38 | ## Runtime Configurations 39 | 40 | Extend the `main.runtime` file when you want to add custom configurations at runtime. 41 | 42 | ### Compilation 43 | 44 | By default, Component compilation is done with the TypeScript compiler. Target format is `ES2015` which 45 | supports execution from both NodeJS and browser runtimes for server-side rendering. You can modify the `tsconfig.json` file to add your own compiler options which will then be merged with the default configs set by teambit. 46 | 47 | Example: 48 | 49 | ```json 50 | { 51 | "compilerOptions": { 52 | "target": "es2017", 53 | "module": "es2015", 54 | "moduleResolution": "node", 55 | "lib": ["es2017", "dom"], 56 | "experimentalDecorators": true, 57 | "esModuleInterop": true, 58 | "outDir": "dist", 59 | "sourceMap": true, 60 | "emitDecoratorMetadata": true, 61 | "allowJs": true, 62 | "baseUrl": ".", 63 | "jsx": "react" 64 | } 65 | } 66 | ``` 67 | 68 | ### Testing 69 | 70 | Component testing is done through [Jest](https://jestjs.io/) with the default `teambit.react/react` environment. You can modify the `jestconfig.js` file to add your own configurations which will then be merged with the default configs set by teambit. 71 | 72 | Example: 73 | 74 | To Override the Jest config to ignore transpiling from specific folders add this to the `jestconfig.js` file: 75 | 76 | ```js 77 | const reactJestConfig = require('@teambit/react/jest/jest.config'); 78 | module.exports = { 79 | ...reactJestConfig, 80 | transformIgnorePatterns: ['/node_modules/(?!(prop-types|@teambit))'] 81 | }; 82 | ``` 83 | 84 | ### Webpack 85 | 86 | Bit uses webpack 5 to bundle components. You can modify the `webpack.config.js` file to add your own configurations which will then be merged with the default configs set by teambit. 87 | 88 | Example: 89 | 90 | ```ts 91 | module.exports = { 92 | module: { 93 | // add your custom rules here 94 | rules: [] 95 | } 96 | }; 97 | ``` 98 | 99 | ### ESLint 100 | 101 | Bit uses ESLint to lint your components. You can add your own rules in the `main-react-env.main.runtime` file. 102 | 103 | Example: 104 | 105 | ```ts 106 | react.useEslint({ 107 | transformers: [ 108 | (config) => { 109 | config.setRule('no-console', ['error']); 110 | // add more rules here 111 | return config; 112 | } 113 | ] 114 | }), 115 | ``` 116 | 117 | To use ESLint: 118 | 119 | ```bash 120 | bit lint 121 | bit lint --fix 122 | ``` 123 | 124 | ### Formatting 125 | 126 | Bit uses Prettier to format your components. You can add your own rules in the `main-react-env.main.runtime` file. 127 | 128 | Example: 129 | 130 | ```ts 131 | react.usePrettier({ 132 | transformers: [ 133 | (config) => { 134 | config.setKey('tabWidth', 2); 135 | // add more rules here 136 | return config; 137 | } 138 | ] 139 | }), 140 | ``` 141 | 142 | To use Prettier: 143 | 144 | ```bash 145 | bit format --check 146 | bit format 147 | ``` 148 | 149 | ### Dependencies 150 | 151 | Override the default dependencies in the `main-react-env.main.runtime` file to include react types of a different version for example. 152 | 153 | ```ts 154 | react.overrideDependencies({ 155 | devDependencies: { 156 | '@types/react': '17.0.3' 157 | } 158 | }); 159 | ``` 160 | 161 | ## Preview Configurations 162 | 163 | Extend the `main-react-env.preview.runtime` file when you want to add your own customizations only for previewing in the Bit UI. 164 | 165 | ### Adding a Theme 166 | 167 | A custom theme has been added to the env which wraps all the composition files with the required theme so they can be developed with the correct themeing rather than the browsers default. This is added only in the preview runtime and not in the main runtime meaning it is only applied to compositions and not when consuming components. Adding a theme when consuming should be done at App level as you component may be consumed in various apps and have different themes applied depending on where it is consumed. 168 | 169 | Example: 170 | 171 | ```ts 172 | react.registerProvider([ThemeCompositions]); 173 | -------------------------------------------------------------------------------- /wurde.comic/envs/main-react-env/main-react-env.main.runtime.ts: -------------------------------------------------------------------------------- 1 | import { 2 | MainRuntime, 3 | } from '@teambit/cli'; 4 | import { 5 | ReactAspect, 6 | ReactMain, 7 | UseWebpackModifiers, 8 | } from '@teambit/react'; 9 | import { 10 | EnvsAspect, 11 | EnvsMain, 12 | } from '@teambit/envs'; 13 | 14 | import { 15 | MainReactEnvAspect, 16 | } from './main-react-env.aspect'; 17 | import { 18 | previewConfigTransformer, 19 | devServerConfigTransformer, 20 | } from './webpack/webpack-transformers'; 21 | 22 | export class MainReactEnvMain { 23 | static slots = []; 24 | 25 | static dependencies = [ReactAspect, EnvsAspect]; 26 | 27 | static runtime = MainRuntime; 28 | 29 | static async provider([react, envs]: [ReactMain, EnvsMain]) { 30 | const webpackModifiers: UseWebpackModifiers = { 31 | previewConfig: [previewConfigTransformer], 32 | devServerConfig: [devServerConfigTransformer], 33 | }; 34 | 35 | const MainReactEnvEnv = react.compose([ 36 | /** 37 | * Uncomment to override the config files for TypeScript, Webpack or Jest 38 | * Your config gets merged with the defaults 39 | */ 40 | 41 | react.useWebpack(webpackModifiers), 42 | react.overrideJestConfig(require.resolve('./jest/jest.config')), 43 | 44 | /** 45 | * override the ESLint default config here then check your files for lint errors 46 | * @example 47 | * bit lint 48 | * bit lint --fix 49 | */ 50 | react.useEslint({ 51 | transformers: [ 52 | (config) => { 53 | config.setRule('no-console', ['error']); 54 | return config; 55 | }, 56 | ], 57 | }), 58 | 59 | /** 60 | * override the Prettier default config here the check your formatting 61 | * @example 62 | * bit format --check 63 | * bit format 64 | */ 65 | react.usePrettier({ 66 | transformers: [ 67 | (config) => { 68 | config.setKey('tabWidth', 2); 69 | return config; 70 | }, 71 | ], 72 | }), 73 | 74 | /** 75 | * override dependencies here 76 | * @example 77 | * Uncomment types to include version 17.0.3 of the types package 78 | */ 79 | react.overrideDependencies({ 80 | devDependencies: { 81 | // '@types/react': '17.0.3' 82 | }, 83 | }), 84 | ]); 85 | envs.registerEnv(MainReactEnvEnv); 86 | return new MainReactEnvMain(); 87 | } 88 | } 89 | 90 | MainReactEnvAspect.addRuntime(MainReactEnvMain); 91 | -------------------------------------------------------------------------------- /wurde.comic/envs/main-react-env/main-react-env.preview.runtime.ts: -------------------------------------------------------------------------------- 1 | import { PreviewRuntime } from '@teambit/preview'; 2 | import { ReactAspect } from '@teambit/react'; 3 | 4 | import { MainReactEnvAspect } from './main-react-env.aspect'; 5 | 6 | export class MainReactEnvPreviewMain { 7 | static runtime = PreviewRuntime; 8 | 9 | static dependencies = [ReactAspect]; 10 | 11 | static async provider() { 12 | const mainReactEnvPreviewMain = new MainReactEnvPreviewMain(); 13 | 14 | return mainReactEnvPreviewMain; 15 | } 16 | } 17 | 18 | MainReactEnvAspect.addRuntime(MainReactEnvPreviewMain); 19 | -------------------------------------------------------------------------------- /wurde.comic/envs/main-react-env/main-react-env.spec.ts: -------------------------------------------------------------------------------- 1 | import { MainReactEnvMain } from './main-react-env.main.runtime'; 2 | 3 | describe('envs/main-react-env', () => { 4 | it('should instantiate successfully', () => { 5 | const env = new MainReactEnvMain(); 6 | expect(env).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /wurde.comic/envs/main-react-env/tailwindcss/tailwind.config.js: -------------------------------------------------------------------------------- 1 | const { breakpoints } = require('@wurde/comic.style.tokens.breakpoints'); 2 | const { colors } = require('@wurde/comic.style.tokens.colors'); 3 | const { fontFamily } = require('@wurde/comic.style.tokens.font-family'); 4 | const { spacing } = require('@wurde/comic.style.tokens.spacing'); 5 | 6 | module.exports = { 7 | // https://tailwindcss.com/docs/content-configuration 8 | content: ['./**/*.tsx', './**/{*.html,*.js,*.md,*.mdx}'], 9 | // https://tailwindcss.com/docs/theme 10 | theme: { 11 | // Extend TailwindCSS's default theme. 12 | extend: { 13 | // https://tailwindcss.com/docs/responsive-design 14 | screens: breakpoints, 15 | colors, 16 | fontFamily, 17 | spacing, 18 | }, 19 | }, 20 | variants: { 21 | extend: {}, 22 | }, 23 | plugins: [], 24 | }; 25 | -------------------------------------------------------------------------------- /wurde.comic/envs/main-react-env/webpack/webpack-transformers.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/teambit/bit/tree/master/scopes/react/react/webpack 2 | 3 | import { 4 | WebpackConfigTransformer, 5 | WebpackConfigMutator, 6 | } from '@teambit/webpack'; 7 | 8 | import webpackConfig from './webpack.config'; 9 | 10 | /** 11 | * Transformation to apply for both preview and dev server 12 | * @param config 13 | * @param _context 14 | */ 15 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 16 | function commonTransformation(config: WebpackConfigMutator) { 17 | // Merge config with the webpack.config.js file 18 | // if you choose to import a module export format config. 19 | config.merge([webpackConfig]); 20 | // config.addAliases({}); 21 | // config.addModuleRule(youRuleHere); 22 | return config; 23 | } 24 | 25 | /** 26 | * Transformation for the preview only 27 | * @param config 28 | * @param context 29 | * @returns 30 | */ 31 | export const previewConfigTransformer: WebpackConfigTransformer = ( 32 | config: WebpackConfigMutator, 33 | ) => { 34 | const newConfig = commonTransformation(config); 35 | return newConfig; 36 | }; 37 | 38 | /** 39 | * Transformation for the dev server only 40 | * @param config 41 | * @param context 42 | * @returns 43 | */ 44 | export const devServerConfigTransformer: WebpackConfigTransformer = ( 45 | config: WebpackConfigMutator, 46 | ) => { 47 | const newConfig = commonTransformation(config); 48 | return newConfig; 49 | }; 50 | -------------------------------------------------------------------------------- /wurde.comic/envs/main-react-env/webpack/webpack.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | module: { 3 | rules: [ 4 | { 5 | test: /\.css$/i, 6 | use: [ 7 | 'style-loader', 8 | 'css-loader', 9 | { 10 | loader: 'postcss-loader', 11 | options: { 12 | postcssOptions: { 13 | plugins: [ 14 | [ 15 | 'postcss-preset-env', 16 | { 17 | // Options 18 | }, 19 | ], 20 | [ 21 | 'tailwindcss', 22 | { 23 | // Options 24 | }, 25 | ], 26 | [ 27 | 'autoprefixer', 28 | { 29 | // Options 30 | }, 31 | ], 32 | ], 33 | }, 34 | }, 35 | }, 36 | ], 37 | }, 38 | ], 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /wurde.comic/pages/viewer/images/chain_of_command.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wurde/custom-elements/7803c0cf8e16458132ae1cac072c39270e8ec270/wurde.comic/pages/viewer/images/chain_of_command.png -------------------------------------------------------------------------------- /wurde.comic/pages/viewer/images/data_trap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wurde/custom-elements/7803c0cf8e16458132ae1cac072c39270e8ec270/wurde.comic/pages/viewer/images/data_trap.png -------------------------------------------------------------------------------- /wurde.comic/pages/viewer/images/git.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wurde/custom-elements/7803c0cf8e16458132ae1cac072c39270e8ec270/wurde.comic/pages/viewer/images/git.png -------------------------------------------------------------------------------- /wurde.comic/pages/viewer/images/logical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wurde/custom-elements/7803c0cf8e16458132ae1cac072c39270e8ec270/wurde.comic/pages/viewer/images/logical.png -------------------------------------------------------------------------------- /wurde.comic/pages/viewer/images/making_progress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wurde/custom-elements/7803c0cf8e16458132ae1cac072c39270e8ec270/wurde.comic/pages/viewer/images/making_progress.png -------------------------------------------------------------------------------- /wurde.comic/pages/viewer/images/million_billion_trillion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wurde/custom-elements/7803c0cf8e16458132ae1cac072c39270e8ec270/wurde.comic/pages/viewer/images/million_billion_trillion.png -------------------------------------------------------------------------------- /wurde.comic/pages/viewer/images/occam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wurde/custom-elements/7803c0cf8e16458132ae1cac072c39270e8ec270/wurde.comic/pages/viewer/images/occam.png -------------------------------------------------------------------------------- /wurde.comic/pages/viewer/images/product_launch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wurde/custom-elements/7803c0cf8e16458132ae1cac072c39270e8ec270/wurde.comic/pages/viewer/images/product_launch.png -------------------------------------------------------------------------------- /wurde.comic/pages/viewer/images/star_ratings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wurde/custom-elements/7803c0cf8e16458132ae1cac072c39270e8ec270/wurde.comic/pages/viewer/images/star_ratings.png -------------------------------------------------------------------------------- /wurde.comic/pages/viewer/images/worrying.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wurde/custom-elements/7803c0cf8e16458132ae1cac072c39270e8ec270/wurde.comic/pages/viewer/images/worrying.png -------------------------------------------------------------------------------- /wurde.comic/pages/viewer/index.ts: -------------------------------------------------------------------------------- 1 | export { Viewer } from './viewer'; 2 | -------------------------------------------------------------------------------- /wurde.comic/pages/viewer/viewer.docs.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: A Viewer page. 3 | --- 4 | 5 | import { Viewer } from './viewer'; 6 | 7 | ### Render Page 8 | 9 | ```js live 10 | 11 | ``` 12 | -------------------------------------------------------------------------------- /wurde.comic/pages/viewer/viewer.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | 4 | import { Viewer } from './viewer'; 5 | 6 | describe('pages/viewer', () => { 7 | it('should render with the correct text', () => { 8 | const { getByText } = render(); 9 | const rendered = getByText('Data Trap'); 10 | expect(rendered).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /wurde.comic/pages/viewer/viewer.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { Heading } from '@wurde/comic.ui.typography.heading'; 3 | import { Image } from '@wurde/comic.ui.media.image'; 4 | import { Button } from '@wurde/comic.ui.forms.button'; 5 | import { useComic } from '@wurde/comic.ui.hooks.use-comic'; 6 | 7 | import chainOfCommand from './images/chain_of_command.png'; 8 | import dataTrap from './images/data_trap.png'; 9 | import git from './images/git.png'; 10 | import logical from './images/logical.png'; 11 | import makingProgress from './images/making_progress.png'; 12 | import MillionBillionTrillion from './images/million_billion_trillion.png'; 13 | import occam from './images/occam.png'; 14 | import productLaunch from './images/product_launch.png'; 15 | import starRatings from './images/star_ratings.png'; 16 | import worrying from './images/worrying.png'; 17 | 18 | function random(min, max) { 19 | return Math.floor(Math.random() * (max - min + 1)) + min; 20 | } 21 | 22 | export function Viewer() { 23 | const [comicId, setComicId] = useState(0); 24 | const comic = useComic(comicId); 25 | let img; 26 | 27 | switch (comic.img) { 28 | case 'chain_of_command.png': 29 | img = chainOfCommand; 30 | break; 31 | case 'data_trap.png': 32 | img = dataTrap; 33 | break; 34 | case 'git.png': 35 | img = git; 36 | break; 37 | case 'logical.png': 38 | img = logical; 39 | break; 40 | case 'making_progress.png': 41 | img = makingProgress; 42 | break; 43 | case 'million_billion_trillion.png': 44 | img = MillionBillionTrillion; 45 | break; 46 | case 'occam.png': 47 | img = occam; 48 | break; 49 | case 'product_launch.png': 50 | img = productLaunch; 51 | break; 52 | case 'star_ratings.png': 53 | img = starRatings; 54 | break; 55 | case 'worrying.png': 56 | img = worrying; 57 | break; 58 | default: 59 | img = chainOfCommand; 60 | } 61 | 62 | return ( 63 |
64 | {comic.title} 65 | 66 | 73 | 74 | {comic.alt} 79 |
80 | ); 81 | } 82 | -------------------------------------------------------------------------------- /wurde.comic/style/tokens/breakpoints/breakpoints.docs.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | labels: ['module'] 3 | description: 'A set of breakpoints to support responsive design.' 4 | --- 5 | 6 | API: 7 | 8 | ```ts 9 | const breakpoints = { 10 | desktop: 1024, 11 | tablet: 768, 12 | mobile: 360, 13 | }; 14 | ``` 15 | -------------------------------------------------------------------------------- /wurde.comic/style/tokens/breakpoints/breakpoints.spec.ts: -------------------------------------------------------------------------------- 1 | import { breakpoints } from './breakpoints'; 2 | 3 | describe('style/tokens/breakpoints', () => { 4 | it('should have breakpoints for desktop, tablet, and mobile', () => { 5 | expect(breakpoints.desktop).toBeDefined(); 6 | expect(breakpoints.desktop).toBe('1024px'); 7 | expect(breakpoints.tablet).toBeDefined(); 8 | expect(breakpoints.tablet).toBe('768px'); 9 | expect(breakpoints.mobile).toBeDefined(); 10 | expect(breakpoints.mobile).toBe('360px'); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /wurde.comic/style/tokens/breakpoints/breakpoints.ts: -------------------------------------------------------------------------------- 1 | export const breakpoints = { 2 | desktop: '1024px', 3 | tablet: '768px', 4 | mobile: '360px', 5 | }; 6 | -------------------------------------------------------------------------------- /wurde.comic/style/tokens/breakpoints/index.ts: -------------------------------------------------------------------------------- 1 | export { breakpoints } from './breakpoints'; 2 | -------------------------------------------------------------------------------- /wurde.comic/style/tokens/colors/colors.docs.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | labels: ['module'] 3 | description: 'A set of colors for use throughout the application.' 4 | --- 5 | 6 | API: 7 | 8 | ```ts 9 | const colors = { 10 | copy: { 11 | primary: '#1C1C1C', 12 | }, 13 | }; 14 | ``` 15 | -------------------------------------------------------------------------------- /wurde.comic/style/tokens/colors/colors.spec.ts: -------------------------------------------------------------------------------- 1 | import { colors } from './colors'; 2 | 3 | describe('style/tokens/colors', () => { 4 | it('should have colors for copy', () => { 5 | expect(colors.copy).toBeDefined(); 6 | expect(colors.copy.primary).toBeDefined(); 7 | expect(colors.copy.primary).toBe('#1C1C1C'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /wurde.comic/style/tokens/colors/colors.ts: -------------------------------------------------------------------------------- 1 | export const colors = { 2 | copy: { 3 | primary: '#1C1C1C', 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /wurde.comic/style/tokens/colors/index.ts: -------------------------------------------------------------------------------- 1 | export { colors } from './colors'; 2 | -------------------------------------------------------------------------------- /wurde.comic/style/tokens/font-family/font-family.docs.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | labels: ['module'] 3 | description: 'A font family definition optimized for browser support.' 4 | --- 5 | 6 | API: 7 | 8 | ```ts 9 | const fontFamily = { 10 | default: 'arial, helvetica, sans-serif;', 11 | }; 12 | ``` 13 | -------------------------------------------------------------------------------- /wurde.comic/style/tokens/font-family/font-family.spec.ts: -------------------------------------------------------------------------------- 1 | import { fontFamily } from './font-family'; 2 | 3 | describe('style/tokens/font-family', () => { 4 | it('should have a default fontFamily', () => { 5 | expect(fontFamily.main).toBeDefined(); 6 | expect(fontFamily.main).toBe('arial,helvetica,sans-serif;'); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /wurde.comic/style/tokens/font-family/font-family.ts: -------------------------------------------------------------------------------- 1 | export const fontFamily = { 2 | main: 'arial,helvetica,sans-serif;', 3 | }; 4 | -------------------------------------------------------------------------------- /wurde.comic/style/tokens/font-family/index.ts: -------------------------------------------------------------------------------- 1 | export { fontFamily } from './font-family'; 2 | -------------------------------------------------------------------------------- /wurde.comic/style/tokens/spacing/index.ts: -------------------------------------------------------------------------------- 1 | export { spacing } from './spacing'; 2 | -------------------------------------------------------------------------------- /wurde.comic/style/tokens/spacing/spacing.docs.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | labels: ['module'] 3 | description: 'A set of t-shirt sizes that follow the rule-of-8. Use these tokens to create consistency in the positioning of your components.' 4 | --- 5 | 6 | API: 7 | 8 | ```ts 9 | const spacing = { 10 | zero: '0px', 11 | xxxs: '4px', 12 | xxs: '8px', 13 | xs: '16px', 14 | s: '32px', 15 | m: '40px', 16 | l: '48px', 17 | xl: '56px', 18 | xxl: '64px', 19 | xxxl: '72px', 20 | }; 21 | ``` 22 | -------------------------------------------------------------------------------- /wurde.comic/style/tokens/spacing/spacing.spec.ts: -------------------------------------------------------------------------------- 1 | import { spacing } from './spacing'; 2 | 3 | describe('style/tokens/spacing', () => { 4 | it('should have spacing using t-shirt sizing and rule of 8', () => { 5 | expect(spacing.zero).toBeDefined(); 6 | expect(spacing.zero).toBe('0px'); 7 | expect(spacing.xxxs).toBeDefined(); 8 | expect(spacing.xxxs).toBe('4px'); 9 | expect(spacing.xxs).toBeDefined(); 10 | expect(spacing.xxs).toBe('8px'); 11 | expect(spacing.xs).toBeDefined(); 12 | expect(spacing.xs).toBe('16px'); 13 | expect(spacing.s).toBeDefined(); 14 | expect(spacing.s).toBe('32px'); 15 | expect(spacing.m).toBeDefined(); 16 | expect(spacing.m).toBe('40px'); 17 | expect(spacing.l).toBeDefined(); 18 | expect(spacing.l).toBe('48px'); 19 | expect(spacing.xl).toBeDefined(); 20 | expect(spacing.xl).toBe('56px'); 21 | expect(spacing.xxl).toBeDefined(); 22 | expect(spacing.xxl).toBe('64px'); 23 | expect(spacing.xxxl).toBeDefined(); 24 | expect(spacing.xxxl).toBe('72px'); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /wurde.comic/style/tokens/spacing/spacing.ts: -------------------------------------------------------------------------------- 1 | export const spacing = { 2 | zero: '0px', 3 | xxxs: '4px', 4 | xxs: '8px', 5 | xs: '16px', 6 | s: '32px', 7 | m: '40px', 8 | l: '48px', 9 | xl: '56px', 10 | xxl: '64px', 11 | xxxl: '72px', 12 | }; 13 | -------------------------------------------------------------------------------- /wurde.comic/ui/forms/button/button.docs.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: A Button component. 3 | --- 4 | 5 | import { Button } from './button'; 6 | 7 | ### Usage 8 | 9 | ```js live 10 | 11 | ``` 12 | -------------------------------------------------------------------------------- /wurde.comic/ui/forms/button/button.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import { Button } from './button'; 4 | 5 | it('should render with the correct text', () => { 6 | const { getByText } = render(); 7 | const rendered = getByText('hello world!'); 8 | expect(rendered).toBeTruthy(); 9 | }); 10 | -------------------------------------------------------------------------------- /wurde.comic/ui/forms/button/button.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from 'react'; 2 | 3 | export type ButtonProps = { 4 | children?: ReactNode 5 | className?: string 6 | onClick?: () => void 7 | }; 8 | 9 | export function Button({ className, onClick, children }: ButtonProps) { 10 | return ( 11 | 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /wurde.comic/ui/forms/button/index.ts: -------------------------------------------------------------------------------- 1 | export { Button } from './button'; 2 | export type { ButtonProps } from './button'; 3 | -------------------------------------------------------------------------------- /wurde.comic/ui/hooks/use-comic/index.ts: -------------------------------------------------------------------------------- 1 | export { useComic } from './use-comic'; 2 | -------------------------------------------------------------------------------- /wurde.comic/ui/hooks/use-comic/use-comic.docs.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: 'A React Hook that fetches an xkdc comic.' 3 | labels: ['hook', 'counter'] 4 | --- 5 | 6 | import { useComic } from './use-comic'; 7 | 8 | ## Component usage 9 | 10 | In this example clicking the button calls `increment` which increments the `count` by 1 11 | 12 | ```js 13 | import { useComic } from './use-comic'; 14 | 15 | const [comicId, setComicId] = useState(1); 16 | const { comic, isLoading, error } = useComic(comicId); 17 | 18 | {comic.title} 19 | {comic.alt} 20 | ``` 21 | -------------------------------------------------------------------------------- /wurde.comic/ui/hooks/use-comic/use-comic.spec.ts: -------------------------------------------------------------------------------- 1 | import { useComic } from './use-comic'; 2 | 3 | describe('ui/hooks/use-comic', () => { 4 | it('should return specific comic if passed ID', () => { 5 | const comic = useComic(1); 6 | expect(comic.title).toBe('Occam'); 7 | }); 8 | 9 | it('should return first comic if passed out of range number', async () => { 10 | const comic = useComic(100); 11 | expect(comic.title).toBe('Data Trap'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /wurde.comic/ui/hooks/use-comic/use-comic.ts: -------------------------------------------------------------------------------- 1 | const comics = [ 2 | { 3 | month: '2', 4 | year: '2022', 5 | alt: 'It\'s important to make sure your analysis destroys as much information as it produces.', 6 | img: 'data_trap.png', 7 | title: 'Data Trap', 8 | day: '16', 9 | }, 10 | { 11 | month: '11', 12 | year: '2021', 13 | alt: 'Oh no, Murphy just picked up the razor.', 14 | img: 'occam.png', 15 | title: 'Occam', 16 | day: '12', 17 | }, 18 | { 19 | month: '8', 20 | year: '2012', 21 | alt: 'I got lost and wandered into the world\'s creepiest cemetery, where the headstones just had names and star ratings. Freaked me out. When I got home I tried to leave the cemetery a bad review on Yelp, but as my hand hovered over the \'one star\' button I felt this distant chill ...', 22 | img: 'star_ratings.png', 23 | title: 'Star Ratings', 24 | day: '22', 25 | }, 26 | { 27 | month: '12', 28 | year: '2018', 29 | alt: 'You can tell most people don\u2019t really assign an absolute meaning to these numbers because in some places and time periods, \u201cbillion\u201d has meant 1,000x what it\'s meant in others, and a lot of us never even noticed.', 30 | img: 'million_billion_trillion.png', 31 | title: 'Million, Billion, Trillion', 32 | day: '28', 33 | }, 34 | { 35 | month: '1', 36 | year: '2015', 37 | alt: 'If the breaking news is about an event at a hospital or a lab, move it all the way over to the right.', 38 | img: 'worrying.png', 39 | title: 'Worrying', 40 | day: '2', 41 | }, 42 | { 43 | month: '6', 44 | year: '2021', 45 | alt: '\'Okay, that was weird, but the product reveal was normal. I think the danger is pas--\' \'One more thing.\' \'Oh no.', 46 | img: 'product_launch.png', 47 | title: 'Product Launch', 48 | day: '7', 49 | }, 50 | { 51 | month: '10', 52 | year: '2017', 53 | alt: 'I started off with countless problems. But now I know, thanks to COUNT(), that I have \'#REF! ERROR: Circular dependency detected\' problems.', 54 | img: 'making_progress.png', 55 | title: 'Making Progress', 56 | day: '23', 57 | }, 58 | { 59 | month: '5', 60 | year: '2011', 61 | alt: 'Themistocles said his infant son ruled all Greece -- \'Athens rules all Greece; I control Athens; my wife controls me; and my infant son controls her.\' Thus, nowadays the world is controlled by whoever buys advertising time on Dora the Explorer.', 62 | img: 'chain_of_command.png', 63 | title: 'Chain of Command', 64 | day: '13', 65 | }, 66 | { 67 | month: '10', 68 | year: '2017', 69 | alt: 'It\'s like I\'ve always said--people just need more common sense. But not the kind of common sense that lets them figure out that they\'re being condescended to by someone who thinks they\'re stupid, because then I\'ll be in trouble.', 70 | img: 'logical.png', 71 | title: 'Logical', 72 | day: '11', 73 | }, 74 | { 75 | month: '10', 76 | year: '2015', 77 | alt: 'If that doesn\'t fix it, git.txt contains the phone number of a friend of mine who understands git. Just wait through a few minutes of \'It\'s really pretty simple, just think of branches as...\' and eventually you\'ll learn the commands that will fix everything.', 78 | img: 'git.png', 79 | title: 'Git', 80 | day: '30', 81 | }, 82 | ]; 83 | 84 | export function useComic(id: number) { 85 | if (id >= 0 && id <= 9) { 86 | return comics[id]; 87 | } 88 | return comics[0]; 89 | } 90 | -------------------------------------------------------------------------------- /wurde.comic/ui/layout/card/card.composition.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Card } from './card'; 3 | 4 | export const BasicCard = () => hello world!; 5 | -------------------------------------------------------------------------------- /wurde.comic/ui/layout/card/card.docs.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: A Card component. 3 | --- 4 | 5 | import { Card } from './card'; 6 | 7 | A component that does something special and renders text in a div. 8 | 9 | ### Component usage 10 | 11 | ```js 12 | Hello world! 13 | ``` 14 | 15 | ### Render hello world! 16 | 17 | ```js live 18 | Hello world! 19 | ``` 20 | -------------------------------------------------------------------------------- /wurde.comic/ui/layout/card/card.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | 4 | import { BasicCard } from './card.composition'; 5 | 6 | describe('ui/layout/card', () => { 7 | it('should render with the correct text', () => { 8 | const { getByText } = render(); 9 | const rendered = getByText('hello world!'); 10 | expect(rendered).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /wurde.comic/ui/layout/card/card.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from 'react'; 2 | 3 | export type CardProps = { 4 | children?: ReactNode; 5 | }; 6 | 7 | export function Card({ children }: CardProps) { 8 | return
{children}
; 9 | } 10 | -------------------------------------------------------------------------------- /wurde.comic/ui/layout/card/index.ts: -------------------------------------------------------------------------------- 1 | export { Card } from './card'; 2 | export type { CardProps } from './card'; 3 | -------------------------------------------------------------------------------- /wurde.comic/ui/media/image/image.docs.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: A Image component. 3 | --- 4 | 5 | import { Image } from './image'; 6 | 7 | A component that renders an image. 8 | 9 | ### Component usage 10 | 11 | ```js live 12 | The distinction between a ship and a boat is a line drawn in water. 16 | ``` 17 | -------------------------------------------------------------------------------- /wurde.comic/ui/media/image/image.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | 4 | import { Image } from './image'; 5 | 6 | describe('ui/media/image', () => { 7 | it('should render with the correct text', () => { 8 | const src = 'https://imgs.xkcd.com/comics/frankenstein_captcha.png'; 9 | const altText = 'The distinction between a ship and a boat is a line drawn in water.'; 10 | 11 | const { container, getByAltText } = render({altText}); 12 | const img = container.querySelector('img'); 13 | expect(img).toBeInTheDocument(); 14 | const imgByAlt = getByAltText(altText); 15 | expect(imgByAlt).toBeTruthy(); 16 | }); 17 | 18 | it('should accept custom styles via class utilities', () => { 19 | const src = 'https://imgs.xkcd.com/comics/frankenstein_captcha.png'; 20 | const altText = 'The distinction between a ship and a boat is a line drawn in water.'; 21 | 22 | const { container } = render({altText}); 23 | const rendered = container.querySelector('.custom-class'); 24 | expect(rendered).toBeTruthy(); 25 | const another = container.querySelector('.another'); 26 | expect(another).toBeTruthy(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /wurde.comic/ui/media/image/image.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export type ImageProps = { 4 | src: string 5 | alt: string 6 | className?: string; 7 | }; 8 | 9 | export function Image({ src, alt, className }: ImageProps) { 10 | return {alt}; 11 | } 12 | 13 | Image.defaultProps = { 14 | className: '', 15 | }; 16 | -------------------------------------------------------------------------------- /wurde.comic/ui/media/image/index.ts: -------------------------------------------------------------------------------- 1 | export { Image } from './image'; 2 | export type { ImageProps } from './image'; 3 | -------------------------------------------------------------------------------- /wurde.comic/ui/typography/heading/heading.composition.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Heading } from './heading'; 3 | 4 | export const BasicHeading = () => hello world!; 5 | -------------------------------------------------------------------------------- /wurde.comic/ui/typography/heading/heading.docs.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: A Heading component. 3 | --- 4 | 5 | import { Heading } from './heading'; 6 | 7 | A component that does something special and renders text in a div. 8 | 9 | ### Component usage 10 | 11 | ```js 12 | Hello world! 13 | ``` 14 | 15 | ### Render 16 | 17 | ```js live 18 | <> 19 | h1.Heading 20 | h2.Heading 21 | h3.Heading 22 | h4.Heading 23 | h5.Heading 24 | h6.Heading 25 | 26 | ``` 27 | -------------------------------------------------------------------------------- /wurde.comic/ui/typography/heading/heading.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | 4 | import { Heading } from './heading'; 5 | 6 | describe('ui/typography/heading', () => { 7 | it('should render with the correct text', () => { 8 | const { getByText } = render(hello world!); 9 | const rendered = getByText('hello world!'); 10 | expect(rendered).toBeTruthy(); 11 | }); 12 | 13 | it('should render with the correct variant', () => { 14 | const { container: baseContainer } = render(); 15 | const base = baseContainer.querySelector('h2'); 16 | expect(base).toBeTruthy(); 17 | 18 | const { container: h1Container } = render(); 19 | const h1 = h1Container.querySelector('h1'); 20 | expect(h1).toBeTruthy(); 21 | 22 | const { container: h2Container } = render(); 23 | const h2 = h2Container.querySelector('h2'); 24 | expect(h2).toBeTruthy(); 25 | 26 | const { container: h3Container } = render(); 27 | const h3 = h3Container.querySelector('h3'); 28 | expect(h3).toBeTruthy(); 29 | 30 | const { container: h4Container } = render(); 31 | const h4 = h4Container.querySelector('h4'); 32 | expect(h4).toBeTruthy(); 33 | 34 | const { container: h5Container } = render(); 35 | const h5 = h5Container.querySelector('h5'); 36 | expect(h5).toBeTruthy(); 37 | 38 | const { container: h6Container } = render(); 39 | const h6 = h6Container.querySelector('h6'); 40 | expect(h6).toBeTruthy(); 41 | }); 42 | 43 | it('should accept custom styles via class utilities', () => { 44 | const { container } = render(); 45 | const rendered = container.querySelector('.custom-class'); 46 | expect(rendered).toBeTruthy(); 47 | const another = container.querySelector('.another'); 48 | expect(another).toBeTruthy(); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /wurde.comic/ui/typography/heading/heading.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from 'react'; 2 | 3 | export type HeadingProps = { 4 | children?: ReactNode; 5 | variant?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; 6 | className?: string; 7 | }; 8 | 9 | export function Heading({ children, variant, className }: HeadingProps) { 10 | switch (variant) { 11 | case 'h1': 12 | return ( 13 |

16 | {children} 17 |

18 | ); 19 | case 'h2': 20 | return ( 21 |

24 | {children} 25 |

26 | ); 27 | case 'h3': 28 | return ( 29 |

32 | {children} 33 |

34 | ); 35 | case 'h4': 36 | return ( 37 |

40 | {children} 41 |

42 | ); 43 | case 'h5': 44 | return ( 45 |
48 | {children} 49 |
50 | ); 51 | case 'h6': 52 | return ( 53 |
56 | {children} 57 |
58 | ); 59 | default: 60 | return ( 61 |

64 | {children} 65 |

66 | ); 67 | } 68 | } 69 | 70 | Heading.defaultProps = { 71 | variant: 'h2', 72 | className: '', 73 | }; 74 | -------------------------------------------------------------------------------- /wurde.comic/ui/typography/heading/index.ts: -------------------------------------------------------------------------------- 1 | export { Heading } from './heading'; 2 | export type { HeadingProps } from './heading'; 3 | -------------------------------------------------------------------------------- /wurde.comic/ui/typography/text/index.ts: -------------------------------------------------------------------------------- 1 | export { Text } from './text'; 2 | export type { TextProps } from './text'; 3 | -------------------------------------------------------------------------------- /wurde.comic/ui/typography/text/text.docs.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: A Text component. 3 | --- 4 | 5 | import { Text } from './text'; 6 | 7 | A component that does something special and renders text in a div. 8 | 9 | ### Component usage 10 | 11 | ```js 12 | Hello world! 13 | ``` 14 | 15 | ### Render hello world! 16 | 17 | ```js live 18 | Hello world! 19 | ``` 20 | -------------------------------------------------------------------------------- /wurde.comic/ui/typography/text/text.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | 4 | import { Text } from './text'; 5 | 6 | describe('ui/typography/text', () => { 7 | it('should render with the correct text', () => { 8 | const { getByText } = render(hello world!); 9 | const rendered = getByText('hello world!'); 10 | expect(rendered).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /wurde.comic/ui/typography/text/text.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from 'react'; 2 | 3 | export type TextProps = { 4 | children?: ReactNode; 5 | }; 6 | 7 | export function Text({ children }: TextProps) { 8 | return {children}; 9 | } 10 | --------------------------------------------------------------------------------