diff --git a/packages/create-mechanic/CHANGELOG.md b/packages/create-mechanic/CHANGELOG.md index d9ca7602..40e588f0 100644 --- a/packages/create-mechanic/CHANGELOG.md +++ b/packages/create-mechanic/CHANGELOG.md @@ -7,9 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Ability to copy template or examples that use custom inputs. +- New Adaptive Grid design function (by @munusshih) added to examples +- Adds base .gitignore to new projects +- Tries to initialize a git repository for new projects +- Right before trying to install dependencies of new project, it will list out which dependencies are being installed + ### Fixed - Missing line break was added finalizing creating a DF. +- Adds some line breaks across the CLI logs for reading room. ## 2.0.0-beta.10 - 2023-02-10 diff --git a/packages/create-mechanic/function-blank/index.js b/packages/create-mechanic/function-blank/function/index.js similarity index 100% rename from packages/create-mechanic/function-blank/index.js rename to packages/create-mechanic/function-blank/function/index.js diff --git a/packages/create-mechanic/function-examples/adaptive-grid/dependencies.json b/packages/create-mechanic/function-examples/adaptive-grid/dependencies.json new file mode 100644 index 00000000..81bb91dd --- /dev/null +++ b/packages/create-mechanic/function-examples/adaptive-grid/dependencies.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "@mechanic-design/engine-react": "^2.0.0-beta.10" + } +} diff --git a/packages/create-mechanic/function-examples/business-card-generator/assets/EULA-PangramPangram-FreeForPersonalUse-MAY2021.pdf b/packages/create-mechanic/function-examples/adaptive-grid/function/assets/EULA-PangramPangram-FreeForPersonalUse-MAY2021.pdf similarity index 100% rename from packages/create-mechanic/function-examples/business-card-generator/assets/EULA-PangramPangram-FreeForPersonalUse-MAY2021.pdf rename to packages/create-mechanic/function-examples/adaptive-grid/function/assets/EULA-PangramPangram-FreeForPersonalUse-MAY2021.pdf diff --git a/packages/create-mechanic/function-examples/business-card-generator/assets/PPObjectSans-Heavy.otf b/packages/create-mechanic/function-examples/adaptive-grid/function/assets/PPObjectSans-Heavy.otf similarity index 100% rename from packages/create-mechanic/function-examples/business-card-generator/assets/PPObjectSans-Heavy.otf rename to packages/create-mechanic/function-examples/adaptive-grid/function/assets/PPObjectSans-Heavy.otf diff --git a/packages/create-mechanic/function-examples/business-card-generator/assets/PPObjectSans-HeavySlanted.otf b/packages/create-mechanic/function-examples/adaptive-grid/function/assets/PPObjectSans-HeavySlanted.otf similarity index 100% rename from packages/create-mechanic/function-examples/business-card-generator/assets/PPObjectSans-HeavySlanted.otf rename to packages/create-mechanic/function-examples/adaptive-grid/function/assets/PPObjectSans-HeavySlanted.otf diff --git a/packages/create-mechanic/function-examples/business-card-generator/assets/PPObjectSans-Regular.otf b/packages/create-mechanic/function-examples/adaptive-grid/function/assets/PPObjectSans-Regular.otf similarity index 100% rename from packages/create-mechanic/function-examples/business-card-generator/assets/PPObjectSans-Regular.otf rename to packages/create-mechanic/function-examples/adaptive-grid/function/assets/PPObjectSans-Regular.otf diff --git a/packages/create-mechanic/function-examples/business-card-generator/assets/PPObjectSans-Slanted.otf b/packages/create-mechanic/function-examples/adaptive-grid/function/assets/PPObjectSans-Slanted.otf similarity index 100% rename from packages/create-mechanic/function-examples/business-card-generator/assets/PPObjectSans-Slanted.otf rename to packages/create-mechanic/function-examples/adaptive-grid/function/assets/PPObjectSans-Slanted.otf diff --git a/packages/create-mechanic/function-examples/adaptive-grid/function/components/Column.js b/packages/create-mechanic/function-examples/adaptive-grid/function/components/Column.js new file mode 100644 index 00000000..93ea7bb2 --- /dev/null +++ b/packages/create-mechanic/function-examples/adaptive-grid/function/components/Column.js @@ -0,0 +1,23 @@ +import React from "react"; + +export const Column = ({ width, height, x, y, showGrid, children }) => { + return ( + <> + +
{children}
+
+ + {showGrid && ( + + )} + + ); +}; diff --git a/packages/create-mechanic/function-examples/adaptive-grid/function/components/Image.js b/packages/create-mechanic/function-examples/adaptive-grid/function/components/Image.js new file mode 100644 index 00000000..b6b2b256 --- /dev/null +++ b/packages/create-mechanic/function-examples/adaptive-grid/function/components/Image.js @@ -0,0 +1,69 @@ +import React from "react"; + +const defaultUrl = + "https://images.unsplash.com/photo-1568214697537-ace27ffd6cf3?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1888&q=80"; + +export const Image = ({ + image, + href, + x, + width, + height, + gutterRatio, + filterOpacity, + gridColor +}) => { + const imageHref = image ? (href ? href : "") : defaultUrl; + + return ( + <> + + {/* mask to crop the image into rectangle */} + + + + + + {/* the image that will be cropped */} + + + {/* filter applied over image */} + + + {/* lines surrounding image */} + + + + + + ); +}; diff --git a/packages/create-mechanic/function-examples/adaptive-grid/function/hooks.js b/packages/create-mechanic/function-examples/adaptive-grid/function/hooks.js new file mode 100644 index 00000000..cc39c1db --- /dev/null +++ b/packages/create-mechanic/function-examples/adaptive-grid/function/hooks.js @@ -0,0 +1,39 @@ +import { useEffect, useState, useRef } from "react"; + +export const usePotentialRandomValue = ( + randomGenerator, + fixedFallback, + isRandom +) => { + const randomValue = randomGenerator(); + const value = useRef(isRandom ? randomValue : fixedFallback); + return value.current; +}; + +export const useImageHref = image => { + const [href, setHref] = useState(""); + + useEffect(() => { + let reader; + if (image) { + reader = new FileReader(); + + reader.readAsDataURL(image); + + reader.onload = function () { + setHref(reader.result); + }; + + reader.onerror = function () { + console.error(reader.error); + }; + } + return () => { + if (reader) { + reader.abort(); + } + }; + }, [image]); + + return href; +}; diff --git a/packages/create-mechanic/function-examples/adaptive-grid/function/index.js b/packages/create-mechanic/function-examples/adaptive-grid/function/index.js new file mode 100644 index 00000000..e3b2fd62 --- /dev/null +++ b/packages/create-mechanic/function-examples/adaptive-grid/function/index.js @@ -0,0 +1,411 @@ +import React, { useEffect } from "react"; + +import { Image } from "./components/Image"; +import { Column } from "./components/Column"; +import { useImageHref, usePotentialRandomValue } from "./hooks"; +import { + getRandomInt, + getRandomSign, + getRandomColor, + brightnessByColor +} from "./utils"; + +import "./styles.css"; + +export const handler = ({ inputs, mechanic }) => { + const { + width, + height, + randomRatio, + grid, + textSize, + randomColor, + textOne, + textTwo, + textThree, + textFour, + title, + image, + filterOpacity, + titleSizeAdjust + } = inputs; + + const canvasRatio = width / height; + const columnOptions = canvasRatio >= 0.5 ? (canvasRatio >= 0.75 ? 3 : 2) : 1; + + // Colors + const textColor = usePotentialRandomValue( + getRandomColor, + randomColor.textColor, + randomColor.show + ); + const titleColor = usePotentialRandomValue( + getRandomColor, + randomColor.titleColor, + randomColor.show + ); + const backgroundColor = usePotentialRandomValue( + getRandomColor, + randomColor.backgroundColor, + randomColor.show + ); + + // Column ratios + const columnOneRatio = usePotentialRandomValue( + () => getRandomInt(2, 10), + randomRatio.columnOneRatio, + randomRatio.show + ); + const columnTwoRatio = usePotentialRandomValue( + () => getRandomInt(2, 10), + canvasRatio >= 0.5 ? randomRatio.columnTwoRatio : 0, + canvasRatio >= 0.5 && randomRatio.show + ); + const columnThreeRatio = usePotentialRandomValue( + () => getRandomInt(2, 10), + canvasRatio >= 0.75 ? randomRatio.columnThreeRatio : 0, + canvasRatio >= 0.75 && randomRatio.show + ); + const imageColumn = usePotentialRandomValue( + () => getRandomInt(1, columnOptions + 1), + randomRatio.imageColumn, + randomRatio.show + ); + + // Other spacing + const border = usePotentialRandomValue( + () => getRandomInt(15, 65), + randomRatio.border, + randomRatio.show + ); + const gutter = usePotentialRandomValue( + () => getRandomInt(15, 45), + randomRatio.gutter, + randomRatio.show + ); + + // Horizontal space + const borderRatio = (border * width) / 1080; + const gutterRatio = (gutter * width) / 1080; + const ratioSum = + (width - borderRatio * 2 - gutterRatio * (columnOptions - 1)) / + (columnOneRatio + columnTwoRatio + columnThreeRatio); + const oneWidth = ratioSum * columnOneRatio; + const twoWidth = ratioSum * columnTwoRatio; + const threeWidth = ratioSum * columnThreeRatio; + + const chooseW = [ + canvasRatio >= 0.5 + ? oneWidth + borderRatio + gutterRatio * 0.5 + : oneWidth + borderRatio * 2, + canvasRatio >= 0.75 + ? twoWidth + gutterRatio + : twoWidth + gutterRatio * 0.5 + borderRatio, + threeWidth + borderRatio + borderRatio * 0.5 + ]; + const chooseX = [ + 0, + borderRatio + gutterRatio * 0.5 + oneWidth, + borderRatio + gutterRatio * 1.5 + oneWidth + twoWidth + ]; + const cropWidth = chooseW[imageColumn - 1]; + const cropX = chooseX[imageColumn - 1]; + + const fullHeight = height - borderRatio * 2; + const textSizeRatio = + ((textSize - (canvasRatio - 0.5) * 2) * width) / + 1080 / + Math.min(canvasRatio, 1); + const titleSize = + ((textSize - title.length * 0.8 + titleSizeAdjust) * 10 * width) / + 1080 / + Math.min(canvasRatio, 1); + const titleAngle = usePotentialRandomValue( + () => getRandomSign() * Math.random() * (60 / canvasRatio), + null, + true + ); + + const gridColor = brightnessByColor(backgroundColor) > 127 ? "#000" : "#fff"; + + const bigTextStyle = { + color: titleColor, + fontSize: textSizeRatio * 1.5, + fontFamily: "Object Sans", + whiteSpace: "pre-wrap", + overflowWrap: "anywhere", + hyphens: "auto" + }; + + const textStyle = { + color: textColor, + fontSize: textSizeRatio, + fontFamily: "Object Sans", + whiteSpace: "pre-wrap", + overflowWrap: "anywhere", + hyphens: "auto" + }; + + const href = useImageHref(image); + + useEffect(() => { + if (!image || href !== "") { + mechanic.done(); + } + }, [image, href]); + + return ( + + + + + + +
+

{textOne}

+ {canvasRatio < 0.5 && ( + <> +
+

{textFour}

+ + )} +
+ +
+

{textTwo}

+ {canvasRatio < 0.5 && ( + <> +
+

{textThree}

+ + )} +
+ + + + {canvasRatio < 0.75 && ( +
+

{textFour}

+
+ )} + +
+

{textThree}

+
+
+ + +
+

{textFour}

+
+
+ + {/* title */} + + {title.toUpperCase()} + + + ); +}; + +export const inputs = { + width: { + type: "number", + default: 1000 + }, + height: { + type: "number", + default: 1000 + }, + randomRatio: { + type: "groupToggle", + default: true, + label: "Random Ratio", + inputs: { + columnOneRatio: { + type: "number", + slider: true, + default: 2, + min: 1, + max: 10, + step: 1 + }, + columnTwoRatio: { + type: "number", + slider: true, + default: 2, + min: 1, + max: 10, + step: 1 + }, + columnThreeRatio: { + type: "number", + slider: true, + default: 1, + min: 1, + max: 10, + step: 1 + }, + border: { + type: "number", + slider: true, + default: 15, + min: 1, + max: 100, + step: 1 + }, + gutter: { + type: "number", + slider: true, + default: 15, + min: 1, + max: 100, + step: 1 + }, + imageColumn: { + type: "number", + slider: true, + default: 1, + min: 1, + max: 3, + step: 1 + } + } + }, + randomColor: { + type: "groupToggle", + default: false, + label: "Random Color", + inputs: { + backgroundColor: { + type: "color", + model: "hex", + default: "#000000" + }, + textColor: { + type: "color", + model: "hex", + default: "#ffffff" + }, + titleColor: { + type: "color", + model: "hex", + default: "#E94825" + } + } + }, + image: { + type: "image", + multiple: false + }, + filterOpacity: { + type: "number", + default: 20, + min: 0, + max: 100, + step: 1, + slider: true + }, + textSize: { + type: "number", + default: 20 + }, + titleSizeAdjust: { + type: "number", + slider: true, + default: 0, + min: -5, + max: 15, + step: 1 + }, + title: { + type: "text", + default: "Mechanic" + }, + textOne: { + type: "text", + default: "MUNUS SHIH" + }, + textTwo: { + type: "text", + default: "MECHANIC.DESIGN INFO@MECHANIC.DESIGN" + }, + textThree: { + type: "text", + default: "@MECHANIC 781 12TH ST, 8A, NEW YORK, NY 10003" + }, + textFour: { + type: "text", + default: "MUNUS@MECHANIC.DESIGN" + }, + grid: { + type: "boolean", + default: false + } +}; + +export const presets = { + "Instagram Story": { + width: 1080, + height: 1920 + }, + "Instagram Post": { + width: 1080, + height: 1080 + }, + Poster: { + width: 812, + height: 1148 + }, + Banner: { + width: 1640, + height: 624 + }, + Ticket: { + width: 394, + height: 1126 + } +}; + +export const settings = { + engine: require("@mechanic-design/engine-react"), + showMultipleExports: true +}; diff --git a/packages/create-mechanic/function-examples/adaptive-grid/function/styles.css b/packages/create-mechanic/function-examples/adaptive-grid/function/styles.css new file mode 100644 index 00000000..1d1b1791 --- /dev/null +++ b/packages/create-mechanic/function-examples/adaptive-grid/function/styles.css @@ -0,0 +1,63 @@ +/* Object Sans + * This beautiful font was designed by Alex Slobzheninov. + * --------------------------------------------------------------------------- + * Object Sans is a contemporary type family that puts together the best + * qualities of Swiss neo-grotesks and geometric fonts. It’s a multifunctional + * workhorse designed to work best in any printed and on-screen contexts. + * It is free to use for personal purposes. If you would like to use it + * for commercial purposes, you will need to purchase a license. + * for more information visit https://pangrampangram.com/products/object-sans + * or check ./assets/EULA-PangramPangram-FreeForPersonalUse-MAY2021.pdf + * Alex Slobzheninov https://www.behance.net/slobzheninov + * --------------------------------------------------------------------------- +*/ + +@font-face { + font-family: "Object Sans"; + src: url("./assets/PPObjectSans-Regular.otf") format("opentype"); +} + +@font-face { + font-family: "Object Sans Italic"; + src: url("./assets/PPObjectSans-Slanted.otf") format("opentype"); + font-style: italic; +} + +@font-face { + font-family: "Object Sans Heavy"; + src: url("./assets/PPObjectSans-Heavy.otf") format("opentype"); + font-weight: bold; +} + +@font-face { + font-family: "Object Sans Slanted"; + src: url("./assets/PPObjectSans-HeavySlanted.otf") format("opentype"); + font-weight: bold; + font-style: italic; +} + +* { + padding: 0; + margin: 0; + box-sizing: border-box; +} + +.column { + height: 100%; + position: relative; + padding: 10px; +} + +.top { + position: absolute; + top: 0; + padding-top: 10px; + padding-right: 10px; +} + +.bottom { + position: absolute; + bottom: 0; + padding-bottom: 10px; + padding-right: 10px; +} diff --git a/packages/create-mechanic/function-examples/adaptive-grid/function/utils.js b/packages/create-mechanic/function-examples/adaptive-grid/function/utils.js new file mode 100644 index 00000000..ac354dc7 --- /dev/null +++ b/packages/create-mechanic/function-examples/adaptive-grid/function/utils.js @@ -0,0 +1,36 @@ +export function getRandomColor() { + return ( + "#" + (0x1000000 + Math.random() * 0xffffff).toString(16).substring(1, 7) + ); +} + +export function getRandomInt(from, to) { + return Math.floor(from + Math.random() * (to - from)); +} + +export function getRandomSign() { + return 2 * Math.round(Math.random()) - 1; +} + +export function brightnessByColor(color) { + let r, g, b; + const isHEX = color.indexOf("#") === 0; + const isRGB = color.indexOf("rgb") === 0; + if (isHEX) { + const hasFullSpec = color.length === 7; + const m = color.substring(1).match(hasFullSpec ? /(\S{2})/g : /(\S{1})/g); + if (m) { + r = parseInt(m[0] + (hasFullSpec ? "" : m[0]), 16); + g = parseInt(m[1] + (hasFullSpec ? "" : m[1]), 16); + b = parseInt(m[2] + (hasFullSpec ? "" : m[2]), 16); + } + } else if (isRGB) { + const m = color.match(/(\d+){3}/g); + if (m) { + r = m[0]; + g = m[1]; + b = m[2]; + } + } + if (r) return (r * 299 + g * 587 + b * 114) / 1000; +} diff --git a/packages/create-mechanic/function-examples/adaptive-grid/inputs/group/index.js b/packages/create-mechanic/function-examples/adaptive-grid/inputs/group/index.js new file mode 100644 index 00000000..ee84687c --- /dev/null +++ b/packages/create-mechanic/function-examples/adaptive-grid/inputs/group/index.js @@ -0,0 +1,87 @@ +import React from "react"; +import { + BooleanInput, + NumberInput, + OptionInput, + ColorInput +} from "@mechanic-design/ui-components"; + +import * as css from "./style.module.css"; + +export const typeName = "groupToggle"; + +export const initValue = input => ({ + show: input.default, + ...Object.fromEntries( + Object.entries(input.inputs).map(([name, input]) => [name, input.default]) + ) +}); + +export const prepareValue = (value, input) => { + const v = + value === undefined || + value === null || + !Object.keys(input.inputs).every(k => value.hasOwnProperty(k)) + ? initValue(input) + : value; + return v; +}; + +export const Input = props => { + const { name, values, inputDef, onChange } = props; + const { show, ...value } = values[name] ?? initValue(inputDef); + + return ( +
+ onChange(e, name, { ...value, show: v })} + /> + {!show && ( + <> + {Object.entries(inputDef.inputs).map(([inputName, input], index) => + input.type === "number" ? ( + + onChange(e, name, { show, ...value, [inputName]: v }) + } + /> + ) : input.type === "color" ? ( + + onChange(e, name, { show, ...value, [inputName]: v }) + } + > + ) : ( + + onChange(e, name, { show, ...value, [inputName]: v }) + } + /> + ) + )} + + )} +
+ ); +}; diff --git a/packages/create-mechanic/function-examples/adaptive-grid/inputs/group/style.module.css b/packages/create-mechanic/function-examples/adaptive-grid/inputs/group/style.module.css new file mode 100644 index 00000000..4bb9fdfa --- /dev/null +++ b/packages/create-mechanic/function-examples/adaptive-grid/inputs/group/style.module.css @@ -0,0 +1,7 @@ +.root { + margin: 1em 0; +} + +.toggle { + margin: 1em 0; +} \ No newline at end of file diff --git a/packages/create-mechanic/function-examples/instagram-story-generator/assets/EULA-PangramPangram-FreeForPersonalUse-MAY2021.pdf b/packages/create-mechanic/function-examples/business-card-generator/function/assets/EULA-PangramPangram-FreeForPersonalUse-MAY2021.pdf similarity index 100% rename from packages/create-mechanic/function-examples/instagram-story-generator/assets/EULA-PangramPangram-FreeForPersonalUse-MAY2021.pdf rename to packages/create-mechanic/function-examples/business-card-generator/function/assets/EULA-PangramPangram-FreeForPersonalUse-MAY2021.pdf diff --git a/packages/create-mechanic/function-examples/instagram-story-generator/assets/PPObjectSans-Heavy.otf b/packages/create-mechanic/function-examples/business-card-generator/function/assets/PPObjectSans-Heavy.otf similarity index 100% rename from packages/create-mechanic/function-examples/instagram-story-generator/assets/PPObjectSans-Heavy.otf rename to packages/create-mechanic/function-examples/business-card-generator/function/assets/PPObjectSans-Heavy.otf diff --git a/packages/create-mechanic/function-examples/instagram-story-generator/assets/PPObjectSans-HeavySlanted.otf b/packages/create-mechanic/function-examples/business-card-generator/function/assets/PPObjectSans-HeavySlanted.otf similarity index 100% rename from packages/create-mechanic/function-examples/instagram-story-generator/assets/PPObjectSans-HeavySlanted.otf rename to packages/create-mechanic/function-examples/business-card-generator/function/assets/PPObjectSans-HeavySlanted.otf diff --git a/packages/create-mechanic/function-examples/instagram-story-generator/assets/PPObjectSans-Regular.otf b/packages/create-mechanic/function-examples/business-card-generator/function/assets/PPObjectSans-Regular.otf similarity index 100% rename from packages/create-mechanic/function-examples/instagram-story-generator/assets/PPObjectSans-Regular.otf rename to packages/create-mechanic/function-examples/business-card-generator/function/assets/PPObjectSans-Regular.otf diff --git a/packages/create-mechanic/function-examples/instagram-story-generator/assets/PPObjectSans-Slanted.otf b/packages/create-mechanic/function-examples/business-card-generator/function/assets/PPObjectSans-Slanted.otf similarity index 100% rename from packages/create-mechanic/function-examples/instagram-story-generator/assets/PPObjectSans-Slanted.otf rename to packages/create-mechanic/function-examples/business-card-generator/function/assets/PPObjectSans-Slanted.otf diff --git a/packages/create-mechanic/function-examples/business-card-generator/index.js b/packages/create-mechanic/function-examples/business-card-generator/function/index.js similarity index 100% rename from packages/create-mechanic/function-examples/business-card-generator/index.js rename to packages/create-mechanic/function-examples/business-card-generator/function/index.js diff --git a/packages/create-mechanic/function-examples/business-card-generator/styles.css b/packages/create-mechanic/function-examples/business-card-generator/function/styles.css similarity index 100% rename from packages/create-mechanic/function-examples/business-card-generator/styles.css rename to packages/create-mechanic/function-examples/business-card-generator/function/styles.css diff --git a/packages/create-mechanic/function-examples/index.js b/packages/create-mechanic/function-examples/index.js index c287427f..cf51188e 100644 --- a/packages/create-mechanic/function-examples/index.js +++ b/packages/create-mechanic/function-examples/index.js @@ -13,6 +13,11 @@ const options = [ name: "Poster Generator", type: "Canvas", dir: "poster-generator" + }, + { + name: "Adaptive Grid", + type: "Canvas", + dir: "adaptive-grid" } ]; diff --git a/packages/create-mechanic/function-examples/instagram-story-generator/Circle.js b/packages/create-mechanic/function-examples/instagram-story-generator/function/Circle.js similarity index 100% rename from packages/create-mechanic/function-examples/instagram-story-generator/Circle.js rename to packages/create-mechanic/function-examples/instagram-story-generator/function/Circle.js diff --git a/packages/create-mechanic/function-examples/poster-generator/assets/EULA-PangramPangram-FreeForPersonalUse-MAY2021.pdf b/packages/create-mechanic/function-examples/instagram-story-generator/function/assets/EULA-PangramPangram-FreeForPersonalUse-MAY2021.pdf similarity index 100% rename from packages/create-mechanic/function-examples/poster-generator/assets/EULA-PangramPangram-FreeForPersonalUse-MAY2021.pdf rename to packages/create-mechanic/function-examples/instagram-story-generator/function/assets/EULA-PangramPangram-FreeForPersonalUse-MAY2021.pdf diff --git a/packages/create-mechanic/function-examples/poster-generator/assets/PPObjectSans-Heavy.otf b/packages/create-mechanic/function-examples/instagram-story-generator/function/assets/PPObjectSans-Heavy.otf similarity index 100% rename from packages/create-mechanic/function-examples/poster-generator/assets/PPObjectSans-Heavy.otf rename to packages/create-mechanic/function-examples/instagram-story-generator/function/assets/PPObjectSans-Heavy.otf diff --git a/packages/create-mechanic/function-examples/poster-generator/assets/PPObjectSans-HeavySlanted.otf b/packages/create-mechanic/function-examples/instagram-story-generator/function/assets/PPObjectSans-HeavySlanted.otf similarity index 100% rename from packages/create-mechanic/function-examples/poster-generator/assets/PPObjectSans-HeavySlanted.otf rename to packages/create-mechanic/function-examples/instagram-story-generator/function/assets/PPObjectSans-HeavySlanted.otf diff --git a/packages/create-mechanic/function-examples/poster-generator/assets/PPObjectSans-Regular.otf b/packages/create-mechanic/function-examples/instagram-story-generator/function/assets/PPObjectSans-Regular.otf similarity index 100% rename from packages/create-mechanic/function-examples/poster-generator/assets/PPObjectSans-Regular.otf rename to packages/create-mechanic/function-examples/instagram-story-generator/function/assets/PPObjectSans-Regular.otf diff --git a/packages/create-mechanic/function-examples/instagram-story-generator/function/assets/PPObjectSans-Slanted.otf b/packages/create-mechanic/function-examples/instagram-story-generator/function/assets/PPObjectSans-Slanted.otf new file mode 100644 index 00000000..739f0d8e Binary files /dev/null and b/packages/create-mechanic/function-examples/instagram-story-generator/function/assets/PPObjectSans-Slanted.otf differ diff --git a/packages/create-mechanic/function-examples/instagram-story-generator/index.js b/packages/create-mechanic/function-examples/instagram-story-generator/function/index.js similarity index 100% rename from packages/create-mechanic/function-examples/instagram-story-generator/index.js rename to packages/create-mechanic/function-examples/instagram-story-generator/function/index.js diff --git a/packages/create-mechanic/function-examples/instagram-story-generator/styles.css b/packages/create-mechanic/function-examples/instagram-story-generator/function/styles.css similarity index 100% rename from packages/create-mechanic/function-examples/instagram-story-generator/styles.css rename to packages/create-mechanic/function-examples/instagram-story-generator/function/styles.css diff --git a/packages/create-mechanic/function-examples/instagram-story-generator/utils.js b/packages/create-mechanic/function-examples/instagram-story-generator/function/utils.js similarity index 100% rename from packages/create-mechanic/function-examples/instagram-story-generator/utils.js rename to packages/create-mechanic/function-examples/instagram-story-generator/function/utils.js diff --git a/packages/create-mechanic/function-examples/poster-generator/function/assets/EULA-PangramPangram-FreeForPersonalUse-MAY2021.pdf b/packages/create-mechanic/function-examples/poster-generator/function/assets/EULA-PangramPangram-FreeForPersonalUse-MAY2021.pdf new file mode 100644 index 00000000..7afcff96 Binary files /dev/null and b/packages/create-mechanic/function-examples/poster-generator/function/assets/EULA-PangramPangram-FreeForPersonalUse-MAY2021.pdf differ diff --git a/packages/create-mechanic/function-examples/poster-generator/function/assets/PPObjectSans-Heavy.otf b/packages/create-mechanic/function-examples/poster-generator/function/assets/PPObjectSans-Heavy.otf new file mode 100644 index 00000000..de186532 Binary files /dev/null and b/packages/create-mechanic/function-examples/poster-generator/function/assets/PPObjectSans-Heavy.otf differ diff --git a/packages/create-mechanic/function-examples/poster-generator/function/assets/PPObjectSans-HeavySlanted.otf b/packages/create-mechanic/function-examples/poster-generator/function/assets/PPObjectSans-HeavySlanted.otf new file mode 100644 index 00000000..247c2760 Binary files /dev/null and b/packages/create-mechanic/function-examples/poster-generator/function/assets/PPObjectSans-HeavySlanted.otf differ diff --git a/packages/create-mechanic/function-examples/poster-generator/function/assets/PPObjectSans-Regular.otf b/packages/create-mechanic/function-examples/poster-generator/function/assets/PPObjectSans-Regular.otf new file mode 100644 index 00000000..3e8b681c Binary files /dev/null and b/packages/create-mechanic/function-examples/poster-generator/function/assets/PPObjectSans-Regular.otf differ diff --git a/packages/create-mechanic/function-examples/poster-generator/index.js b/packages/create-mechanic/function-examples/poster-generator/function/index.js similarity index 100% rename from packages/create-mechanic/function-examples/poster-generator/index.js rename to packages/create-mechanic/function-examples/poster-generator/function/index.js diff --git a/packages/create-mechanic/function-examples/poster-generator/utils.js b/packages/create-mechanic/function-examples/poster-generator/function/utils.js similarity index 100% rename from packages/create-mechanic/function-examples/poster-generator/utils.js rename to packages/create-mechanic/function-examples/poster-generator/function/utils.js diff --git a/packages/create-mechanic/function-templates/canvas-image/index.js b/packages/create-mechanic/function-templates/canvas-image/function/index.js similarity index 100% rename from packages/create-mechanic/function-templates/canvas-image/index.js rename to packages/create-mechanic/function-templates/canvas-image/function/index.js diff --git a/packages/create-mechanic/function-templates/canvas-video/index.js b/packages/create-mechanic/function-templates/canvas-video/function/index.js similarity index 100% rename from packages/create-mechanic/function-templates/canvas-video/index.js rename to packages/create-mechanic/function-templates/canvas-video/function/index.js diff --git a/packages/create-mechanic/function-templates/d3-image/index.js b/packages/create-mechanic/function-templates/d3-image/function/index.js similarity index 100% rename from packages/create-mechanic/function-templates/d3-image/index.js rename to packages/create-mechanic/function-templates/d3-image/function/index.js diff --git a/packages/create-mechanic/function-templates/p5-image/index.js b/packages/create-mechanic/function-templates/p5-image/function/index.js similarity index 100% rename from packages/create-mechanic/function-templates/p5-image/index.js rename to packages/create-mechanic/function-templates/p5-image/function/index.js diff --git a/packages/create-mechanic/function-templates/p5-video/index.js b/packages/create-mechanic/function-templates/p5-video/function/index.js similarity index 100% rename from packages/create-mechanic/function-templates/p5-video/index.js rename to packages/create-mechanic/function-templates/p5-video/function/index.js diff --git a/packages/create-mechanic/function-templates/react-image/index.js b/packages/create-mechanic/function-templates/react-image/function/index.js similarity index 100% rename from packages/create-mechanic/function-templates/react-image/index.js rename to packages/create-mechanic/function-templates/react-image/function/index.js diff --git a/packages/create-mechanic/function-templates/react-video/index.js b/packages/create-mechanic/function-templates/react-video/function/index.js similarity index 100% rename from packages/create-mechanic/function-templates/react-video/index.js rename to packages/create-mechanic/function-templates/react-video/function/index.js diff --git a/packages/create-mechanic/function-templates/svg-image/index.js b/packages/create-mechanic/function-templates/svg-image/function/index.js similarity index 100% rename from packages/create-mechanic/function-templates/svg-image/index.js rename to packages/create-mechanic/function-templates/svg-image/function/index.js diff --git a/packages/create-mechanic/function-templates/svg-video/index.js b/packages/create-mechanic/function-templates/svg-video/function/index.js similarity index 100% rename from packages/create-mechanic/function-templates/svg-video/index.js rename to packages/create-mechanic/function-templates/svg-video/function/index.js diff --git a/packages/create-mechanic/function-templates/svgjs-image/index.js b/packages/create-mechanic/function-templates/svgjs-image/function/index.js similarity index 100% rename from packages/create-mechanic/function-templates/svgjs-image/index.js rename to packages/create-mechanic/function-templates/svgjs-image/function/index.js diff --git a/packages/create-mechanic/index.js b/packages/create-mechanic/index.js index 5edf0686..f0a191d1 100644 --- a/packages/create-mechanic/index.js +++ b/packages/create-mechanic/index.js @@ -12,6 +12,7 @@ const { installationMethodQuestion, generateProjectTemplate, installDependencies, + tryGitInit, checkLockFile } = require("./new-project"); const { @@ -106,6 +107,7 @@ const command = async argv => { const { confirmContinue } = await inquirer.prompt(confirmDFQuestion); await sleep(); if (confirmContinue) { + log(); log(content.designFunctionBasesDescription); } else { skipFunctions = true; @@ -149,6 +151,9 @@ const command = async argv => { // Install dependencies in new project directory const install = await askToInstall(projectName); + // Try initializing git repository + await tryGitInit(projectName); + // Done! log(content.doneAndNextStepsMessage(projectName, install)); log(content.bye); diff --git a/packages/create-mechanic/new-function.js b/packages/create-mechanic/new-function.js index 3247a199..5cc581a5 100644 --- a/packages/create-mechanic/new-function.js +++ b/packages/create-mechanic/new-function.js @@ -13,29 +13,42 @@ const log = console.log; // https://gist.github.com/lovasoa/8691344#gistcomment-3299018 const walk = (dir, fileCallback, directoryCallback) => { const files = fs.readdirSync(dir); + let wasSuccessful = true; files.forEach(file => { const filepath = path.join(dir, file); const stats = fs.statSync(filepath); if (stats.isDirectory()) { - directoryCallback(file, filepath, stats); - walk(filepath, fileCallback, directoryCallback); + const success = directoryCallback(file, filepath, stats); + if (wasSuccessful && !success) wasSuccessful = success; + if (success) { + wasSuccessful = walk(filepath, fileCallback, directoryCallback); + } } else if (stats.isFile()) { - fileCallback(file, filepath, stats); + const success = fileCallback(file, filepath, stats); + if (wasSuccessful && !success) wasSuccessful = success; } }); + return wasSuccessful; }; -const copyDirAndContents = (baseFunctionDir, newFunctionDir) => { +const copyDirAndContents = (originDir, targetDir) => { const copyFile = (_, filepath) => { - if (path.join(baseFunctionDir, "dependencies.json") === filepath) return; - const relativePath = path.relative(baseFunctionDir, filepath); - fs.copyFileSync(filepath, path.join(newFunctionDir, relativePath)); + const relativePath = path.relative(originDir, filepath); + const target = path.join(targetDir, relativePath); + if (!fs.pathExistsSync(target)) { + fs.copyFileSync(filepath, target); + return true; + } else return false; }; - const copyDir = (_, filepath) => { - const relativePath = path.relative(baseFunctionDir, filepath); - fs.mkdirSync(path.join(newFunctionDir, relativePath)); + const copyDir = (_, dirPath) => { + const relativePath = path.relative(originDir, dirPath); + const target = path.join(targetDir, relativePath); + if (!fs.pathExistsSync(target)) { + fs.mkdirSync(target); + return true; + } else return false; }; - walk(baseFunctionDir, copyFile, copyDir); + return walk(originDir, copyFile, copyDir); }; const baseExists = (typeOfBaseUsed, base) => { @@ -110,40 +123,49 @@ const generateFunctionTemplate = async ( spinner.start(content.generateFunctionStart); // Create design function folder - const directory = path.resolve(projectName); + const projectDir = path.resolve(projectName); + const projectPackagePath = path.join(projectDir, "package.json"); const newFunctionDir = path.join( - directory, + projectDir, config.functionsPath || "functions", functionName ); await fs.mkdir(newFunctionDir); // Path of template directory to copy - const baseFunctionDir = path.join( - __dirname, + const functionTypeDirectory = typeOfBaseUsed === "Template" ? "function-templates" : typeOfBaseUsed === "Example" ? "function-examples" - : "function-blank", + : "function-blank"; + + const functionDir = typeOfBaseUsed === "Template" ? functionTemplateOptions[base].dir : typeOfBaseUsed === "Example" ? functionExampleOptions[base].dir - : "" + : ""; + const baseFunctionDir = path.join( + __dirname, + functionTypeDirectory, + functionDir + ); + const functionSrcDir = path.join(baseFunctionDir, "function"); + const functionDependenciesPath = path.join( + baseFunctionDir, + "dependencies.json" ); + const inputsSrcDic = path.join(baseFunctionDir, "inputs"); // Add dependencies and copy basic files await Promise.all([ (async () => { const packageObj = JSON.parse( - await fs.readFile(path.join(directory, "package.json"), "utf8") + await fs.readFile(projectPackagePath, "utf8") ); const baseDependencies = JSON.parse( - await fs.readFile( - path.join(baseFunctionDir, "dependencies.json"), - "utf8" - ) + await fs.readFile(functionDependenciesPath, "utf8") ); // Add dependencies for (const depType in baseDependencies) { @@ -156,16 +178,39 @@ const generateFunctionTemplate = async ( } // Write the resulting package await fs.writeFile( - path.join(directory, "package.json"), + projectPackagePath, JSON.stringify(packageObj, null, 2) ); })() ]); + + // Add any custom inputs + const templateHasInputs = await fs.pathExists(inputsSrcDic); + const generatedCustomInputs = { tried: false, success: false }; + if (templateHasInputs) { + const projectInputDir = path.join(projectDir, "inputs"); + const projectInputDirExists = await fs.pathExists(projectInputDir); + if (!projectInputDirExists) { + await fs.mkdir(projectInputDir); + } + + const copiedEverything = copyDirAndContents(inputsSrcDic, projectInputDir); + generatedCustomInputs.tried = true; + generatedCustomInputs.success = copiedEverything; + } + // Copy all files in base dir - copyDirAndContents(baseFunctionDir, newFunctionDir); + copyDirAndContents(functionSrcDir, newFunctionDir); spinner.succeed(content.generateFunctionSuccess(functionName)); - log(content.functionCreationDetails(functionName)); + log(); + log( + content.functionCreationDetails( + { functionName, functionTypeDirectory, functionDir }, + generatedCustomInputs + ) + ); + return newFunctionDir; }; diff --git a/packages/create-mechanic/new-project.js b/packages/create-mechanic/new-project.js index b2176e46..35f1cbd7 100644 --- a/packages/create-mechanic/new-project.js +++ b/packages/create-mechanic/new-project.js @@ -63,7 +63,7 @@ const generateProjectTemplate = async (projectName, typeOfBaseUsed) => { // Copying content promises await Promise.all([ // Copy array of files that get duplicated without change - ...["mechanic.config.js", "README.md"].map(filename => + ...["mechanic.config.js", "README.md", "_gitignore"].map(filename => fs.copyFile( path.join(projectTemplateDir, filename), path.join(directory, filename.replace(/^_/, ".")) @@ -88,6 +88,7 @@ const generateProjectTemplate = async (projectName, typeOfBaseUsed) => { ]); spinner.succeed(content.generateProjectSuccess(typeOfBaseUsed, projectName)); + log(); log(content.projectContents(path.dirname(directory))); }; @@ -110,6 +111,17 @@ const installDependencies = async (projectName, installingMethod) => { // Project directory const cwd = path.resolve(projectName); + // List out dependencies being installed + const packageJsonPath = path.join(cwd, "package.json"); + const packageObj = JSON.parse(await fs.readFile(packageJsonPath, "utf8")); + log(content.installingDependenciesMessage); + for (const depType of ["devDependencies", "dependencies"]) { + for (const dep in packageObj[depType]) { + log(content.dependencyItem(dep)); + } + } + log(); + try { spinner.start(content.installTry(installingMethod)); // Install @@ -126,6 +138,59 @@ const installDependencies = async (projectName, installingMethod) => { } }; +async function isInGitRepository(cwd) { + try { + await execa("git", ["rev-parse", "--is-inside-work-tree"], { cwd }); + return true; + } catch (_) {} + return false; +} + +async function isInMercurialRepository(cwd) { + try { + await execa("hg", ["--cwd", ".", "root"], { cwd }); + return true; + } catch (_) {} + return false; +} + +// Adaptation of https://github.com/vercel/next.js/blob/canary/packages/create-next-app/helpers/git.ts +const tryGitInit = async projectName => { + // Project directory + const cwd = path.resolve(projectName); + let didInit = false; + try { + await execa("git", ["--version"], { cwd }); + if ( + (await isInGitRepository(cwd)) || + (await isInMercurialRepository(cwd)) + ) { + return false; + } + + await execa("git", ["init"], { cwd }); + didInit = true; + + await execa("git", ["checkout", "-b", "main"], { cwd }); + + await execa("git", ["add", "-A"], { cwd }); + await execa( + "git", + ["commit", "-m", "Initial commit from Create Mechanic"], + { cwd } + ); + + return true; + } catch (e) { + if (didInit) { + try { + fs.rmSync(path.join(cwd, ".git")); + } catch (_) {} + } + return false; + } +}; + module.exports = { getProjectQuestion, confirmDFQuestion, @@ -133,5 +198,6 @@ module.exports = { installationMethodQuestion, generateProjectTemplate, checkLockFile, - installDependencies + installDependencies, + tryGitInit }; diff --git a/packages/create-mechanic/project-template/_gitignore b/packages/create-mechanic/project-template/_gitignore index e69de29b..5c787228 100644 --- a/packages/create-mechanic/project-template/_gitignore +++ b/packages/create-mechanic/project-template/_gitignore @@ -0,0 +1,15 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules + +# production +/dist + +# misc +.DS_Store + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/create-mechanic/script-content.js b/packages/create-mechanic/script-content.js index ccc220b4..ce97f4ba 100644 --- a/packages/create-mechanic/script-content.js +++ b/packages/create-mechanic/script-content.js @@ -1,9 +1,11 @@ const { logo: { mechanic, mechanicInverse }, - colors: { success, bgRed, bgBlue } + colors: { success, bgRed, bgBlue, fail } } = require("@mechanic-design/utils"); const mechanicPackage = "@mechanic-design/core"; +const sourceCodeUrl = "https://github.com/designsystemsinternational/mechanic"; +const sourceCodeMainBranchUrl = `${sourceCodeUrl}/tree/main`; module.exports = { welcome: `${mechanic} @@ -81,7 +83,10 @@ ${bgBlue( generateFunctionStart: "Adding design function to project...", generateFunctionSuccess: functionName => `Design function "${functionName}" added to project!`, - functionCreationDetails: functionName => + functionCreationDetails: ( + { functionName, functionDir, functionTypeDirectory }, + customInputGeneration + ) => `This just: > Created a folder inside functions/, called ${success( functionName @@ -89,13 +94,31 @@ ${bgBlue( "index.js" )} file where the design function is defined. > Added some other dependencies into your project to make your design function work. - -`, +${ + customInputGeneration.tried + ? customInputGeneration.success + ? "> Added a custom input used in the function. You can find it in the " + + success("inputs/") + + " folder \n" + : "> " + + fail("Tried") + + " adding a needed custom input, but it wasn't possible. " + + "Check " + + `${sourceCodeMainBranchUrl}/packages/create-mechanic/${functionTypeDirectory}${ + functionDir !== "" ? "/" + functionDir : "" + }/inputs for the input's source code.\n` + : "" +}`, confirmInstallQuestion: "Do you wish to install dependencies for your project right away?", installationMethodQuestion: "Do you wish to install dependencies using npm or yarn?", + installingDependenciesMessage: "\nDependencies to install:", + dependencyItem: dep => + !dep.includes("@mechanic-design") + ? `- ${dep}` + : `- ${bgRed("@mechanic-design")}/${bgBlue(dep.split("/")[1])}`, installTry: method => `Trying with ${method}.`, installSucceed: method => `Installed dependencies with ${method}.`, installFailed: method =>