diff --git a/package.json b/package.json index 6f369ce..65423fb 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "build": "run-p -c build:*", "build:design-system": "yarn workspace @roleypoly/design-system run build", "build:web": "yarn workspace @roleypoly/web run build", + "create-component": "yarn workspace @roleypoly/design-system run create-component", "lint": "run-p -c lint:* --", "lint:eslint": "eslint", "lint:prettier": "cross-env prettier -c '**/*.{ts,tsx,css,yml,yaml,md,json,js,jsx,sh,gitignore,mdx,Dockerfile}'", diff --git a/packages/design-system/README.md b/packages/design-system/README.md index 11498d0..cb41338 100644 --- a/packages/design-system/README.md +++ b/packages/design-system/README.md @@ -17,7 +17,13 @@ You need: Run: -- `yarn storybook` to get started. +- `yarn start:design-system` to get started. + +Need to make a new component? + +- `yarn create-component ` + - This will create the skeleton files needed for a component. + - See below for atomic types. ## Atomic Design 101 diff --git a/packages/design-system/hack/create-component.js b/packages/design-system/hack/create-component.js new file mode 100644 index 0000000..909a35e --- /dev/null +++ b/packages/design-system/hack/create-component.js @@ -0,0 +1,74 @@ +#!/usr/bin/env node + +// Usage: create-component.js + +const fs = require('fs'); +const path = require('path'); +const { camelCase, capitalCase, paramCase, pascalCase } = require('change-case'); + +const baseDir = path.resolve(__dirname, '..'); +const types = ['atom', 'molecule', 'organism', 'template']; + +const componentType = process.argv[2]; +const name = process.argv[3]; +const forceReplace = process.argv[4] === '--force'; + +if (!types.includes(componentType)) { + throw new Error(`Invalid component type: ${componentType}`); +} + +const typeStoryGroup = `${componentType.replace( + /^[a-zA-Z]/, + componentType[0].toUpperCase() +)}s`; + +const kebabCaseName = paramCase(name); +const pascalCaseName = pascalCase(name); +const camelCaseName = camelCase(name); +const capitalCaseName = capitalCase(name); + +const componentRoot = `${baseDir}/${componentType}s/${kebabCaseName}`; + +if (fs.existsSync(componentRoot)) { + if (!forceReplace) { + throw new Error( + `Component already exists: ${pascalCaseName} in ${componentType}s/${kebabCaseName}` + ); + } + + console.log(`Removing existing component: ${pascalCaseName}`); + fs.rmSync(componentRoot, { recursive: true }); +} + +// Make base dir +fs.mkdirSync(componentRoot); + +// Write index.ts +const index_ts = `export * from './${pascalCaseName}';\n`; +fs.writeFileSync(`${componentRoot}/index.ts`, index_ts, { encoding: 'utf8' }); + +// Write component +const component_tsx = `import { ${pascalCaseName}Styled } from './${pascalCaseName}.styled';\n\nexport const ${pascalCaseName} = () => (\n <${pascalCaseName}Styled>${pascalCaseName}\n);\n`; +fs.writeFileSync(`${componentRoot}/${pascalCaseName}.tsx`, component_tsx, { + encoding: 'utf8', +}); + +// Write styles +const component_styled_ts = `import styled from 'styled-components';\nexport const ${pascalCaseName}Styled = styled.div\`\`;\n`; +fs.writeFileSync(`${componentRoot}/${pascalCaseName}.styled.ts`, component_styled_ts, { + encoding: 'utf8', +}); + +// Write storybook +const component_stories_tsx = `import { ${pascalCaseName} } from './${pascalCaseName}';\n\nexport default {\n title: '${typeStoryGroup}/${capitalCaseName}',\n component: ${pascalCaseName},\n};\n\nexport const ${camelCaseName} = (args) => <${pascalCaseName} {...args} />;\n`; +fs.writeFileSync( + `${componentRoot}/${pascalCaseName}.stories.tsx`, + component_stories_tsx, + { + encoding: 'utf8', + } +); + +// All done! +console.log(`✨ Created ${componentType} '${name}'`); +console.log(`Open it: ${path.resolve(componentRoot)}`); diff --git a/packages/design-system/package.json b/packages/design-system/package.json index 7b0cc41..87da5bb 100644 --- a/packages/design-system/package.json +++ b/packages/design-system/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "scripts": { "build": "build-storybook -o ../../dist/-/storybook", + "create-component": "node ./hack/create-component.js", "start": "start-storybook -p 6006" }, "dependencies": { @@ -42,6 +43,7 @@ "@types/styled-components": "^5.1.11", "babel-loader": "8.1.0", "babel-plugin-styled-components": "^1.13.1", + "change-case": "^4.1.2", "tslint": "^6.1.3", "typescript": "^4.3.5" } diff --git a/packages/design-system/templates/editor-utility/EditorUtility.stories.tsx b/packages/design-system/templates/editor-utility/EditorUtility.stories.tsx new file mode 100644 index 0000000..7c9c6cd --- /dev/null +++ b/packages/design-system/templates/editor-utility/EditorUtility.stories.tsx @@ -0,0 +1,8 @@ +import { EditorUtility } from './EditorUtility'; + +export default { + title: 'Templates/Editor Utility', + component: EditorUtility, +}; + +export const editorUtility = (args) => ; diff --git a/packages/design-system/templates/editor-utility/EditorUtility.styled.ts b/packages/design-system/templates/editor-utility/EditorUtility.styled.ts new file mode 100644 index 0000000..966a1a7 --- /dev/null +++ b/packages/design-system/templates/editor-utility/EditorUtility.styled.ts @@ -0,0 +1,2 @@ +import styled from 'styled-components'; +export const EditorUtilityStyled = styled.div``; diff --git a/packages/design-system/templates/editor-utility/EditorUtility.tsx b/packages/design-system/templates/editor-utility/EditorUtility.tsx new file mode 100644 index 0000000..541fb35 --- /dev/null +++ b/packages/design-system/templates/editor-utility/EditorUtility.tsx @@ -0,0 +1,5 @@ +import { EditorUtilityStyled } from './EditorUtility.styled'; + +export const EditorUtility = () => ( + EditorUtility +); diff --git a/packages/design-system/templates/editor-utility/index.ts b/packages/design-system/templates/editor-utility/index.ts new file mode 100644 index 0000000..18d4150 --- /dev/null +++ b/packages/design-system/templates/editor-utility/index.ts @@ -0,0 +1 @@ +export * from './EditorUtility'; diff --git a/yarn.lock b/yarn.lock index 13c70f7..0b2dcf4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5434,7 +5434,7 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camel-case@^4.1.1: +camel-case@^4.1.1, camel-case@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== @@ -5486,6 +5486,15 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, can resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001197.tgz#47ad15b977d2f32b3ec2fe2b087e0c50443771db" integrity sha512-8aE+sqBqtXz4G8g35Eg/XEaFr2N7rd/VQ6eABGBmNtcB8cN6qNJhMi6oSFy4UWWZgqgL3filHT8Nha4meu3tsw== +capital-case@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/capital-case/-/capital-case-1.0.4.tgz#9d130292353c9249f6b00fa5852bee38a717e669" + integrity sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + upper-case-first "^2.0.2" + capture-exit@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" @@ -5551,6 +5560,24 @@ chalk@^4.1.1: ansi-styles "^4.1.0" supports-color "^7.1.0" +change-case@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/change-case/-/change-case-4.1.2.tgz#fedfc5f136045e2398c0410ee441f95704641e12" + integrity sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A== + dependencies: + camel-case "^4.1.2" + capital-case "^1.0.4" + constant-case "^3.0.4" + dot-case "^3.0.4" + header-case "^2.0.4" + no-case "^3.0.4" + param-case "^3.0.4" + pascal-case "^3.1.2" + path-case "^3.0.4" + sentence-case "^3.0.4" + snake-case "^3.0.4" + tslib "^2.0.3" + char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -5993,6 +6020,15 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= +constant-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-3.0.4.tgz#3b84a9aeaf4cf31ec45e6bf5de91bdfb0589faf1" + integrity sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + upper-case "^2.0.2" + constants-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" @@ -8902,6 +8938,14 @@ he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +header-case@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/header-case/-/header-case-2.0.4.tgz#5a42e63b55177349cf405beb8d775acabb92c063" + integrity sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q== + dependencies: + capital-case "^1.0.4" + tslib "^2.0.3" + hex-color-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" @@ -12381,7 +12425,7 @@ parallel-transform@^1.1.0: inherits "^2.0.3" readable-stream "^2.1.5" -param-case@^3.0.3: +param-case@^3.0.3, param-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== @@ -12489,6 +12533,14 @@ path-browserify@0.0.1: resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== +path-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/path-case/-/path-case-3.0.4.tgz#9168645334eb942658375c56f80b4c0cb5f82c6f" + integrity sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + path-dirname@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" @@ -15024,6 +15076,15 @@ send@0.17.1: range-parser "~1.2.1" statuses "~1.5.0" +sentence-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-3.0.4.tgz#3645a7b8c117c787fde8702056225bb62a45131f" + integrity sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + upper-case-first "^2.0.2" + serialize-javascript@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" @@ -15211,6 +15272,14 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" +snake-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c" + integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -16676,6 +16745,20 @@ upath@^1.1.1, upath@^1.1.2, upath@^1.2.0: resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== +upper-case-first@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-2.0.2.tgz#992c3273f882abd19d1e02894cc147117f844324" + integrity sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg== + dependencies: + tslib "^2.0.3" + +upper-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-2.0.2.tgz#d89810823faab1df1549b7d97a76f8662bae6f7a" + integrity sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg== + dependencies: + tslib "^2.0.3" + uri-js@^4.2.2: version "4.4.0" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602"