diff --git a/.gitignore b/.gitignore index b512c09..55371e5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -node_modules \ No newline at end of file +node_modules +.vscode \ No newline at end of file diff --git a/calculate.js b/calculate.js deleted file mode 100644 index 5fd3968..0000000 --- a/calculate.js +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @param {type} name - */ - -//params -const lines_per_field = 2 -// const lines_per_gutter = 0 -const rows = document.getElementById('rows').value -const columns = document.getElementById('columns').value -const box_height = 21.897 // calculate -const box_width = 678.858 // calculate -const h_text = 7.084 // measure?? - -//calcs -const lines = lines_per_field * rows + lines_per_gutter * (rows - 1) -const total_text = h_text * lines -const per_line_spacing = (box_height - total_text) / (lines - 1) - -//output -function getLeading() { - return per_line_spacing + h_text -} -const leading = getLeading() -const h_gutter = 2 * per_line_spacing + h_text -const h_field = (box_height - h_gutter * (rows - 1)) / rows -const v_gutter = (box_width - columns * h_field) / (columns - 1) - -window.onload = function() { - let c = document.getElementById("textDatum"); - let ctx = c.getContext("2d"); - - ctx.font = "18px Futura"; - - let fM = ctx.measureText("A"); // a character with the maximum height - let txtH = fM.actualBoundingBoxAscent + fM.actualBoundingBoxDescent; - - ctx.fillText("Height: " + txtH, 5, 80); -} diff --git a/index.css b/index.css deleted file mode 100644 index fa83d7b..0000000 --- a/index.css +++ /dev/null @@ -1,175 +0,0 @@ -:root { - --white: #fff; - --black: #000; - - /* Primary colors*/ - --primary-1: #2b8379; - --primary-2: #19a596; - --primary-3: #7fd1c7; - --primary-4: #7fd1c7; - --primary-5: #d0f3ef; - - /* Neutral colors */ - --neutral-1: #121212; - --neutral-2: #434343; - --neutral-3: #94868b; - --neutral-4: #d9cfd3; - --neutral-5: #f2ecee; - - /* Accent-blue colors */ - --accent-1: #970e3d; - --accent-2: #c43464; - --accent-3: #de7699; - --accent-4: #e6c3ce; - --accent-5: #fff2f7; - } - - .grid-container { - display: grid; - grid-template-columns: auto auto auto auto; - grid-gap: 10px; - } - - .header { - padding: 10px; - } - - .main { - grid-column: 2 / span 3; - } - - .sidebar { - grid-column: 1 / span 1; - } - - #page { - width: auto; - height: auto; - border: var(--neutral-5) solid 1px; - } - - body { - background-color: var(--neutral-1); - font-family: Helvetica, sans-serif; - color: white; - } - - h1 { - font-family: Helvetica, sans-serif; - font-size: 36px; - font-weight: 600; - } - - h2 { - font-size: 20px; - font-weight: 500; - } - - h3 { - font-size: 24px; - font-weight: normal; - } - - p { - line-height: 30px; - font-size: 18px; - } - - a { - color: var(--primary-2); - font-weight: bold; - text-decoration: none; - } - a:hover { - text-decoration: underline; - } - - .rounded { - border-radius: 30px; - } - - .container { - max-width: 900px; - margin: 0 auto; - padding: 0 20px; - } - - - /* FORMS */ - .form h2 { - font-size: 24px; - font-weight: 400; - } - - .form h3 { - font-size: 20px; - font-weight: 300; - margin-bottom: 15px; - } - - .form-group { - background-color: var(--neutral-2); - padding: 5px; - } - - .input-required { - color: var(--primary-2); - text-decoration: none; - font-weight: bold; - padding: 0 1px; - } - - .label { - /* display: block; */ - font-size: 10px; - font-weight: 500; - } - - .input { - font-size: 10px; - margin-top: 1em; - margin-bottom: 1.5em; - padding: 0.75em 0.5em; - /* min-width: 200px; */ - border: none; - /* border-left: 7px solid var(--neutral-4); */ - /* transition: border-left-color 160ms; */ - /* background-color: white; */ - /* width: 100%; */ - } - - ::placeholder { - color: var(--neutral-3); - } - - input:not(.btn):focus { - outline: hidden; - border-left: 7px solid var(--primary-1); - } - - /* NAVBAR */ - .navbar { - background-color: white; - padding: 10px; - box-shadow: 0px 3px 7px 1px rgba(0, 0, 0, 0.07), - 0px -3px 7px 1px rgba(0, 0, 0, 0.07); - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 20px; - } - - .nav-brand { - font-weight: 450; - text-decoration: none; - padding-left: 20px; - margin-top: 15px; - margin-bottom: 15px; - color: initial; - } - - select { - padding: 10px 15px; - border-radius: 8px; - } - \ No newline at end of file diff --git a/index.html b/index.html deleted file mode 100644 index 9ff42a3..0000000 --- a/index.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - - Grids - - Grids - - -
-

Grids

-

Proportional Grid & Typesetting

-
-
- -
-
- -
-
- - diff --git a/package-lock.json b/package-lock.json index 9bc2c2c..80ffe9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,16 +9,30 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "bootstrap": "^5.1.3" + "bootstrap": "^5.1.3", + "font-picker": "^3.5.1", + "modules": "^0.4.0", + "node": "^21.6.1" }, "devDependencies": { "electron": "^17.4.7" } }, + "node_modules/@babel/runtime": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@electron/get": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.13.1.tgz", - "integrity": "sha512-U5vkXDZ9DwXtkPqlB45tfYnnYBN8PePp1z/XDCupnSpdrxT8/ThCv9WCwPLf9oqiSGZTkH6dx2jDUPuoXpjkcA==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.14.1.tgz", + "integrity": "sha512-BrZYyL/6m0ZXz/lDxy/nlVhQz+WF+iPS6qXolEU8atw7h6v1aYkjwJZ63m+bJMBTxDE66X+r2tPS4a/8C82sZw==", "dev": true, "dependencies": { "debug": "^4.1.1", @@ -47,6 +61,14 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@samuelmeuli/font-manager": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@samuelmeuli/font-manager/-/font-manager-1.4.0.tgz", + "integrity": "sha512-TaPoX4qA6ABrACiSI18lQOOKjvbLNrT+84UWfzwcguWQ4nT+sprOSRyt/RVXnt9fQp/wFQVC2NcHbzd+AkXffg==", + "dependencies": { + "@babel/runtime": "^7.7.4" + } + }, "node_modules/@sindresorhus/is": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", @@ -253,9 +275,9 @@ "dev": true }, "node_modules/electron": { - "version": "17.4.7", - "resolved": "https://registry.npmjs.org/electron/-/electron-17.4.7.tgz", - "integrity": "sha512-CMdUpd6oEwqbF7wcXwy9VNNXfTTbaeRg+zrGZciPzyzsEmJ9vzWcR1WpOxIQ4sIMjUyo1pFbvaD0VOgI2t4x3A==", + "version": "17.4.11", + "resolved": "https://registry.npmjs.org/electron/-/electron-17.4.11.tgz", + "integrity": "sha512-mdSWM2iY/Bh5bKzd5drYS3mf8JWyR9P9UXZA2uLEZ+1fhgLEVkY9qu501QHoMsKlNwgn96EreQC+dfdQ75VTcA==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -357,6 +379,14 @@ "pend": "~1.2.0" } }, + "node_modules/font-picker": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/font-picker/-/font-picker-3.5.1.tgz", + "integrity": "sha512-WhxgbjZB/pnpk9okPWLLpZFlzpszfqvWH1ZodEzXF4cbVnhkKX+m1Bi05KdlbV1R14FN6iIrAaBn1YW7xXhgMA==", + "dependencies": { + "@samuelmeuli/font-manager": "^1.4.0" + } + }, "node_modules/fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -402,9 +432,9 @@ } }, "node_modules/global-agent/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dev": true, "optional": true, "dependencies": { @@ -478,9 +508,9 @@ "dev": true }, "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, "node_modules/inherits": { @@ -585,10 +615,13 @@ } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/mkdirp": { "version": "0.5.5", @@ -602,12 +635,40 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/modules": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/modules/-/modules-0.4.0.tgz", + "integrity": "sha512-LX4JgwPHJr1FurPDKp1BlGgMXqZXtxO1O8ABGmj2g15CbLGlInTHcA9flqw6uN6oYKE2T0ngWdiHvcX97mdBsw==", + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/node": { + "version": "21.6.1", + "resolved": "https://registry.npmjs.org/node/-/node-21.6.1.tgz", + "integrity": "sha512-cTqZk0/Wl6qeVcftyriVhHGFw1xvXl9o8TPI/qLcoVKh6X1dDKJGVi+EbhUg6864+KoDBnEaVxre59W8r8cLcA==", + "hasInstallScript": true, + "dependencies": { + "node-bin-setup": "^1.0.0" + }, + "bin": { + "node": "bin/node" + }, + "engines": { + "npm": ">=5.0.0" + } + }, + "node_modules/node-bin-setup": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/node-bin-setup/-/node-bin-setup-1.1.3.tgz", + "integrity": "sha512-opgw9iSCAzT2+6wJOETCpeRYAQxSopqQ2z+N6BXwIMsQQ7Zj5M8MaafQY8JMlolRR6R1UXg2WmhKp0p9lSOivg==" + }, "node_modules/normalize-url": { "version": "4.5.1", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", @@ -731,6 +792,11 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, "node_modules/responselike": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", @@ -765,9 +831,9 @@ "dev": true }, "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -914,10 +980,18 @@ } }, "dependencies": { + "@babel/runtime": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", + "requires": { + "regenerator-runtime": "^0.14.0" + } + }, "@electron/get": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.13.1.tgz", - "integrity": "sha512-U5vkXDZ9DwXtkPqlB45tfYnnYBN8PePp1z/XDCupnSpdrxT8/ThCv9WCwPLf9oqiSGZTkH6dx2jDUPuoXpjkcA==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.14.1.tgz", + "integrity": "sha512-BrZYyL/6m0ZXz/lDxy/nlVhQz+WF+iPS6qXolEU8atw7h6v1aYkjwJZ63m+bJMBTxDE66X+r2tPS4a/8C82sZw==", "dev": true, "requires": { "debug": "^4.1.1", @@ -937,6 +1011,14 @@ "integrity": "sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==", "peer": true }, + "@samuelmeuli/font-manager": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@samuelmeuli/font-manager/-/font-manager-1.4.0.tgz", + "integrity": "sha512-TaPoX4qA6ABrACiSI18lQOOKjvbLNrT+84UWfzwcguWQ4nT+sprOSRyt/RVXnt9fQp/wFQVC2NcHbzd+AkXffg==", + "requires": { + "@babel/runtime": "^7.7.4" + } + }, "@sindresorhus/is": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", @@ -1101,9 +1183,9 @@ "dev": true }, "electron": { - "version": "17.4.7", - "resolved": "https://registry.npmjs.org/electron/-/electron-17.4.7.tgz", - "integrity": "sha512-CMdUpd6oEwqbF7wcXwy9VNNXfTTbaeRg+zrGZciPzyzsEmJ9vzWcR1WpOxIQ4sIMjUyo1pFbvaD0VOgI2t4x3A==", + "version": "17.4.11", + "resolved": "https://registry.npmjs.org/electron/-/electron-17.4.11.tgz", + "integrity": "sha512-mdSWM2iY/Bh5bKzd5drYS3mf8JWyR9P9UXZA2uLEZ+1fhgLEVkY9qu501QHoMsKlNwgn96EreQC+dfdQ75VTcA==", "dev": true, "requires": { "@electron/get": "^1.13.0", @@ -1185,6 +1267,14 @@ "pend": "~1.2.0" } }, + "font-picker": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/font-picker/-/font-picker-3.5.1.tgz", + "integrity": "sha512-WhxgbjZB/pnpk9okPWLLpZFlzpszfqvWH1ZodEzXF4cbVnhkKX+m1Bi05KdlbV1R14FN6iIrAaBn1YW7xXhgMA==", + "requires": { + "@samuelmeuli/font-manager": "^1.4.0" + } + }, "fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -1221,9 +1311,9 @@ }, "dependencies": { "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dev": true, "optional": true, "requires": { @@ -1281,9 +1371,9 @@ "dev": true }, "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, "inherits": { @@ -1376,9 +1466,9 @@ "dev": true }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true }, "mkdirp": { @@ -1390,12 +1480,30 @@ "minimist": "^1.2.5" } }, + "modules": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/modules/-/modules-0.4.0.tgz", + "integrity": "sha512-LX4JgwPHJr1FurPDKp1BlGgMXqZXtxO1O8ABGmj2g15CbLGlInTHcA9flqw6uN6oYKE2T0ngWdiHvcX97mdBsw==" + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node": { + "version": "21.6.1", + "resolved": "https://registry.npmjs.org/node/-/node-21.6.1.tgz", + "integrity": "sha512-cTqZk0/Wl6qeVcftyriVhHGFw1xvXl9o8TPI/qLcoVKh6X1dDKJGVi+EbhUg6864+KoDBnEaVxre59W8r8cLcA==", + "requires": { + "node-bin-setup": "^1.0.0" + } + }, + "node-bin-setup": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/node-bin-setup/-/node-bin-setup-1.1.3.tgz", + "integrity": "sha512-opgw9iSCAzT2+6wJOETCpeRYAQxSopqQ2z+N6BXwIMsQQ7Zj5M8MaafQY8JMlolRR6R1UXg2WmhKp0p9lSOivg==" + }, "normalize-url": { "version": "4.5.1", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", @@ -1498,6 +1606,11 @@ "util-deprecate": "~1.0.1" } }, + "regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, "responselike": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", @@ -1529,9 +1642,9 @@ "dev": true }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true }, "semver-compare": { diff --git a/package.json b/package.json index 163e442..0eb66bc 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "grids", "version": "1.0.0", "description": "Proportional Grid Generator", - "main": "main.js", + "main": "./src/index.js", "scripts": { "start": "electron .", "test": "echo \"Error: no test specified\" && exit 1" @@ -22,6 +22,9 @@ "electron": "^17.4.7" }, "dependencies": { - "bootstrap": "^5.1.3" + "bootstrap": "^5.1.3", + "font-picker": "^3.5.1", + "modules": "^0.4.0", + "node": "^21.6.1" } } diff --git a/src/FontPicker.js b/src/FontPicker.js new file mode 100755 index 0000000..e574fd9 --- /dev/null +++ b/src/FontPicker.js @@ -0,0 +1,642 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = global || self, global.FontPicker = factory()); + }(this, (function () { 'use strict'; + + /*! ***************************************************************************** + Copyright (c) Microsoft Corporation. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use + this file except in compliance with the License. You may obtain a copy of the + License at http://www.apache.org/licenses/LICENSE-2.0 + + THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED + WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, + MERCHANTABLITY OR NON-INFRINGEMENT. + + See the Apache Version 2.0 License for specific language governing permissions + and limitations under the License. + ***************************************************************************** */ + + var __assign = function() { + __assign = Object.assign || function __assign(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); + }; + + function __rest(s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) + t[p[i]] = s[p[i]]; + } + return t; + } + + function __awaiter(thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); + } + + function __generator(thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } + } + + function styleInject(css, ref) { + if ( ref === void 0 ) ref = {}; + var insertAt = ref.insertAt; + + if (!css || typeof document === 'undefined') { return; } + + var head = document.head || document.getElementsByTagName('head')[0]; + var style = document.createElement('style'); + style.type = 'text/css'; + + if (insertAt === 'top') { + if (head.firstChild) { + head.insertBefore(style, head.firstChild); + } else { + head.appendChild(style); + } + } else { + head.appendChild(style); + } + + if (style.styleSheet) { + style.styleSheet.cssText = css; + } else { + style.appendChild(document.createTextNode(css)); + } + } + + var css = "@charset \"UTF-8\";\ndiv[id^=font-picker] {\n position: relative;\n display: inline-block;\n width: 200px;\n box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.2);\n}\ndiv[id^=font-picker] * {\n box-sizing: border-box;\n}\ndiv[id^=font-picker] p {\n margin: 0;\n padding: 0;\n}\ndiv[id^=font-picker] button {\n color: inherit;\n font-size: inherit;\n background: none;\n border: 0;\n outline: none;\n cursor: pointer;\n}\ndiv[id^=font-picker] .dropdown-button {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n height: 35px;\n padding: 0 10px;\n background: #cbcbcb;\n}\ndiv[id^=font-picker] .dropdown-button:hover, div[id^=font-picker] .dropdown-button:focus {\n background: #bebebe;\n}\ndiv[id^=font-picker] .dropdown-button .dropdown-font-name {\n overflow: hidden;\n white-space: nowrap;\n}\ndiv[id^=font-picker] .dropdown-icon {\n margin-left: 10px;\n}\n@-webkit-keyframes spinner {\n to {\n transform: rotate(360deg);\n }\n}\n@keyframes spinner {\n to {\n transform: rotate(360deg);\n }\n}\ndiv[id^=font-picker] .dropdown-icon.loading::before {\n display: block;\n width: 10px;\n height: 10px;\n border: 2px solid #b2b2b2;\n border-top-color: #000000;\n border-radius: 50%;\n -webkit-animation: spinner 0.6s linear infinite;\n animation: spinner 0.6s linear infinite;\n content: \"\";\n}\ndiv[id^=font-picker] .dropdown-icon.finished::before {\n display: block;\n width: 0;\n height: 0;\n margin: 0 2px;\n border-top: 6px solid #000000;\n border-right: 5px solid transparent;\n border-left: 5px solid transparent;\n transition: transform 0.3s;\n content: \"\";\n}\ndiv[id^=font-picker] .dropdown-icon.error::before {\n content: \"⚠\";\n}\ndiv[id^=font-picker].expanded .dropdown-icon.finished::before {\n transform: rotate(-180deg);\n}\ndiv[id^=font-picker].expanded ul {\n max-height: 200px;\n}\ndiv[id^=font-picker] ul {\n position: absolute;\n z-index: 1;\n width: 100%;\n max-height: 0;\n margin: 0;\n padding: 0;\n overflow-x: hidden;\n overflow-y: auto;\n background: #eaeaea;\n box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.2);\n transition: 0.3s;\n -webkit-overflow-scrolling: touch;\n}\ndiv[id^=font-picker] ul li {\n height: 35px;\n list-style: none;\n}\ndiv[id^=font-picker] ul li button {\n display: flex;\n align-items: center;\n width: 100%;\n height: 100%;\n padding: 0 10px;\n white-space: nowrap;\n}\ndiv[id^=font-picker] ul li button:hover, div[id^=font-picker] ul li button:focus {\n background: #dddddd;\n}\ndiv[id^=font-picker] ul li button.active-font {\n background: #d1d1d1;\n}"; + styleInject(css); + + function getFontId(fontFamily) { + return fontFamily.replace(/\s+/g, "-").toLowerCase(); + } + function validatePickerId(pickerId) { + if (pickerId.match(/[^0-9a-z]/i)) { + throw Error("The `pickerId` parameter may only contain letters and digits"); + } + } + + function get(url) { + return new Promise(function (resolve, reject) { + var request = new XMLHttpRequest(); + request.overrideMimeType("application/json"); + request.open("GET", url, true); + request.onreadystatechange = function () { + if (request.readyState === 4) { + if (request.status !== 200) { + reject(new Error("Response has status code " + request.status)); + } + else { + resolve(request.responseText); + } + } + }; + request.send(); + }); + } + + var LIST_BASE_URL = "https://www.googleapis.com/webfonts/v1/webfonts"; + function getFontList(apiKey) { + return __awaiter(this, void 0, void 0, function () { + var url, response, json, fontsOriginal; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = new URL(LIST_BASE_URL); + url.searchParams.append("sort", "popularity"); + url.searchParams.append("key", apiKey); + return [4, get(url.href)]; + case 1: + response = _a.sent(); + json = JSON.parse(response); + fontsOriginal = json.items; + return [2, fontsOriginal.map(function (fontOriginal) { + var family = fontOriginal.family, subsets = fontOriginal.subsets, others = __rest(fontOriginal, ["family", "subsets"]); + return __assign(__assign({}, others), { family: family, id: getFontId(family), scripts: subsets }); + })]; + } + }); + }); + } + + var previewFontsStylesheet = document.createElement("style"); + document.head.appendChild(previewFontsStylesheet); + function applyFontPreview(previewFont, selectorSuffix) { + var fontId = getFontId(previewFont.family); + var style = "\n\t\t\t#font-button-" + fontId + selectorSuffix + " {\n\t\t\t\tfont-family: \"" + previewFont.family + "\";\n\t\t\t}\n\t\t"; + previewFontsStylesheet.appendChild(document.createTextNode(style)); + } + function getActiveFontStylesheet(selectorSuffix) { + var stylesheetId = "active-font-" + selectorSuffix; + var activeFontStylesheet = document.getElementById(stylesheetId); + if (!activeFontStylesheet) { + activeFontStylesheet = document.createElement("style"); + activeFontStylesheet.id = stylesheetId; + document.head.appendChild(activeFontStylesheet); + } + return activeFontStylesheet; + } + function applyActiveFont(activeFont, previousFontFamily, selectorSuffix) { + var style = "\n\t\t.apply-font" + selectorSuffix + " {\n\t\t\tfont-family: \"" + activeFont.family + "\"" + (previousFontFamily ? ", \"" + previousFontFamily + "\"" : "") + ";\n\t\t}\n\t"; + var activeFontStylesheet = getActiveFontStylesheet(selectorSuffix); + activeFontStylesheet.innerHTML = style; + } + + var PREVIEW_ATTRIBUTE_NAME = "data-is-preview"; + function getStylesheetId(fontId) { + return "font-" + fontId; + } + function stylesheetExists(fontId, isPreview) { + var stylesheetNode = document.getElementById(getStylesheetId(fontId)); + if (isPreview === null || isPreview === undefined) { + return stylesheetNode !== null; + } + return (stylesheetNode !== null && + stylesheetNode.getAttribute(PREVIEW_ATTRIBUTE_NAME) === isPreview.toString()); + } + function createStylesheet(fontId, isPreview) { + var stylesheetNode = document.createElement("style"); + stylesheetNode.id = getStylesheetId(fontId); + stylesheetNode.setAttribute(PREVIEW_ATTRIBUTE_NAME, isPreview.toString()); + document.head.appendChild(stylesheetNode); + } + function fillStylesheet(fontId, styles) { + var stylesheetId = getStylesheetId(fontId); + var stylesheetNode = document.getElementById(stylesheetId); + if (stylesheetNode) { + stylesheetNode.textContent = styles; + } + else { + console.error("Could not fill stylesheet: Stylesheet with ID \"" + stylesheetId + "\" not found"); + } + } + function setStylesheetType(fontId, isPreview) { + var stylesheetId = getStylesheetId(fontId); + var stylesheetNode = document.getElementById(stylesheetId); + if (stylesheetNode) { + stylesheetNode.setAttribute(PREVIEW_ATTRIBUTE_NAME, isPreview.toString()); + } + else { + console.error("Could not change stylesheet type: Stylesheet with ID \"" + stylesheetId + "\" not found"); + } + } + + function getMatches(regex, str) { + var matches = []; + var match; + do { + match = regex.exec(str); + if (match) { + matches.push(match[1]); + } + } while (match); + return matches; + } + + var FONT_FACE_REGEX = /@font-face {([\s\S]*?)}/gm; + var FONT_FAMILY_REGEX = /font-family: ['"](.*?)['"]/gm; + function extractFontStyles(allFontStyles) { + var rules = getMatches(FONT_FACE_REGEX, allFontStyles); + var fontStyles = {}; + rules.forEach(function (rule) { + var fontFamily = getMatches(FONT_FAMILY_REGEX, rule)[0]; + var fontId = getFontId(fontFamily); + if (!(fontId in fontStyles)) { + fontStyles[fontId] = ""; + } + fontStyles[fontId] += "@font-face {\n" + rule + "\n}\n\n"; + }); + return fontStyles; + } + + var FONT_BASE_URL = "https://fonts.googleapis.com/css"; + function getStylesheet(fonts, scripts, variants, previewsOnly) { + return __awaiter(this, void 0, void 0, function () { + var url, variantsStr, familiesStr, familyNamesConcat, downloadChars; + return __generator(this, function (_a) { + url = new URL(FONT_BASE_URL); + variantsStr = variants.join(","); + familiesStr = fonts.map(function (font) { return font.family + ":" + variantsStr; }); + url.searchParams.append("family", familiesStr.join("|")); + url.searchParams.append("subset", scripts.join(",")); + if (previewsOnly) { + familyNamesConcat = fonts.map(function (font) { return font.family; }).join(""); + downloadChars = familyNamesConcat + .split("") + .filter(function (char, pos, self) { return self.indexOf(char) === pos; }) + .join(""); + url.searchParams.append("text", downloadChars); + } + url.searchParams.append("font-display", "swap"); + return [2, get(url.href)]; + }); + }); + } + + function loadFontPreviews(fonts, scripts, variants, selectorSuffix) { + return __awaiter(this, void 0, void 0, function () { + var fontsArray, fontsToFetch, response, fontStyles; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + fontsArray = Array.from(fonts.values()); + fontsToFetch = fontsArray + .map(function (font) { return font.id; }) + .filter(function (fontId) { return !stylesheetExists(fontId); }); + fontsToFetch.forEach(function (fontId) { return createStylesheet(fontId, true); }); + return [4, getStylesheet(fontsArray, scripts, variants, true)]; + case 1: + response = _a.sent(); + fontStyles = extractFontStyles(response); + fontsArray.forEach(function (font) { + applyFontPreview(font, selectorSuffix); + if (fontsToFetch.includes(font.id)) { + if (!(font.id in fontStyles)) { + console.error("Missing styles for font \"" + font.family + "\" (fontId \"" + font.id + "\") in Google Fonts response"); + return; + } + fillStylesheet(font.id, fontStyles[font.id]); + } + }); + return [2]; + } + }); + }); + } + function loadActiveFont(font, previousFontFamily, scripts, variants, selectorSuffix) { + return __awaiter(this, void 0, void 0, function () { + var fontStyle; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!stylesheetExists(font.id, false)) return [3, 1]; + applyActiveFont(font, previousFontFamily, selectorSuffix); + return [3, 3]; + case 1: + if (stylesheetExists(font.id, true)) { + setStylesheetType(font.id, false); + } + else { + createStylesheet(font.id, false); + } + return [4, getStylesheet([font], scripts, variants, false)]; + case 2: + fontStyle = _a.sent(); + applyActiveFont(font, previousFontFamily, selectorSuffix); + fillStylesheet(font.id, fontStyle); + _a.label = 3; + case 3: return [2]; + } + }); + }); + } + + var FONT_FAMILY_DEFAULT = "Open Sans"; + var OPTIONS_DEFAULTS = { + pickerId: "", + families: [], + categories: [], + scripts: ["latin"], + variants: ["regular"], + filter: function () { return true; }, + limit: 50, + sort: "alphabet", + }; + + var FontManager = (function () { + function FontManager(apiKey, defaultFamily, _a, onChange) { + if (defaultFamily === void 0) { defaultFamily = FONT_FAMILY_DEFAULT; } + var _b = _a.pickerId, pickerId = _b === void 0 ? OPTIONS_DEFAULTS.pickerId : _b, _c = _a.families, families = _c === void 0 ? OPTIONS_DEFAULTS.families : _c, _d = _a.categories, categories = _d === void 0 ? OPTIONS_DEFAULTS.categories : _d, _e = _a.scripts, scripts = _e === void 0 ? OPTIONS_DEFAULTS.scripts : _e, _f = _a.variants, variants = _f === void 0 ? OPTIONS_DEFAULTS.variants : _f, _g = _a.filter, filter = _g === void 0 ? OPTIONS_DEFAULTS.filter : _g, _h = _a.limit, limit = _h === void 0 ? OPTIONS_DEFAULTS.limit : _h, _j = _a.sort, sort = _j === void 0 ? OPTIONS_DEFAULTS.sort : _j; + if (onChange === void 0) { onChange = function () { }; } + this.fonts = new Map(); + validatePickerId(pickerId); + this.selectorSuffix = pickerId ? "-" + pickerId : ""; + this.apiKey = apiKey; + this.options = { + pickerId: pickerId, + families: families, + categories: categories, + scripts: scripts, + variants: variants, + filter: filter, + limit: limit, + sort: sort, + }; + this.onChange = onChange; + this.addFont(defaultFamily, false); + this.setActiveFont(defaultFamily, false); + } + FontManager.prototype.init = function () { + return __awaiter(this, void 0, void 0, function () { + var fonts, _loop_1, this_1, i, state_1, fontsToLoad; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4, getFontList(this.apiKey)]; + case 1: + fonts = _a.sent(); + _loop_1 = function (i) { + var font = fonts[i]; + if (this_1.fonts.size >= this_1.options.limit) { + return "break"; + } + if (!this_1.fonts.has(font.family) && + (this_1.options.families.length === 0 || this_1.options.families.includes(font.family)) && + (this_1.options.categories.length === 0 || this_1.options.categories.includes(font.category)) && + this_1.options.scripts.every(function (script) { return font.scripts.includes(script); }) && + this_1.options.variants.every(function (variant) { return font.variants.includes(variant); }) && + this_1.options.filter(font) === true) { + this_1.fonts.set(font.family, font); + } + }; + this_1 = this; + for (i = 0; i < fonts.length; i += 1) { + state_1 = _loop_1(i); + if (state_1 === "break") + break; + } + fontsToLoad = new Map(this.fonts); + fontsToLoad["delete"](this.activeFontFamily); + loadFontPreviews(fontsToLoad, this.options.scripts, this.options.variants, this.selectorSuffix); + return [2, this.fonts]; + } + }); + }); + }; + FontManager.prototype.getFonts = function () { + return this.fonts; + }; + FontManager.prototype.addFont = function (fontFamily, downloadPreview) { + if (downloadPreview === void 0) { downloadPreview = true; } + var font = { + family: fontFamily, + id: getFontId(fontFamily), + }; + this.fonts.set(fontFamily, font); + if (downloadPreview) { + var fontMap = new Map(); + fontMap.set(fontFamily, font); + loadFontPreviews(fontMap, this.options.scripts, this.options.variants, this.selectorSuffix); + } + }; + FontManager.prototype.removeFont = function (fontFamily) { + this.fonts["delete"](fontFamily); + }; + FontManager.prototype.getActiveFont = function () { + var activeFont = this.fonts.get(this.activeFontFamily); + if (!activeFont) { + throw Error("Cannot get active font: \"" + this.activeFontFamily + "\" is not in the font list"); + } + else { + return activeFont; + } + }; + FontManager.prototype.setActiveFont = function (fontFamily, runOnChange) { + var _this = this; + if (runOnChange === void 0) { runOnChange = true; } + var previousFontFamily = this.activeFontFamily; + var activeFont = this.fonts.get(fontFamily); + if (!activeFont) { + throw Error("Cannot update active font: \"" + fontFamily + "\" is not in the font list"); + } + this.activeFontFamily = fontFamily; + loadActiveFont(activeFont, previousFontFamily, this.options.scripts, this.options.variants, this.selectorSuffix).then(function () { + if (runOnChange) { + _this.onChange(activeFont); + } + }); + }; + FontManager.prototype.setOnChange = function (onChange) { + this.onChange = onChange; + }; + return FontManager; + }()); + + var FontPicker = (function () { + function FontPicker(apiKey, defaultFamily, _a, onChange) { + if (defaultFamily === void 0) { defaultFamily = FONT_FAMILY_DEFAULT; } + var _b = _a.pickerId, pickerId = _b === void 0 ? OPTIONS_DEFAULTS.pickerId : _b, _c = _a.families, families = _c === void 0 ? OPTIONS_DEFAULTS.families : _c, _d = _a.categories, categories = _d === void 0 ? OPTIONS_DEFAULTS.categories : _d, _e = _a.scripts, scripts = _e === void 0 ? OPTIONS_DEFAULTS.scripts : _e, _f = _a.variants, variants = _f === void 0 ? OPTIONS_DEFAULTS.variants : _f, _g = _a.filter, filter = _g === void 0 ? OPTIONS_DEFAULTS.filter : _g, _h = _a.limit, limit = _h === void 0 ? OPTIONS_DEFAULTS.limit : _h, _j = _a.sort, sort = _j === void 0 ? OPTIONS_DEFAULTS.sort : _j; + if (onChange === void 0) { onChange = function () { }; } + this.expanded = false; + this.closeEventListener = this.closeEventListener.bind(this); + this.toggleExpanded = this.toggleExpanded.bind(this); + var options = { + pickerId: pickerId, + families: families, + categories: categories, + scripts: scripts, + variants: variants, + filter: filter, + limit: limit, + sort: sort, + }; + this.fontManager = new FontManager(apiKey, defaultFamily, options, onChange); + this.generateUI(sort); + } + FontPicker.prototype.generateUI = function (sort) { + var _this = this; + var selectorSuffix = this.fontManager.selectorSuffix; + var pickerId = "font-picker" + selectorSuffix; + this.fontPickerDiv = document.getElementById(pickerId); + if (!this.fontPickerDiv) { + throw Error("Missing div with id=\"" + pickerId + "\""); + } + var dropdownButton = document.createElement("button"); + dropdownButton.classList.add("dropdown-button"); + dropdownButton.onclick = this.toggleExpanded; + dropdownButton.onkeypress = this.toggleExpanded; + dropdownButton.type = "button"; + this.fontPickerDiv.appendChild(dropdownButton); + this.dropdownFamily = document.createElement("p"); + this.dropdownFamily.textContent = this.fontManager.getActiveFont().family; + this.dropdownFamily.classList.add("dropdown-font-family"); + dropdownButton.appendChild(this.dropdownFamily); + var dropdownIcon = document.createElement("p"); + dropdownIcon.classList.add("dropdown-icon", "loading"); + dropdownButton.appendChild(dropdownIcon); + this.fontManager + .init() + .then(function (fontMap) { + var fonts = Array.from(fontMap.values()); + if (sort === "alphabet") { + fonts.sort(function (font1, font2) { + return font1.family.localeCompare(font2.family); + }); + } + _this.generateFontList(fonts); + dropdownIcon.classList.replace("loading", "finished"); + })["catch"](function (err) { + dropdownIcon.classList.replace("loading", "error"); + console.error("Error trying to fetch the list of available fonts"); + console.error(err); + }); + }; + FontPicker.prototype.generateFontList = function (fonts) { + var _this = this; + this.ul = document.createElement("ul"); + this.ul.classList.add("font-list"); + fonts.forEach(function (font) { + _this.addFontLi(font); + }); + this.fontPickerDiv.appendChild(this.ul); + var activeFontFamily = this.fontManager.getActiveFont().family; + var activeFontId = getFontId(activeFontFamily); + var fontButtonId = "font-button-" + activeFontId + this.fontManager.selectorSuffix; + this.activeFontButton = document.getElementById(fontButtonId); + if (this.activeFontButton) { + this.activeFontButton.classList.add("active-font"); + } + else { + console.error("Could not find font button with ID (" + fontButtonId + ")"); + } + }; + FontPicker.prototype.addFontLi = function (font, listIndex) { + var _this = this; + var fontId = getFontId(font.family); + var li = document.createElement("li"); + li.classList.add("font-list-item"); + var fontButton = document.createElement("button"); + fontButton.type = "button"; + fontButton.id = "font-button-" + fontId + this.fontManager.selectorSuffix; + fontButton.classList.add("font-button"); + fontButton.textContent = font.family; + var onActivate = function () { + _this.toggleExpanded(); + _this.setActiveFont(font.family); + }; + fontButton.onclick = onActivate; + fontButton.onkeypress = onActivate; + li.appendChild(fontButton); + if (listIndex) { + this.ul.insertBefore(li, this.ul.children[listIndex]); + } + else { + this.ul.appendChild(li); + } + }; + FontPicker.prototype.closeEventListener = function (e) { + var targetEl = e.target; + var fontPickerEl = document.getElementById("font-picker" + this.fontManager.selectorSuffix); + while (true) { + if (targetEl === fontPickerEl) { + return; + } + if (targetEl.parentNode) { + targetEl = targetEl.parentNode; + } + else { + this.toggleExpanded(); + return; + } + } + }; + FontPicker.prototype.toggleExpanded = function () { + if (this.expanded) { + this.expanded = false; + this.fontPickerDiv.classList.remove("expanded"); + document.removeEventListener("click", this.closeEventListener); + } + else { + this.expanded = true; + this.fontPickerDiv.classList.add("expanded"); + document.addEventListener("click", this.closeEventListener); + } + }; + FontPicker.prototype.getFonts = function () { + return this.fontManager.getFonts(); + }; + FontPicker.prototype.addFont = function (fontFamily, index) { + if (Array.from(this.fontManager.getFonts().keys()).includes(fontFamily)) { + throw Error("Did not add font to font picker: Font family \"" + fontFamily + "\" is already in the list"); + } + this.fontManager.addFont(fontFamily, true); + var font = this.fontManager.getFonts().get(fontFamily); + if (font) { + this.addFontLi(font, index); + } + else { + console.error("Font \"" + fontFamily + "\" is missing in font list"); + } + }; + FontPicker.prototype.removeFont = function (fontFamily) { + this.fontManager.removeFont(fontFamily); + var fontId = getFontId(fontFamily); + var fontButton = document.getElementById("font-button-" + fontId + this.fontManager.selectorSuffix); + if (fontButton) { + var fontLi = fontButton.parentElement; + fontButton.remove(); + if (fontLi) { + fontLi.remove(); + } + } + else { + throw Error("Could not remove font from font picker: Font family \"" + fontFamily + "\" is not in the list"); + } + }; + FontPicker.prototype.getActiveFont = function () { + return this.fontManager.getActiveFont(); + }; + FontPicker.prototype.setActiveFont = function (fontFamily) { + this.fontManager.setActiveFont(fontFamily); + var fontId = getFontId(fontFamily); + this.dropdownFamily.textContent = fontFamily; + if (this.activeFontButton) { + this.activeFontButton.classList.remove("active-font"); + this.activeFontButton = document.getElementById("font-button-" + fontId + this.fontManager.selectorSuffix); + this.activeFontButton.classList.add("active-font"); + } + else { + console.error("`activeFontButton` is undefined"); + } + }; + FontPicker.prototype.setOnChange = function (onChange) { + this.fontManager.setOnChange(onChange); + }; + return FontPicker; + }()); + + return FontPicker; + + }))); + \ No newline at end of file diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..c0c66ec --- /dev/null +++ b/src/index.css @@ -0,0 +1,37 @@ +.grid-container { + display: grid; + grid-template-columns: 15rem auto; + /* grid-gap: 10px; */ +} + +.header { + padding: 10px; + border: black solid 1px; +} + +.sidebar { + border: black solid 1px; +} + +.main { + display: flex; + justify-content: center; + align-content: center; + border: red solid 1px; + padding: 1rem; +} + +#page { + width: 400px; + height: 400px; + border: black solid 1px; + /* background-color: var(--neutral-5); */ +} + +#textDatum { + border: var(--neutral-5) solid 1px; +} + +body { + font-family: Helvetica, sans-serif; +} \ No newline at end of file diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..444a6db --- /dev/null +++ b/src/index.html @@ -0,0 +1,68 @@ + + + + + + + + Grids + + +
+ +
+
+ +
+
Lorem ipsum
+
+
+ + + + + diff --git a/main.js b/src/index.js similarity index 93% rename from main.js rename to src/index.js index 9aa80f0..89275e3 100644 --- a/main.js +++ b/src/index.js @@ -8,7 +8,7 @@ const loadMainWindow = () => { width : 1200, height: 800, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, "preload.js") } }); diff --git a/src/preload.js b/src/preload.js new file mode 100644 index 0000000..24b1aa7 --- /dev/null +++ b/src/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron') + +contextBridge.exposeInMainWorld('api', { + title: "Auto Typesetter" +}) \ No newline at end of file diff --git a/src/render.js b/src/render.js new file mode 100644 index 0000000..0551d36 --- /dev/null +++ b/src/render.js @@ -0,0 +1,74 @@ +// initialize input variables +let page = document.getElementById("page") +let liveAreaWidthInput = document.getElementById("width") +let liveAreaWidth = liveAreaWidthInput.value +let liveAreaHeightInput = document.getElementById("height") +let liveAreaHeight = liveAreaHeightInput.value + +let userInput = document.getElementById("userInput") +let rowsInput = document.getElementById("rows") +let columnsInput = document.getElementById("columns") +let linesPerFieldInput = document.getElementById("linesPerField") +let linesPerGutterInput = document.getElementById("linesPerGutter") + +// let fontInput = getActiveFont() +let typeSizeInput = document.getElementById("size") +let textHeight = typeSizeInput.value + +//measure type +window.onload = function() { + let c = document.getElementById("measuringStick") + let ctx = c.getContext("2d") + + ctx.font = "18px Futura" + + let fM = ctx.measureText("A") // a character with the maximum height + textHeight = fM.actualBoundingBoxAscent + fM.actualBoundingBoxDescent + console.log(textHeight) + + ctx.fillText("Height: " + textHeight, 5, 80) + + updateValues() +} + +userInput.addEventListener('change', () => { + console.log("input change detected") + updateValues() +}); + +function updateValues() { + // params + let liveAreaHeight = liveAreaHeightInput.value // live area height dimension + let liveAreaWidth = liveAreaWidthInput.value // live area width dimension + let rows = rowsInput.value // grid rows + let columns = columnsInput.value // grid columns + let linesPerField = linesPerFieldInput.value // lines of text per grid field + let linesPerGutter = linesPerGutterInput.value // lines of text between grid fields + + // calcs + let lines = linesPerField * rows + linesPerGutter * (rows - 1) // total lines of text in live area + let total_text = textHeight * lines // total height of live area + let perLineSpacing = (liveAreaHeight - total_text) / (lines - 1) // vertical whitespace between lines of text + let leading = perLineSpacing + textHeight // height of a single line of text, might need to change based on how css renders a line and its leading (aka line spacing) + + let horizontalGutter = 2 * perLineSpacing + textHeight // horizontal gutter dimension + let fieldHeight = (liveAreaHeight - horizontalGutter * (rows - 1)) / rows // grid field height dimension + let verticalGutter = (liveAreaWidth - columns * fieldHeight) / (columns - 1) // vertical gutter dimension + let fieldWidth = (liveAreaWidth - verticalGutter * (columns - 1)) / columns // grid field width dimension + + // render + renderPage() +} + +function renderPage() { + // live area + page.style.width = liveAreaWidth + page.style.height = liveAreaHeight + console.log("page set to " + page.style.width + " by " + page.style.height) + + // font + page.style.fontSize = typeSizeInput.value + console.log("page font size set to " + page.style.fontSize) + + // grid +} \ No newline at end of file