From 3900a13481b3ae225f57cdc1b838ca42af16b8a5 Mon Sep 17 00:00:00 2001 From: Corbin Crutchley Date: Sun, 25 Sep 2022 05:51:04 -0700 Subject: [PATCH] chore: apply automatic linting --- .eslintrc.js | 92 +- .prettierrc | 22 +- astro.config.ts | 179 ++-- content/data/languages.json | 6 +- content/data/licenses.json | 80 +- content/data/pronouns.json | 640 ++++++------ content/data/roles.json | 48 +- content/data/unicorns.json | 922 ++++++++---------- package.json | 138 +-- public/manifest.json | 102 +- public/scripts/backbtn.js | 52 +- public/scripts/tabs.js | 337 +++---- public/scripts/themetoggle.js | 57 +- public/sw.js | 18 +- public/uninstall-sw.js | 20 +- .../blog-post-layout/blog-post-layout.astro | 18 +- .../dark-light-button/dark-light-button.astro | 28 +- src/components/layout/layout.astro | 94 +- src/components/pagination/pagination-logic.ts | 168 ++-- src/components/pagination/pagination.astro | 98 +- .../post-card-list/post-card-list.astro | 25 +- src/components/post-card/post-card.astro | 91 +- src/components/seo/analytics.astro | 6 +- src/components/seo/article.astro | 52 +- src/components/seo/book.astro | 30 +- src/components/seo/locale.astro | 76 +- src/components/seo/open-graph.astro | 92 +- src/components/seo/profile.astro | 20 +- src/components/seo/seo.astro | 87 +- src/components/seo/shared.ts | 38 +- src/components/seo/twitter.astro | 63 +- ...heading-intersection-observer-script.astro | 109 ++- .../table-of-contents/table-of-contents.astro | 49 +- .../table-of-contents.module.scss | 4 +- .../user-profile-pic/user-profile-pic.astro | 53 +- src/constants/site-config.ts | 34 +- src/constants/site-url.js | 36 +- src/constants/theme.ts | 126 +-- src/convertkit.scss | 687 ++++++------- src/global.scss | 546 +++++------ src/icons/attachment.astro | 45 +- src/icons/feather.astro | 37 +- src/layouts/document.astro | 140 +-- .../post-metadata/post-metadata.astro | 75 +- .../post-title-header/post-title-header.astro | 18 +- .../suggested-articles.astro | 73 +- .../suggested-articles.module.scss | 100 +- .../blog-post/tabs-script/tabs-script.astro | 8 +- .../blocking-theme-changer-script.astro | 112 +-- src/page-components/layouts/theme-style.astro | 50 +- .../post-list-header/post-list-header.astro | 44 +- src/page-components/post-list/post-list.astro | 33 +- .../profile-header/profile-header.astro | 232 +++-- .../profile-header/profile-header.module.scss | 200 ++-- .../profile-header/social-button.astro | 53 +- .../profile-header/social-button.module.scss | 119 ++- .../unicorns/unicorn-page.astro | 87 +- src/pages/index.astro | 24 +- src/pages/page/[page].astro | 54 +- src/pages/posts/[postid].astro | 139 +-- src/pages/unicorns/[unicornid]/index.astro | 95 +- .../unicorns/[unicornid]/page/[page].astro | 82 +- src/shiki.scss | 14 +- src/styles/_text_styles.scss | 1 - src/tabs.scss | 118 +-- src/types/CollectionInfo.ts | 66 +- src/types/LicenseInfo.ts | 12 +- src/types/PostInfo.ts | 58 +- src/types/PronounInfo.ts | 12 +- src/types/RolesInfo.ts | 48 +- src/types/UnicornInfo.ts | 58 +- src/types/modules/gatsby-remark-embedder.d.ts | 6 +- src/types/modules/remark-behead.d.ts | 22 +- src/types/modules/window.d.ts | 14 +- src/utils/api.ts | 56 +- src/utils/data.ts | 74 +- src/utils/get-all-posts.ts | 96 +- src/utils/get-image-size.ts | 18 +- src/utils/get-suggested-articles.ts | 365 ++++--- src/utils/markdown/rehype-astro-image-md.ts | 158 +-- src/utils/markdown/rehype-excerpt.ts | 74 +- src/utils/markdown/rehype-header-text.ts | 50 +- .../markdown/rehype-unicorn-element-map.ts | 231 ++--- .../rehype-unicorn-get-suggested-posts.ts | 49 +- .../markdown/rehype-unicorn-populate-post.ts | 158 ++- src/utils/markdown/rehype-word-count.ts | 148 +-- src/utils/markdown/tabs/index.ts | 2 +- src/utils/markdown/tabs/tabs.ts | 240 ++--- src/utils/translations.ts | 28 +- src/utils/url-paths.ts | 46 +- tsconfig.json | 56 +- vercel.json | 40 +- 92 files changed, 4787 insertions(+), 4694 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 284a9f46..4919d26e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,46 +1,46 @@ -const tsRules = { - "@typescript-eslint/ban-types": "off", - "@typescript-eslint/no-empty-interface": "off" -} - -module.exports = { - env: { - node: true, - browser: true, - }, - extends: ['eslint:recommended', 'plugin:astro/recommended'], - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - }, - rules: { - "no-unused-vars": "off" - }, - overrides: [ - { - files: ['*.astro'], - parser: 'astro-eslint-parser', - parserOptions: { - parser: '@typescript-eslint/parser', - extraFileExtensions: ['.astro'], - }, - rules: { - ...tsRules - }, - }, - { - files: ['*.ts'], - parser: '@typescript-eslint/parser', - extends: ['plugin:@typescript-eslint/recommended'], - rules: { - ...tsRules - }, - }, - { - // Define the configuration for ` diff --git a/src/components/layout/layout.astro b/src/components/layout/layout.astro index 0cee2a96..98052d39 100644 --- a/src/components/layout/layout.astro +++ b/src/components/layout/layout.astro @@ -1,39 +1,55 @@ ---- -import layoutStyles from "./layout.module.scss"; -import DarkLightButton from "components/dark-light-button/dark-light-button.astro"; -import { Icon } from 'astro-icon'; - -// const { back } = useHistory(); - -const rootPath = `/`; - -const isBase = Astro.url.pathname === rootPath; -const isBlogPost = Astro.url.pathname.startsWith(`${rootPath}posts`); -const isCollection = Astro.url.pathname.startsWith(`${rootPath}collections`); - ---- -
-
-
- {!isBase ? (<> - - \ No newline at end of file + headingsEls + .filter((a) => a) + .forEach((heading) => { + observer.observe(heading); + }); + }; + diff --git a/src/components/table-of-contents/table-of-contents.astro b/src/components/table-of-contents/table-of-contents.astro index 09feb9ef..23650a65 100644 --- a/src/components/table-of-contents/table-of-contents.astro +++ b/src/components/table-of-contents/table-of-contents.astro @@ -6,7 +6,7 @@ import { PostInfo } from "types/PostInfo"; import HeadingIntersectionObserverScript from "./heading-intersection-observer-script.astro"; interface TableOfContentsProps { - headingsWithId: PostInfo["headingsWithId"]; + headingsWithId: PostInfo["headingsWithId"]; } const { headingsWithId } = Astro.props as TableOfContentsProps; @@ -18,33 +18,30 @@ const minDepth = Math.min(...headings.map((h) => h.depth)); // offset the heading depths by minDepth, so they always start at 1 const headingsToDisplay = headings - .map((h) => Object.assign({}, h, { depth: h.depth - minDepth + 1 })) - .filter((headingInfo) => headingInfo.depth <= 3); + .map((h) => Object.assign({}, h, { depth: h.depth - minDepth + 1 })) + .filter((headingInfo) => headingInfo.depth <= 3); -const headingsToDisplaySlugs = headingsToDisplay.map(item => item.slug); +const headingsToDisplaySlugs = headingsToDisplay.map((item) => item.slug); --- - \ No newline at end of file + diff --git a/src/components/table-of-contents/table-of-contents.module.scss b/src/components/table-of-contents/table-of-contents.module.scss index bbfbcc54..cc882ebc 100644 --- a/src/components/table-of-contents/table-of-contents.module.scss +++ b/src/components/table-of-contents/table-of-contents.module.scss @@ -60,7 +60,9 @@ @extend %headline-uniwidth-2; } -.tocH2, .tocH3, .tocH4 { +.tocH2, +.tocH3, +.tocH4 { a { font-style: italic; } diff --git a/src/components/user-profile-pic/user-profile-pic.astro b/src/components/user-profile-pic/user-profile-pic.astro index 71d23d74..1d9decfe 100644 --- a/src/components/user-profile-pic/user-profile-pic.astro +++ b/src/components/user-profile-pic/user-profile-pic.astro @@ -1,39 +1,42 @@ --- import styles from "./user-profile-pic.module.scss"; import { UnicornInfo } from "uu-types"; -import {Image} from '@astrojs/image/components'; +import { Image } from "@astrojs/image/components"; // TODO: Fix image loading and image 'onClick' interface UserProfilePicProps { - authors: Array; - className: string; + authors: Array; + className: string; } -const { authors, className } = Astro.props as UserProfilePicProps +const { authors, className } = Astro.props as UserProfilePicProps; const hasTwoAuthors = authors.length !== 1; --- -
- {authors.map((unicorn, i) => { - const classesToApply = hasTwoAuthors ? styles.twoAuthor : ""; - return ( -
- {unicorn.name} -
- ); - })} +
+ { + authors.map((unicorn, i) => { + const classesToApply = hasTwoAuthors ? styles.twoAuthor : ""; + + return ( +
+ {unicorn.name} +
+ ); + }) + }
diff --git a/src/constants/site-config.ts b/src/constants/site-config.ts index 8f117489..4d82a358 100644 --- a/src/constants/site-config.ts +++ b/src/constants/site-config.ts @@ -6,32 +6,32 @@ let parent: string; // Try & Catch to allow for hosts themselves to be passed // `new URL('domain.com')` will fail/throw, but is a valid host try { - const url = new URL(siteUrl); - // URLs like 'localhost:3000' might not give host. - // Throw in order to catch in wrapper handler - if (!url.host) throw new Error(); - parent = url.host; + const url = new URL(siteUrl); + // URLs like 'localhost:3000' might not give host. + // Throw in order to catch in wrapper handler + if (!url.host) throw new Error(); + parent = url.host; } catch (_) { - const url = new URL("https://" + siteUrl); - parent = url.host; + const url = new URL("https://" + siteUrl); + parent = url.host; } // Twitch embed throws error with strings like 'localhost:3000', but // those persist with `new URL().host` if (parent.startsWith("localhost")) { - parent = "localhost"; + parent = "localhost"; } const siteMetadata = { - title: `Unicorn Utterances`, - description: `Learning programming from magically majestic words. A place to learn about all sorts of programming topics from entry-level concepts to advanced abstractions`, - siteUrl, - disqusShortname: "unicorn-utterances", - repoPath: "unicorn-utterances/unicorn-utterances", - relativeToPosts: "/content/blog", - keywords: - "programming,development,mobile,web,game,utterances,software engineering,javascript,angular,react,computer science", - twitterHandle: "@unicornuttrncs", + title: `Unicorn Utterances`, + description: `Learning programming from magically majestic words. A place to learn about all sorts of programming topics from entry-level concepts to advanced abstractions`, + siteUrl, + disqusShortname: "unicorn-utterances", + repoPath: "unicorn-utterances/unicorn-utterances", + relativeToPosts: "/content/blog", + keywords: + "programming,development,mobile,web,game,utterances,software engineering,javascript,angular,react,computer science", + twitterHandle: "@unicornuttrncs", }; export { parent, siteUrl, buildMode, siteMetadata }; diff --git a/src/constants/site-url.js b/src/constants/site-url.js index 56b07b79..b1f06247 100644 --- a/src/constants/site-url.js +++ b/src/constants/site-url.js @@ -1,22 +1,22 @@ export default () => { - const buildMode = process.env.BUILD_ENV || "production"; - let siteUrl = process.env.SITE_URL || process.env.VERCEL_URL || ""; + const buildMode = process.env.BUILD_ENV || "production"; + let siteUrl = process.env.SITE_URL || process.env.VERCEL_URL || ""; - if (!siteUrl) { - switch (buildMode) { - case "production": - siteUrl = "https://unicorn-utterances.com"; - break; - case "development": - siteUrl = "http://localhost:9000"; - break; - default: - siteUrl = "https://beta.unicorn-utterances.com"; - } - } + if (!siteUrl) { + switch (buildMode) { + case "production": + siteUrl = "https://unicorn-utterances.com"; + break; + case "development": + siteUrl = "http://localhost:9000"; + break; + default: + siteUrl = "https://beta.unicorn-utterances.com"; + } + } - return { - buildMode, - siteUrl, - }; + return { + buildMode, + siteUrl, + }; }; diff --git a/src/constants/theme.ts b/src/constants/theme.ts index cc2ab835..24a9326c 100644 --- a/src/constants/theme.ts +++ b/src/constants/theme.ts @@ -1,66 +1,66 @@ export const COLORS = { - //main styles - darkPrimary: { light: "#153E67", dark: "#E4F4FF" }, - primary: { light: "#127DB3", dark: "#127DB3" }, - lightPrimary: { light: "#315e81", dark: "#bdd9e9" }, - black: { light: "black", dark: "white" }, - white: { light: "white", dark: "black" }, - darkGrey: { light: "rgba(0, 0, 0, 0.64)", dark: "rgba(255, 255, 255, .64)" }, - highImpactBlack: { - light: "rgba(0, 0, 0, 0.87)", - dark: "rgba(255, 255, 255, .87)", - }, - midImpactBlack: { - light: "rgba(0, 0, 0, 0.64)", - dark: "rgba(255, 255, 255, .64)", - }, - lowImpactBlack: { - light: "rgba(0, 0, 0, 0.58)", - dark: "rgba(255, 255, 255, .58)", - }, - minImpactBlack: { - light: "rgba(0, 0, 0, 0.2)", - dark: "rgba(255, 255, 255, .2)", - }, - backgroundColor: { light: "#E4F4FF", dark: "#072a41" }, - cardActiveBackground: { light: "#EBF6FC", dark: "#163954" }, - cardActiveBoxShadow: { - light: "0px 2px 4px rgba(11, 37, 104, 0.27), inset 0px 1px 0px #FFFFFF", - dark: "0px 2px 4px rgba(0, 0, 0, 0.27), inset 0px 1px 0px #435e75", - }, - codeBlockBackground: { light: "white", dark: "#202746" }, - codeInlineBackground: { light: "#cbe8fb", dark: "#1d495e" }, - //code styles - codeBackgroundColor: { light: "#fff", dark: "#161b1d" }, - textColor: { light: "#5e6687", dark: "#7ea2b4" }, - stringColor: { light: "#007396", dark: "#7ee2c4" }, - keywordColor: { light: "#846c00", dark: "#b5ea94" }, - operatorColor: { light: "#b74c00", dark: "#935c25" }, - punctuationColor: { light: "#006fce", dark: "#7ea2b4" }, - constantColor: { light: "#aa05d4", dark: "#cf8ae1" }, - functionColor: { light: "#5357d2", dark: "#c1c3ff" }, - selectionColor: { light: "#dfe2f1", dark: "#cfe0ec" }, - commentColor: { light: "#898ea4", dark: "#c7d5d7" }, - propColor: { light: "#c08b30", dark: "#8a8a0f" }, - varColor: { light: "#3d8fd1", dark: "#88c1e2" }, - selectorColor: { light: "#6679cc", dark: "#bdbdff" }, - urlColor: { light: "#22a9c9", dark: "#9affde" }, - insertedUnderlineColor: { light: "#202746", dark: "#ebf8ff" }, - highlightColor: { light: "#c94922", dark: "#ff92c0" }, - lineNumbersColor: { light: "#979db4", dark: "#abe1fa" }, - lineHighlightColor: { - light: "rgba(107, 115, 148, 0.2)", - dark: "rgba(235, 248, 255, 0.2)", - }, - lineHighlightFadeColor: { - light: "rgba(107, 115, 148, 0)", - dark: "rgba(235, 248, 255, 0)", - }, - scrollBarBG: { - light: "rgba(18, 125, 179, 0.3)", - dark: "rgba(228, 244, 255, 0.3)", - }, - scrollBarThumb: { light: "var(--primary)", dark: "var(--darkPrimary)" }, + //main styles + darkPrimary: { light: "#153E67", dark: "#E4F4FF" }, + primary: { light: "#127DB3", dark: "#127DB3" }, + lightPrimary: { light: "#315e81", dark: "#bdd9e9" }, + black: { light: "black", dark: "white" }, + white: { light: "white", dark: "black" }, + darkGrey: { light: "rgba(0, 0, 0, 0.64)", dark: "rgba(255, 255, 255, .64)" }, + highImpactBlack: { + light: "rgba(0, 0, 0, 0.87)", + dark: "rgba(255, 255, 255, .87)", + }, + midImpactBlack: { + light: "rgba(0, 0, 0, 0.64)", + dark: "rgba(255, 255, 255, .64)", + }, + lowImpactBlack: { + light: "rgba(0, 0, 0, 0.58)", + dark: "rgba(255, 255, 255, .58)", + }, + minImpactBlack: { + light: "rgba(0, 0, 0, 0.2)", + dark: "rgba(255, 255, 255, .2)", + }, + backgroundColor: { light: "#E4F4FF", dark: "#072a41" }, + cardActiveBackground: { light: "#EBF6FC", dark: "#163954" }, + cardActiveBoxShadow: { + light: "0px 2px 4px rgba(11, 37, 104, 0.27), inset 0px 1px 0px #FFFFFF", + dark: "0px 2px 4px rgba(0, 0, 0, 0.27), inset 0px 1px 0px #435e75", + }, + codeBlockBackground: { light: "white", dark: "#202746" }, + codeInlineBackground: { light: "#cbe8fb", dark: "#1d495e" }, + //code styles + codeBackgroundColor: { light: "#fff", dark: "#161b1d" }, + textColor: { light: "#5e6687", dark: "#7ea2b4" }, + stringColor: { light: "#007396", dark: "#7ee2c4" }, + keywordColor: { light: "#846c00", dark: "#b5ea94" }, + operatorColor: { light: "#b74c00", dark: "#935c25" }, + punctuationColor: { light: "#006fce", dark: "#7ea2b4" }, + constantColor: { light: "#aa05d4", dark: "#cf8ae1" }, + functionColor: { light: "#5357d2", dark: "#c1c3ff" }, + selectionColor: { light: "#dfe2f1", dark: "#cfe0ec" }, + commentColor: { light: "#898ea4", dark: "#c7d5d7" }, + propColor: { light: "#c08b30", dark: "#8a8a0f" }, + varColor: { light: "#3d8fd1", dark: "#88c1e2" }, + selectorColor: { light: "#6679cc", dark: "#bdbdff" }, + urlColor: { light: "#22a9c9", dark: "#9affde" }, + insertedUnderlineColor: { light: "#202746", dark: "#ebf8ff" }, + highlightColor: { light: "#c94922", dark: "#ff92c0" }, + lineNumbersColor: { light: "#979db4", dark: "#abe1fa" }, + lineHighlightColor: { + light: "rgba(107, 115, 148, 0.2)", + dark: "rgba(235, 248, 255, 0.2)", + }, + lineHighlightFadeColor: { + light: "rgba(107, 115, 148, 0)", + dark: "rgba(235, 248, 255, 0)", + }, + scrollBarBG: { + light: "rgba(18, 125, 179, 0.3)", + dark: "rgba(228, 244, 255, 0.3)", + }, + scrollBarThumb: { light: "var(--primary)", dark: "var(--darkPrimary)" }, }; -export const COLOR_MODE_STORAGE_KEY = "currentTheme"; \ No newline at end of file +export const COLOR_MODE_STORAGE_KEY = "currentTheme"; diff --git a/src/convertkit.scss b/src/convertkit.scss index a4bd5258..4067927a 100644 --- a/src/convertkit.scss +++ b/src/convertkit.scss @@ -1,41 +1,41 @@ .formkit-form { - border-radius: 5px; - padding: 20px; - margin: 1rem auto; - border: var(--cardOutlineStyle); + border-radius: 5px; + padding: 20px; + margin: 1rem auto; + border: var(--cardOutlineStyle); - .newsletter-heading { - text-align: center; - } + .newsletter-heading { + text-align: center; + } } .formkit-form * { - box-sizing: border-box; + box-sizing: border-box; } .formkit-form { - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } .formkit-form legend { - border: none; - font-size: inherit; - margin-bottom: 10px; - padding: 0; - position: relative; - display: table; + border: none; + font-size: inherit; + margin-bottom: 10px; + padding: 0; + position: relative; + display: table; } .formkit-form fieldset { - border: 0; - padding: 0.01em 0 0 0; - margin: 0; - min-width: 0; + border: 0; + padding: 0.01em 0 0 0; + margin: 0; + min-width: 0; } .formkit-form body:not(:-moz-handler-blocked) fieldset { - display: table-cell; + display: table-cell; } .formkit-form h1, @@ -44,31 +44,31 @@ .formkit-form h4, .formkit-form h5, .formkit-form h6 { - color: inherit; - font-size: inherit; - font-weight: inherit; + color: inherit; + font-size: inherit; + font-weight: inherit; } .formkit-form h2 { - font-size: 1.5em; - margin: 1em 0; + font-size: 1.5em; + margin: 1em 0; } .formkit-form h3 { - font-size: 1.17em; - margin: 1em 0; + font-size: 1.17em; + margin: 1em 0; } .formkit-form p { - color: inherit; - font-size: inherit; - font-weight: inherit; + color: inherit; + font-size: inherit; + font-weight: inherit; } .formkit-form ol:not([template-default]), .formkit-form ul:not([template-default]), .formkit-form blockquote:not([template-default]) { - text-align: left; + text-align: left; } .formkit-form p:not([template-default]), @@ -76,497 +76,528 @@ .formkit-form blockquote:not([template-default]), .formkit-form ol:not([template-default]), .formkit-form ul:not([template-default]) { - color: inherit; - font-style: initial; + color: inherit; + font-style: initial; } .formkit-form .ordered-list, .formkit-form .unordered-list { - list-style-position: outside !important; - padding-left: 1em; + list-style-position: outside !important; + padding-left: 1em; } .formkit-form .list-item { - padding-left: 0; + padding-left: 0; } .formkit-form[data-format="modal"] { - display: none; + display: none; } .formkit-form[data-format="slide in"] { - display: none; + display: none; } .formkit-form[data-format="sticky bar"] { - display: none; + display: none; } .formkit-sticky-bar .formkit-form[data-format="sticky bar"] { - display: block; + display: block; } .formkit-form .formkit-input, .formkit-form .formkit-select, .formkit-form .formkit-checkboxes { - width: 100%; + width: 100%; } .formkit-form .formkit-button, .formkit-form .formkit-submit { - border: 0; - border-radius: 5px; - color: #ffffff; - cursor: pointer; - display: inline-block; - text-align: center; - font-size: 15px; - font-weight: 500; - cursor: pointer; - margin-bottom: 15px; - overflow: hidden; - padding: 0; - position: relative; - vertical-align: middle; + border: 0; + border-radius: 5px; + color: #ffffff; + cursor: pointer; + display: inline-block; + text-align: center; + font-size: 15px; + font-weight: 500; + cursor: pointer; + margin-bottom: 15px; + overflow: hidden; + padding: 0; + position: relative; + vertical-align: middle; } .formkit-form .formkit-button:hover, .formkit-form .formkit-submit:hover, .formkit-form .formkit-button:focus, .formkit-form .formkit-submit:focus { - outline: none; + outline: none; } -.formkit-form .formkit-button:hover>span, -.formkit-form .formkit-submit:hover>span, -.formkit-form .formkit-button:focus>span, -.formkit-form .formkit-submit:focus>span { - background-color: rgba(0, 0, 0, 0.1); +.formkit-form .formkit-button:hover > span, +.formkit-form .formkit-submit:hover > span, +.formkit-form .formkit-button:focus > span, +.formkit-form .formkit-submit:focus > span { + background-color: rgba(0, 0, 0, 0.1); } -.formkit-form .formkit-button>span, -.formkit-form .formkit-submit>span { - display: block; - -webkit-transition: all 300ms ease-in-out; - transition: all 300ms ease-in-out; - padding: 12px 24px; +.formkit-form .formkit-button > span, +.formkit-form .formkit-submit > span { + display: block; + -webkit-transition: all 300ms ease-in-out; + transition: all 300ms ease-in-out; + padding: 12px 24px; } .formkit-form .formkit-input { - background: #ffffff; - font-size: 15px; - padding: 12px; - border: 1px solid #e3e3e3; - -webkit-flex: 1 0 auto; - -ms-flex: 1 0 auto; - flex: 1 0 auto; - line-height: 1.4; - margin: 0; - -webkit-transition: border-color ease-out 300ms; - transition: border-color ease-out 300ms; + background: #ffffff; + font-size: 15px; + padding: 12px; + border: 1px solid #e3e3e3; + -webkit-flex: 1 0 auto; + -ms-flex: 1 0 auto; + flex: 1 0 auto; + line-height: 1.4; + margin: 0; + -webkit-transition: border-color ease-out 300ms; + transition: border-color ease-out 300ms; } .formkit-form .formkit-input:focus { - outline: none; - border-color: #1677be; - -webkit-transition: border-color ease 300ms; - transition: border-color ease 300ms; + outline: none; + border-color: #1677be; + -webkit-transition: border-color ease 300ms; + transition: border-color ease 300ms; } .formkit-form .formkit-input::-webkit-input-placeholder { - color: inherit; - opacity: 0.8; + color: inherit; + opacity: 0.8; } .formkit-form .formkit-input::-moz-placeholder { - color: inherit; - opacity: 0.8; + color: inherit; + opacity: 0.8; } .formkit-form .formkit-input:-ms-input-placeholder { - color: inherit; - opacity: 0.8; + color: inherit; + opacity: 0.8; } .formkit-form .formkit-input::placeholder { - color: inherit; - opacity: 0.8; + color: inherit; + opacity: 0.8; } .formkit-form [data-group="dropdown"] { - position: relative; - display: inline-block; - width: 100%; + position: relative; + display: inline-block; + width: 100%; } .formkit-form [data-group="dropdown"]::before { - content: ""; - top: calc(50% - 2.5px); - right: 10px; - position: absolute; - pointer-events: none; - border-color: #4f4f4f transparent transparent transparent; - border-style: solid; - border-width: 6px 6px 0 6px; - height: 0; - width: 0; - z-index: 999; + content: ""; + top: calc(50% - 2.5px); + right: 10px; + position: absolute; + pointer-events: none; + border-color: #4f4f4f transparent transparent transparent; + border-style: solid; + border-width: 6px 6px 0 6px; + height: 0; + width: 0; + z-index: 999; } .formkit-form [data-group="dropdown"] select { - height: auto; - width: 100%; - cursor: pointer; - color: #333333; - line-height: 1.4; - margin-bottom: 0; - padding: 0 6px; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - font-size: 15px; - padding: 12px; - padding-right: 25px; - border: 1px solid #e3e3e3; - background: #ffffff; + height: auto; + width: 100%; + cursor: pointer; + color: #333333; + line-height: 1.4; + margin-bottom: 0; + padding: 0 6px; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + font-size: 15px; + padding: 12px; + padding-right: 25px; + border: 1px solid #e3e3e3; + background: #ffffff; } .formkit-form [data-group="dropdown"] select:focus { - outline: none; + outline: none; } .formkit-form [data-group="checkboxes"] { - text-align: left; - margin: 0; + text-align: left; + margin: 0; } .formkit-form [data-group="checkboxes"] [data-group="checkbox"] { - margin-bottom: 10px; + margin-bottom: 10px; } .formkit-form [data-group="checkboxes"] [data-group="checkbox"] * { - cursor: pointer; + cursor: pointer; } .formkit-form [data-group="checkboxes"] [data-group="checkbox"]:last-of-type { - margin-bottom: 0; + margin-bottom: 0; } -.formkit-form [data-group="checkboxes"] [data-group="checkbox"] input[type="checkbox"] { - display: none; +.formkit-form + [data-group="checkboxes"] + [data-group="checkbox"] + input[type="checkbox"] { + display: none; } -.formkit-form [data-group="checkboxes"] [data-group="checkbox"] input[type="checkbox"]+label::after { - content: none; +.formkit-form + [data-group="checkboxes"] + [data-group="checkbox"] + input[type="checkbox"] + + label::after { + content: none; } -.formkit-form [data-group="checkboxes"] [data-group="checkbox"] input[type="checkbox"]:checked+label::after { - border-color: #ffffff; - content: ""; +.formkit-form + [data-group="checkboxes"] + [data-group="checkbox"] + input[type="checkbox"]:checked + + label::after { + border-color: #ffffff; + content: ""; } -.formkit-form [data-group="checkboxes"] [data-group="checkbox"] input[type="checkbox"]:checked+label::before { - background: #10bf7a; - border-color: #10bf7a; +.formkit-form + [data-group="checkboxes"] + [data-group="checkbox"] + input[type="checkbox"]:checked + + label::before { + background: #10bf7a; + border-color: #10bf7a; } .formkit-form [data-group="checkboxes"] [data-group="checkbox"] label { - position: relative; - display: inline-block; - padding-left: 28px; + position: relative; + display: inline-block; + padding-left: 28px; } .formkit-form [data-group="checkboxes"] [data-group="checkbox"] label::before, .formkit-form [data-group="checkboxes"] [data-group="checkbox"] label::after { - position: absolute; - content: ""; - display: inline-block; + position: absolute; + content: ""; + display: inline-block; } .formkit-form [data-group="checkboxes"] [data-group="checkbox"] label::before { - height: 16px; - width: 16px; - border: 1px solid #e3e3e3; - background: #ffffff; - left: 0px; - top: 3px; + height: 16px; + width: 16px; + border: 1px solid #e3e3e3; + background: #ffffff; + left: 0px; + top: 3px; } .formkit-form [data-group="checkboxes"] [data-group="checkbox"] label::after { - height: 4px; - width: 8px; - border-left: 2px solid #4d4d4d; - border-bottom: 2px solid #4d4d4d; - -webkit-transform: rotate(-45deg); - -ms-transform: rotate(-45deg); - transform: rotate(-45deg); - left: 4px; - top: 8px; + height: 4px; + width: 8px; + border-left: 2px solid #4d4d4d; + border-bottom: 2px solid #4d4d4d; + -webkit-transform: rotate(-45deg); + -ms-transform: rotate(-45deg); + transform: rotate(-45deg); + left: 4px; + top: 8px; } .formkit-form .formkit-alert { - background: #f9fafb; - border: 1px solid #e3e3e3; - border-radius: 5px; - -webkit-flex: 1 0 auto; - -ms-flex: 1 0 auto; - flex: 1 0 auto; - list-style: none; - margin: 25px auto; - padding: 12px; - text-align: center; - width: 100%; + background: #f9fafb; + border: 1px solid #e3e3e3; + border-radius: 5px; + -webkit-flex: 1 0 auto; + -ms-flex: 1 0 auto; + flex: 1 0 auto; + list-style: none; + margin: 25px auto; + padding: 12px; + text-align: center; + width: 100%; } .formkit-form .formkit-alert:empty { - display: none; + display: none; } .formkit-form .formkit-alert-success { - background: #d3fbeb; - border-color: #10bf7a; - color: #0c905c; + background: #d3fbeb; + border-color: #10bf7a; + color: #0c905c; } .formkit-form .formkit-alert-error { - background: #fde8e2; - border-color: #f2643b; - color: #ea4110; + background: #fde8e2; + border-color: #f2643b; + color: #ea4110; } .formkit-form .formkit-spinner { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - height: 0px; - width: 0px; - margin: 0 auto; - position: absolute; - top: 0; - left: 0; - right: 0; - width: 0px; - overflow: hidden; - text-align: center; - -webkit-transition: all 300ms ease-in-out; - transition: all 300ms ease-in-out; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + height: 0px; + width: 0px; + margin: 0 auto; + position: absolute; + top: 0; + left: 0; + right: 0; + width: 0px; + overflow: hidden; + text-align: center; + -webkit-transition: all 300ms ease-in-out; + transition: all 300ms ease-in-out; } -.formkit-form .formkit-spinner>div { - margin: auto; - width: 12px; - height: 12px; - background-color: #fff; - opacity: 0.3; - border-radius: 100%; - display: inline-block; - -webkit-animation: formkit-bouncedelay-formkit-form-data-uid-882d42bb6f- 1.4s infinite ease-in-out both; - animation: formkit-bouncedelay-formkit-form-data-uid-882d42bb6f- 1.4s infinite ease-in-out both; +.formkit-form .formkit-spinner > div { + margin: auto; + width: 12px; + height: 12px; + background-color: #fff; + opacity: 0.3; + border-radius: 100%; + display: inline-block; + -webkit-animation: formkit-bouncedelay-formkit-form-data-uid-882d42bb6f- 1.4s + infinite ease-in-out both; + animation: formkit-bouncedelay-formkit-form-data-uid-882d42bb6f- 1.4s infinite + ease-in-out both; } -.formkit-form .formkit-spinner>div:nth-child(1) { - -webkit-animation-delay: -0.32s; - animation-delay: -0.32s; +.formkit-form .formkit-spinner > div:nth-child(1) { + -webkit-animation-delay: -0.32s; + animation-delay: -0.32s; } -.formkit-form .formkit-spinner>div:nth-child(2) { - -webkit-animation-delay: -0.16s; - animation-delay: -0.16s; +.formkit-form .formkit-spinner > div:nth-child(2) { + -webkit-animation-delay: -0.16s; + animation-delay: -0.16s; } .formkit-form .formkit-submit[data-active] .formkit-spinner { - opacity: 1; - height: 100%; - width: 50px; + opacity: 1; + height: 100%; + width: 50px; } -.formkit-form .formkit-submit[data-active] .formkit-spinner~span { - opacity: 0; +.formkit-form .formkit-submit[data-active] .formkit-spinner ~ span { + opacity: 0; } .formkit-form .formkit-powered-by[data-active="false"] { - opacity: 0.35; + opacity: 0.35; } .formkit-form .formkit-powered-by-convertkit-container { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - width: 100%; - z-index: 5; - margin: 10px 0; - position: relative; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + width: 100%; + z-index: 5; + margin: 10px 0; + position: relative; } .formkit-form .formkit-powered-by-convertkit-container[data-active="false"] { - opacity: 0.35; + opacity: 0.35; } .formkit-form .formkit-powered-by-convertkit { - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - background-color: #ffffff; - border: 1px solid #dce1e5; - border-radius: 4px; - color: #373f45; - cursor: pointer; - display: block; - height: 36px; - margin: 0 auto; - opacity: 0.95; - padding: 0; - -webkit-text-decoration: none; - text-decoration: none; - text-indent: 100%; - -webkit-transition: ease-in-out all 200ms; - transition: ease-in-out all 200ms; - white-space: nowrap; - overflow: hidden; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: 190px; - background-repeat: no-repeat; - background-position: center; - background-image: url("data:image/svg+xml;charset=utf8,%3Csvg width='162' height='20' viewBox='0 0 162 20' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M83.0561 15.2457C86.675 15.2457 89.4722 12.5154 89.4722 9.14749C89.4722 5.99211 86.8443 4.06563 85.1038 4.06563C82.6801 4.06563 80.7373 5.76407 80.4605 8.28551C80.4092 8.75244 80.0387 9.14403 79.5686 9.14069C78.7871 9.13509 77.6507 9.12841 76.9314 9.13092C76.6217 9.13199 76.3658 8.88106 76.381 8.57196C76.4895 6.38513 77.2218 4.3404 78.618 2.76974C80.1695 1.02445 82.4289 0 85.1038 0C89.5979 0 93.8406 4.07791 93.8406 9.14749C93.8406 14.7608 89.1832 19.3113 83.1517 19.3113C78.8502 19.3113 74.5179 16.5041 73.0053 12.5795C72.9999 12.565 72.9986 12.5492 73.0015 12.534C73.0218 12.4179 73.0617 12.3118 73.1011 12.2074C73.1583 12.0555 73.2143 11.907 73.2062 11.7359L73.18 11.1892C73.174 11.0569 73.2075 10.9258 73.2764 10.8127C73.3452 10.6995 73.4463 10.6094 73.5666 10.554L73.7852 10.4523C73.9077 10.3957 74.0148 10.3105 74.0976 10.204C74.1803 10.0974 74.2363 9.97252 74.2608 9.83983C74.3341 9.43894 74.6865 9.14749 75.0979 9.14749C75.7404 9.14749 76.299 9.57412 76.5088 10.1806C77.5188 13.1 79.1245 15.2457 83.0561 15.2457Z' fill='%23373F45'/%3E%3Cpath d='M155.758 6.91365C155.028 6.91365 154.804 6.47916 154.804 5.98857C154.804 5.46997 154.986 5.06348 155.758 5.06348C156.53 5.06348 156.712 5.46997 156.712 5.98857C156.712 6.47905 156.516 6.91365 155.758 6.91365ZM142.441 12.9304V9.32833L141.415 9.32323V8.90392C141.415 8.44719 141.786 8.07758 142.244 8.07986L142.441 8.08095V6.55306L144.082 6.09057V8.08073H145.569V8.50416C145.569 8.61242 145.548 8.71961 145.506 8.81961C145.465 8.91961 145.404 9.01047 145.328 9.08699C145.251 9.16351 145.16 9.2242 145.06 9.26559C144.96 9.30698 144.853 9.32826 144.745 9.32822H144.082V12.7201C144.082 13.2423 144.378 13.4256 144.76 13.4887C145.209 13.5629 145.583 13.888 145.583 14.343V14.9626C144.029 14.9626 142.441 14.8942 142.441 12.9304Z' fill='%23373F45'/%3E%3Cpath d='M110.058 7.92554C108.417 7.88344 106.396 8.92062 106.396 11.5137C106.396 14.0646 108.417 15.0738 110.058 15.0318C111.742 15.0738 113.748 14.0646 113.748 11.5137C113.748 8.92062 111.742 7.88344 110.058 7.92554ZM110.07 13.7586C108.878 13.7586 108.032 12.8905 108.032 11.461C108.032 10.1013 108.878 9.20569 110.071 9.20569C111.263 9.20569 112.101 10.0995 112.101 11.459C112.101 12.8887 111.263 13.7586 110.07 13.7586Z' fill='%23373F45'/%3E%3Cpath d='M118.06 7.94098C119.491 7.94098 120.978 8.33337 120.978 11.1366V14.893H120.063C119.608 14.893 119.238 14.524 119.238 14.0689V10.9965C119.238 9.66506 118.747 9.16047 117.891 9.16047C117.414 9.16047 116.797 9.52486 116.502 9.81915V14.069C116.502 14.1773 116.481 14.2845 116.44 14.3845C116.398 14.4845 116.337 14.5753 116.261 14.6519C116.184 14.7284 116.093 14.7891 115.993 14.8305C115.893 14.8719 115.786 14.8931 115.678 14.8931H114.847V8.10918H115.773C115.932 8.10914 116.087 8.16315 116.212 8.26242C116.337 8.36168 116.424 8.50033 116.46 8.65577C116.881 8.19328 117.428 7.94098 118.06 7.94098ZM122.854 8.09713C123.024 8.09708 123.19 8.1496 123.329 8.2475C123.468 8.34541 123.574 8.48391 123.631 8.64405L125.133 12.8486L126.635 8.64415C126.692 8.48402 126.798 8.34551 126.937 8.2476C127.076 8.1497 127.242 8.09718 127.412 8.09724H128.598L126.152 14.3567C126.091 14.5112 125.986 14.6439 125.849 14.7374C125.711 14.831 125.549 14.881 125.383 14.8809H124.333L121.668 8.09713H122.854Z' fill='%23373F45'/%3E%3Cpath d='M135.085 14.5514C134.566 14.7616 133.513 15.0416 132.418 15.0416C130.496 15.0416 129.024 13.9345 129.024 11.4396C129.024 9.19701 130.451 7.99792 132.191 7.99792C134.338 7.99792 135.254 9.4378 135.158 11.3979C135.139 11.8029 134.786 12.0983 134.38 12.0983H130.679C130.763 13.1916 131.562 13.7662 132.615 13.7662C133.028 13.7662 133.462 13.7452 133.983 13.6481C134.535 13.545 135.085 13.9375 135.085 14.4985V14.5514ZM133.673 10.949C133.785 9.87621 133.061 9.28752 132.191 9.28752C131.321 9.28752 130.734 9.93979 130.679 10.9489L133.673 10.949Z' fill='%23373F45'/%3E%3Cpath d='M137.345 8.11122C137.497 8.11118 137.645 8.16229 137.765 8.25635C137.884 8.35041 137.969 8.48197 138.005 8.62993C138.566 8.20932 139.268 7.94303 139.759 7.94303C139.801 7.94303 140.068 7.94303 140.489 7.99913V8.7265C140.489 9.11748 140.15 9.4147 139.759 9.4147C139.31 9.4147 138.651 9.5829 138.131 9.8773V14.8951H136.462V8.11112L137.345 8.11122ZM156.6 14.0508V8.09104H155.769C155.314 8.09104 154.944 8.45999 154.944 8.9151V14.8748H155.775C156.23 14.8748 156.6 14.5058 156.6 14.0508ZM158.857 12.9447V9.34254H157.749V8.91912C157.749 8.46401 158.118 8.09506 158.574 8.09506H158.857V6.56739L160.499 6.10479V8.09506H161.986V8.51848C161.986 8.97359 161.617 9.34254 161.161 9.34254H160.499V12.7345C160.499 13.2566 160.795 13.44 161.177 13.503C161.626 13.5774 162 13.9024 162 14.3574V14.977C160.446 14.977 158.857 14.9086 158.857 12.9447ZM98.1929 10.1124C98.2033 6.94046 100.598 5.16809 102.895 5.16809C104.171 5.16809 105.342 5.44285 106.304 6.12953L105.914 6.6631C105.654 7.02011 105.16 7.16194 104.749 6.99949C104.169 6.7702 103.622 6.7218 103.215 6.7218C101.335 6.7218 99.9169 7.92849 99.9068 10.1123C99.9169 12.2959 101.335 13.5201 103.215 13.5201C103.622 13.5201 104.169 13.4717 104.749 13.2424C105.16 13.0799 105.654 13.2046 105.914 13.5615L106.304 14.0952C105.342 14.7819 104.171 15.0566 102.895 15.0566C100.598 15.0566 98.2033 13.2842 98.1929 10.1124ZM147.619 5.21768C148.074 5.21768 148.444 5.58663 148.444 6.04174V9.81968L151.82 5.58131C151.897 5.47733 151.997 5.39282 152.112 5.3346C152.227 5.27638 152.355 5.24607 152.484 5.24611H153.984L150.166 10.0615L153.984 14.8749H152.484C152.355 14.8749 152.227 14.8446 152.112 14.7864C151.997 14.7281 151.897 14.6436 151.82 14.5397L148.444 10.3025V14.0508C148.444 14.5059 148.074 14.8749 147.619 14.8749H146.746V5.21768H147.619Z' fill='%23373F45'/%3E%3Cpath d='M0.773438 6.5752H2.68066C3.56543 6.5752 4.2041 6.7041 4.59668 6.96191C4.99219 7.21973 5.18994 7.62695 5.18994 8.18359C5.18994 8.55859 5.09326 8.87061 4.8999 9.11963C4.70654 9.36865 4.42822 9.52539 4.06494 9.58984V9.63379C4.51611 9.71875 4.84717 9.88721 5.05811 10.1392C5.27197 10.3882 5.37891 10.7266 5.37891 11.1543C5.37891 11.7314 5.17676 12.1841 4.77246 12.5122C4.37109 12.8374 3.81152 13 3.09375 13H0.773438V6.5752ZM1.82373 9.22949H2.83447C3.27393 9.22949 3.59473 9.16064 3.79688 9.02295C3.99902 8.88232 4.1001 8.64502 4.1001 8.31104C4.1001 8.00928 3.99023 7.79102 3.77051 7.65625C3.55371 7.52148 3.20801 7.4541 2.7334 7.4541H1.82373V9.22949ZM1.82373 10.082V12.1167H2.93994C3.37939 12.1167 3.71045 12.0332 3.93311 11.8662C4.15869 11.6963 4.27148 11.4297 4.27148 11.0664C4.27148 10.7324 4.15723 10.4849 3.92871 10.3237C3.7002 10.1626 3.35303 10.082 2.88721 10.082H1.82373Z' fill='%23373F45'/%3E%3Cpath d='M13.011 6.5752V10.7324C13.011 11.207 12.9084 11.623 12.7034 11.9805C12.5012 12.335 12.2068 12.6089 11.8201 12.8022C11.4363 12.9927 10.9763 13.0879 10.4402 13.0879C9.6433 13.0879 9.02368 12.877 8.5813 12.4551C8.13892 12.0332 7.91772 11.4531 7.91772 10.7148V6.5752H8.9724V10.6401C8.9724 11.1704 9.09546 11.5615 9.34155 11.8135C9.58765 12.0654 9.96557 12.1914 10.4753 12.1914C11.4656 12.1914 11.9607 11.6714 11.9607 10.6313V6.5752H13.011Z' fill='%23373F45'/%3E%3Cpath d='M15.9146 13V6.5752H16.9649V13H15.9146Z' fill='%23373F45'/%3E%3Cpath d='M19.9255 13V6.5752H20.9758V12.0991H23.696V13H19.9255Z' fill='%23373F45'/%3E%3Cpath d='M28.2828 13H27.2325V7.47607H25.3428V6.5752H30.1724V7.47607H28.2828V13Z' fill='%23373F45'/%3E%3Cpath d='M41.9472 13H40.8046L39.7148 9.16796C39.6679 9.00097 39.6093 8.76074 39.539 8.44727C39.4687 8.13086 39.4262 7.91113 39.4116 7.78809C39.3823 7.97559 39.3339 8.21875 39.2665 8.51758C39.2021 8.81641 39.1479 9.03905 39.1039 9.18554L38.0405 13H36.8979L36.0673 9.7832L35.2236 6.5752H36.2958L37.2143 10.3193C37.3578 10.9199 37.4604 11.4502 37.5219 11.9102C37.5541 11.6611 37.6025 11.3828 37.6669 11.0752C37.7314 10.7676 37.79 10.5186 37.8427 10.3281L38.8886 6.5752H39.9301L41.0024 10.3457C41.1049 10.6943 41.2133 11.2158 41.3276 11.9102C41.3715 11.4912 41.477 10.958 41.644 10.3105L42.558 6.5752H43.6215L41.9472 13Z' fill='%23373F45'/%3E%3Cpath d='M45.7957 13V6.5752H46.846V13H45.7957Z' fill='%23373F45'/%3E%3Cpath d='M52.0258 13H50.9755V7.47607H49.0859V6.5752H53.9155V7.47607H52.0258V13Z' fill='%23373F45'/%3E%3Cpath d='M61.2312 13H60.1765V10.104H57.2146V13H56.1643V6.5752H57.2146V9.20312H60.1765V6.5752H61.2312V13Z' fill='%23373F45'/%3E%3C/svg%3E"); + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + background-color: #ffffff; + border: 1px solid #dce1e5; + border-radius: 4px; + color: #373f45; + cursor: pointer; + display: block; + height: 36px; + margin: 0 auto; + opacity: 0.95; + padding: 0; + -webkit-text-decoration: none; + text-decoration: none; + text-indent: 100%; + -webkit-transition: ease-in-out all 200ms; + transition: ease-in-out all 200ms; + white-space: nowrap; + overflow: hidden; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + width: 190px; + background-repeat: no-repeat; + background-position: center; + background-image: url("data:image/svg+xml;charset=utf8,%3Csvg width='162' height='20' viewBox='0 0 162 20' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M83.0561 15.2457C86.675 15.2457 89.4722 12.5154 89.4722 9.14749C89.4722 5.99211 86.8443 4.06563 85.1038 4.06563C82.6801 4.06563 80.7373 5.76407 80.4605 8.28551C80.4092 8.75244 80.0387 9.14403 79.5686 9.14069C78.7871 9.13509 77.6507 9.12841 76.9314 9.13092C76.6217 9.13199 76.3658 8.88106 76.381 8.57196C76.4895 6.38513 77.2218 4.3404 78.618 2.76974C80.1695 1.02445 82.4289 0 85.1038 0C89.5979 0 93.8406 4.07791 93.8406 9.14749C93.8406 14.7608 89.1832 19.3113 83.1517 19.3113C78.8502 19.3113 74.5179 16.5041 73.0053 12.5795C72.9999 12.565 72.9986 12.5492 73.0015 12.534C73.0218 12.4179 73.0617 12.3118 73.1011 12.2074C73.1583 12.0555 73.2143 11.907 73.2062 11.7359L73.18 11.1892C73.174 11.0569 73.2075 10.9258 73.2764 10.8127C73.3452 10.6995 73.4463 10.6094 73.5666 10.554L73.7852 10.4523C73.9077 10.3957 74.0148 10.3105 74.0976 10.204C74.1803 10.0974 74.2363 9.97252 74.2608 9.83983C74.3341 9.43894 74.6865 9.14749 75.0979 9.14749C75.7404 9.14749 76.299 9.57412 76.5088 10.1806C77.5188 13.1 79.1245 15.2457 83.0561 15.2457Z' fill='%23373F45'/%3E%3Cpath d='M155.758 6.91365C155.028 6.91365 154.804 6.47916 154.804 5.98857C154.804 5.46997 154.986 5.06348 155.758 5.06348C156.53 5.06348 156.712 5.46997 156.712 5.98857C156.712 6.47905 156.516 6.91365 155.758 6.91365ZM142.441 12.9304V9.32833L141.415 9.32323V8.90392C141.415 8.44719 141.786 8.07758 142.244 8.07986L142.441 8.08095V6.55306L144.082 6.09057V8.08073H145.569V8.50416C145.569 8.61242 145.548 8.71961 145.506 8.81961C145.465 8.91961 145.404 9.01047 145.328 9.08699C145.251 9.16351 145.16 9.2242 145.06 9.26559C144.96 9.30698 144.853 9.32826 144.745 9.32822H144.082V12.7201C144.082 13.2423 144.378 13.4256 144.76 13.4887C145.209 13.5629 145.583 13.888 145.583 14.343V14.9626C144.029 14.9626 142.441 14.8942 142.441 12.9304Z' fill='%23373F45'/%3E%3Cpath d='M110.058 7.92554C108.417 7.88344 106.396 8.92062 106.396 11.5137C106.396 14.0646 108.417 15.0738 110.058 15.0318C111.742 15.0738 113.748 14.0646 113.748 11.5137C113.748 8.92062 111.742 7.88344 110.058 7.92554ZM110.07 13.7586C108.878 13.7586 108.032 12.8905 108.032 11.461C108.032 10.1013 108.878 9.20569 110.071 9.20569C111.263 9.20569 112.101 10.0995 112.101 11.459C112.101 12.8887 111.263 13.7586 110.07 13.7586Z' fill='%23373F45'/%3E%3Cpath d='M118.06 7.94098C119.491 7.94098 120.978 8.33337 120.978 11.1366V14.893H120.063C119.608 14.893 119.238 14.524 119.238 14.0689V10.9965C119.238 9.66506 118.747 9.16047 117.891 9.16047C117.414 9.16047 116.797 9.52486 116.502 9.81915V14.069C116.502 14.1773 116.481 14.2845 116.44 14.3845C116.398 14.4845 116.337 14.5753 116.261 14.6519C116.184 14.7284 116.093 14.7891 115.993 14.8305C115.893 14.8719 115.786 14.8931 115.678 14.8931H114.847V8.10918H115.773C115.932 8.10914 116.087 8.16315 116.212 8.26242C116.337 8.36168 116.424 8.50033 116.46 8.65577C116.881 8.19328 117.428 7.94098 118.06 7.94098ZM122.854 8.09713C123.024 8.09708 123.19 8.1496 123.329 8.2475C123.468 8.34541 123.574 8.48391 123.631 8.64405L125.133 12.8486L126.635 8.64415C126.692 8.48402 126.798 8.34551 126.937 8.2476C127.076 8.1497 127.242 8.09718 127.412 8.09724H128.598L126.152 14.3567C126.091 14.5112 125.986 14.6439 125.849 14.7374C125.711 14.831 125.549 14.881 125.383 14.8809H124.333L121.668 8.09713H122.854Z' fill='%23373F45'/%3E%3Cpath d='M135.085 14.5514C134.566 14.7616 133.513 15.0416 132.418 15.0416C130.496 15.0416 129.024 13.9345 129.024 11.4396C129.024 9.19701 130.451 7.99792 132.191 7.99792C134.338 7.99792 135.254 9.4378 135.158 11.3979C135.139 11.8029 134.786 12.0983 134.38 12.0983H130.679C130.763 13.1916 131.562 13.7662 132.615 13.7662C133.028 13.7662 133.462 13.7452 133.983 13.6481C134.535 13.545 135.085 13.9375 135.085 14.4985V14.5514ZM133.673 10.949C133.785 9.87621 133.061 9.28752 132.191 9.28752C131.321 9.28752 130.734 9.93979 130.679 10.9489L133.673 10.949Z' fill='%23373F45'/%3E%3Cpath d='M137.345 8.11122C137.497 8.11118 137.645 8.16229 137.765 8.25635C137.884 8.35041 137.969 8.48197 138.005 8.62993C138.566 8.20932 139.268 7.94303 139.759 7.94303C139.801 7.94303 140.068 7.94303 140.489 7.99913V8.7265C140.489 9.11748 140.15 9.4147 139.759 9.4147C139.31 9.4147 138.651 9.5829 138.131 9.8773V14.8951H136.462V8.11112L137.345 8.11122ZM156.6 14.0508V8.09104H155.769C155.314 8.09104 154.944 8.45999 154.944 8.9151V14.8748H155.775C156.23 14.8748 156.6 14.5058 156.6 14.0508ZM158.857 12.9447V9.34254H157.749V8.91912C157.749 8.46401 158.118 8.09506 158.574 8.09506H158.857V6.56739L160.499 6.10479V8.09506H161.986V8.51848C161.986 8.97359 161.617 9.34254 161.161 9.34254H160.499V12.7345C160.499 13.2566 160.795 13.44 161.177 13.503C161.626 13.5774 162 13.9024 162 14.3574V14.977C160.446 14.977 158.857 14.9086 158.857 12.9447ZM98.1929 10.1124C98.2033 6.94046 100.598 5.16809 102.895 5.16809C104.171 5.16809 105.342 5.44285 106.304 6.12953L105.914 6.6631C105.654 7.02011 105.16 7.16194 104.749 6.99949C104.169 6.7702 103.622 6.7218 103.215 6.7218C101.335 6.7218 99.9169 7.92849 99.9068 10.1123C99.9169 12.2959 101.335 13.5201 103.215 13.5201C103.622 13.5201 104.169 13.4717 104.749 13.2424C105.16 13.0799 105.654 13.2046 105.914 13.5615L106.304 14.0952C105.342 14.7819 104.171 15.0566 102.895 15.0566C100.598 15.0566 98.2033 13.2842 98.1929 10.1124ZM147.619 5.21768C148.074 5.21768 148.444 5.58663 148.444 6.04174V9.81968L151.82 5.58131C151.897 5.47733 151.997 5.39282 152.112 5.3346C152.227 5.27638 152.355 5.24607 152.484 5.24611H153.984L150.166 10.0615L153.984 14.8749H152.484C152.355 14.8749 152.227 14.8446 152.112 14.7864C151.997 14.7281 151.897 14.6436 151.82 14.5397L148.444 10.3025V14.0508C148.444 14.5059 148.074 14.8749 147.619 14.8749H146.746V5.21768H147.619Z' fill='%23373F45'/%3E%3Cpath d='M0.773438 6.5752H2.68066C3.56543 6.5752 4.2041 6.7041 4.59668 6.96191C4.99219 7.21973 5.18994 7.62695 5.18994 8.18359C5.18994 8.55859 5.09326 8.87061 4.8999 9.11963C4.70654 9.36865 4.42822 9.52539 4.06494 9.58984V9.63379C4.51611 9.71875 4.84717 9.88721 5.05811 10.1392C5.27197 10.3882 5.37891 10.7266 5.37891 11.1543C5.37891 11.7314 5.17676 12.1841 4.77246 12.5122C4.37109 12.8374 3.81152 13 3.09375 13H0.773438V6.5752ZM1.82373 9.22949H2.83447C3.27393 9.22949 3.59473 9.16064 3.79688 9.02295C3.99902 8.88232 4.1001 8.64502 4.1001 8.31104C4.1001 8.00928 3.99023 7.79102 3.77051 7.65625C3.55371 7.52148 3.20801 7.4541 2.7334 7.4541H1.82373V9.22949ZM1.82373 10.082V12.1167H2.93994C3.37939 12.1167 3.71045 12.0332 3.93311 11.8662C4.15869 11.6963 4.27148 11.4297 4.27148 11.0664C4.27148 10.7324 4.15723 10.4849 3.92871 10.3237C3.7002 10.1626 3.35303 10.082 2.88721 10.082H1.82373Z' fill='%23373F45'/%3E%3Cpath d='M13.011 6.5752V10.7324C13.011 11.207 12.9084 11.623 12.7034 11.9805C12.5012 12.335 12.2068 12.6089 11.8201 12.8022C11.4363 12.9927 10.9763 13.0879 10.4402 13.0879C9.6433 13.0879 9.02368 12.877 8.5813 12.4551C8.13892 12.0332 7.91772 11.4531 7.91772 10.7148V6.5752H8.9724V10.6401C8.9724 11.1704 9.09546 11.5615 9.34155 11.8135C9.58765 12.0654 9.96557 12.1914 10.4753 12.1914C11.4656 12.1914 11.9607 11.6714 11.9607 10.6313V6.5752H13.011Z' fill='%23373F45'/%3E%3Cpath d='M15.9146 13V6.5752H16.9649V13H15.9146Z' fill='%23373F45'/%3E%3Cpath d='M19.9255 13V6.5752H20.9758V12.0991H23.696V13H19.9255Z' fill='%23373F45'/%3E%3Cpath d='M28.2828 13H27.2325V7.47607H25.3428V6.5752H30.1724V7.47607H28.2828V13Z' fill='%23373F45'/%3E%3Cpath d='M41.9472 13H40.8046L39.7148 9.16796C39.6679 9.00097 39.6093 8.76074 39.539 8.44727C39.4687 8.13086 39.4262 7.91113 39.4116 7.78809C39.3823 7.97559 39.3339 8.21875 39.2665 8.51758C39.2021 8.81641 39.1479 9.03905 39.1039 9.18554L38.0405 13H36.8979L36.0673 9.7832L35.2236 6.5752H36.2958L37.2143 10.3193C37.3578 10.9199 37.4604 11.4502 37.5219 11.9102C37.5541 11.6611 37.6025 11.3828 37.6669 11.0752C37.7314 10.7676 37.79 10.5186 37.8427 10.3281L38.8886 6.5752H39.9301L41.0024 10.3457C41.1049 10.6943 41.2133 11.2158 41.3276 11.9102C41.3715 11.4912 41.477 10.958 41.644 10.3105L42.558 6.5752H43.6215L41.9472 13Z' fill='%23373F45'/%3E%3Cpath d='M45.7957 13V6.5752H46.846V13H45.7957Z' fill='%23373F45'/%3E%3Cpath d='M52.0258 13H50.9755V7.47607H49.0859V6.5752H53.9155V7.47607H52.0258V13Z' fill='%23373F45'/%3E%3Cpath d='M61.2312 13H60.1765V10.104H57.2146V13H56.1643V6.5752H57.2146V9.20312H60.1765V6.5752H61.2312V13Z' fill='%23373F45'/%3E%3C/svg%3E"); } .formkit-form .formkit-powered-by-convertkit:hover, .formkit-form .formkit-powered-by-convertkit:focus { - background-color: #ffffff; - -webkit-transform: scale(1.025) perspective(1px); - -ms-transform: scale(1.025) perspective(1px); - transform: scale(1.025) perspective(1px); - opacity: 1; + background-color: #ffffff; + -webkit-transform: scale(1.025) perspective(1px); + -ms-transform: scale(1.025) perspective(1px); + transform: scale(1.025) perspective(1px); + opacity: 1; } .formkit-form .formkit-powered-by-convertkit[data-variant="dark"], .formkit-form .formkit-powered-by-convertkit[data-variant="light"] { - background-color: transparent; - border-color: transparent; - width: 166px; + background-color: transparent; + border-color: transparent; + width: 166px; } .formkit-form .formkit-powered-by-convertkit[data-variant="light"] { - color: #ffffff; - background-image: url("data:image/svg+xml;charset=utf8,%3Csvg width='162' height='20' viewBox='0 0 162 20' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M83.0561 15.2457C86.675 15.2457 89.4722 12.5154 89.4722 9.14749C89.4722 5.99211 86.8443 4.06563 85.1038 4.06563C82.6801 4.06563 80.7373 5.76407 80.4605 8.28551C80.4092 8.75244 80.0387 9.14403 79.5686 9.14069C78.7871 9.13509 77.6507 9.12841 76.9314 9.13092C76.6217 9.13199 76.3658 8.88106 76.381 8.57196C76.4895 6.38513 77.2218 4.3404 78.618 2.76974C80.1695 1.02445 82.4289 0 85.1038 0C89.5979 0 93.8406 4.07791 93.8406 9.14749C93.8406 14.7608 89.1832 19.3113 83.1517 19.3113C78.8502 19.3113 74.5179 16.5041 73.0053 12.5795C72.9999 12.565 72.9986 12.5492 73.0015 12.534C73.0218 12.4179 73.0617 12.3118 73.1011 12.2074C73.1583 12.0555 73.2143 11.907 73.2062 11.7359L73.18 11.1892C73.174 11.0569 73.2075 10.9258 73.2764 10.8127C73.3452 10.6995 73.4463 10.6094 73.5666 10.554L73.7852 10.4523C73.9077 10.3957 74.0148 10.3105 74.0976 10.204C74.1803 10.0974 74.2363 9.97252 74.2608 9.83983C74.3341 9.43894 74.6865 9.14749 75.0979 9.14749C75.7404 9.14749 76.299 9.57412 76.5088 10.1806C77.5188 13.1 79.1245 15.2457 83.0561 15.2457Z' fill='white'/%3E%3Cpath d='M155.758 6.91365C155.028 6.91365 154.804 6.47916 154.804 5.98857C154.804 5.46997 154.986 5.06348 155.758 5.06348C156.53 5.06348 156.712 5.46997 156.712 5.98857C156.712 6.47905 156.516 6.91365 155.758 6.91365ZM142.441 12.9304V9.32833L141.415 9.32323V8.90392C141.415 8.44719 141.786 8.07758 142.244 8.07986L142.441 8.08095V6.55306L144.082 6.09057V8.08073H145.569V8.50416C145.569 8.61242 145.548 8.71961 145.506 8.81961C145.465 8.91961 145.404 9.01047 145.328 9.08699C145.251 9.16351 145.16 9.2242 145.06 9.26559C144.96 9.30698 144.853 9.32826 144.745 9.32822H144.082V12.7201C144.082 13.2423 144.378 13.4256 144.76 13.4887C145.209 13.5629 145.583 13.888 145.583 14.343V14.9626C144.029 14.9626 142.441 14.8942 142.441 12.9304Z' fill='white'/%3E%3Cpath d='M110.058 7.92554C108.417 7.88344 106.396 8.92062 106.396 11.5137C106.396 14.0646 108.417 15.0738 110.058 15.0318C111.742 15.0738 113.748 14.0646 113.748 11.5137C113.748 8.92062 111.742 7.88344 110.058 7.92554ZM110.07 13.7586C108.878 13.7586 108.032 12.8905 108.032 11.461C108.032 10.1013 108.878 9.20569 110.071 9.20569C111.263 9.20569 112.101 10.0995 112.101 11.459C112.101 12.8887 111.263 13.7586 110.07 13.7586Z' fill='white'/%3E%3Cpath d='M118.06 7.94098C119.491 7.94098 120.978 8.33337 120.978 11.1366V14.893H120.063C119.608 14.893 119.238 14.524 119.238 14.0689V10.9965C119.238 9.66506 118.747 9.16047 117.891 9.16047C117.414 9.16047 116.797 9.52486 116.502 9.81915V14.069C116.502 14.1773 116.481 14.2845 116.44 14.3845C116.398 14.4845 116.337 14.5753 116.261 14.6519C116.184 14.7284 116.093 14.7891 115.993 14.8305C115.893 14.8719 115.786 14.8931 115.678 14.8931H114.847V8.10918H115.773C115.932 8.10914 116.087 8.16315 116.212 8.26242C116.337 8.36168 116.424 8.50033 116.46 8.65577C116.881 8.19328 117.428 7.94098 118.06 7.94098ZM122.854 8.09713C123.024 8.09708 123.19 8.1496 123.329 8.2475C123.468 8.34541 123.574 8.48391 123.631 8.64405L125.133 12.8486L126.635 8.64415C126.692 8.48402 126.798 8.34551 126.937 8.2476C127.076 8.1497 127.242 8.09718 127.412 8.09724H128.598L126.152 14.3567C126.091 14.5112 125.986 14.6439 125.849 14.7374C125.711 14.831 125.549 14.881 125.383 14.8809H124.333L121.668 8.09713H122.854Z' fill='white'/%3E%3Cpath d='M135.085 14.5514C134.566 14.7616 133.513 15.0416 132.418 15.0416C130.496 15.0416 129.024 13.9345 129.024 11.4396C129.024 9.19701 130.451 7.99792 132.191 7.99792C134.338 7.99792 135.254 9.4378 135.158 11.3979C135.139 11.8029 134.786 12.0983 134.38 12.0983H130.679C130.763 13.1916 131.562 13.7662 132.615 13.7662C133.028 13.7662 133.462 13.7452 133.983 13.6481C134.535 13.545 135.085 13.9375 135.085 14.4985V14.5514ZM133.673 10.949C133.785 9.87621 133.061 9.28752 132.191 9.28752C131.321 9.28752 130.734 9.93979 130.679 10.9489L133.673 10.949Z' fill='white'/%3E%3Cpath d='M137.345 8.11122C137.497 8.11118 137.645 8.16229 137.765 8.25635C137.884 8.35041 137.969 8.48197 138.005 8.62993C138.566 8.20932 139.268 7.94303 139.759 7.94303C139.801 7.94303 140.068 7.94303 140.489 7.99913V8.7265C140.489 9.11748 140.15 9.4147 139.759 9.4147C139.31 9.4147 138.651 9.5829 138.131 9.8773V14.8951H136.462V8.11112L137.345 8.11122ZM156.6 14.0508V8.09104H155.769C155.314 8.09104 154.944 8.45999 154.944 8.9151V14.8748H155.775C156.23 14.8748 156.6 14.5058 156.6 14.0508ZM158.857 12.9447V9.34254H157.749V8.91912C157.749 8.46401 158.118 8.09506 158.574 8.09506H158.857V6.56739L160.499 6.10479V8.09506H161.986V8.51848C161.986 8.97359 161.617 9.34254 161.161 9.34254H160.499V12.7345C160.499 13.2566 160.795 13.44 161.177 13.503C161.626 13.5774 162 13.9024 162 14.3574V14.977C160.446 14.977 158.857 14.9086 158.857 12.9447ZM98.1929 10.1124C98.2033 6.94046 100.598 5.16809 102.895 5.16809C104.171 5.16809 105.342 5.44285 106.304 6.12953L105.914 6.6631C105.654 7.02011 105.16 7.16194 104.749 6.99949C104.169 6.7702 103.622 6.7218 103.215 6.7218C101.335 6.7218 99.9169 7.92849 99.9068 10.1123C99.9169 12.2959 101.335 13.5201 103.215 13.5201C103.622 13.5201 104.169 13.4717 104.749 13.2424C105.16 13.0799 105.654 13.2046 105.914 13.5615L106.304 14.0952C105.342 14.7819 104.171 15.0566 102.895 15.0566C100.598 15.0566 98.2033 13.2842 98.1929 10.1124ZM147.619 5.21768C148.074 5.21768 148.444 5.58663 148.444 6.04174V9.81968L151.82 5.58131C151.897 5.47733 151.997 5.39282 152.112 5.3346C152.227 5.27638 152.355 5.24607 152.484 5.24611H153.984L150.166 10.0615L153.984 14.8749H152.484C152.355 14.8749 152.227 14.8446 152.112 14.7864C151.997 14.7281 151.897 14.6436 151.82 14.5397L148.444 10.3025V14.0508C148.444 14.5059 148.074 14.8749 147.619 14.8749H146.746V5.21768H147.619Z' fill='white'/%3E%3Cpath d='M0.773438 6.5752H2.68066C3.56543 6.5752 4.2041 6.7041 4.59668 6.96191C4.99219 7.21973 5.18994 7.62695 5.18994 8.18359C5.18994 8.55859 5.09326 8.87061 4.8999 9.11963C4.70654 9.36865 4.42822 9.52539 4.06494 9.58984V9.63379C4.51611 9.71875 4.84717 9.88721 5.05811 10.1392C5.27197 10.3882 5.37891 10.7266 5.37891 11.1543C5.37891 11.7314 5.17676 12.1841 4.77246 12.5122C4.37109 12.8374 3.81152 13 3.09375 13H0.773438V6.5752ZM1.82373 9.22949H2.83447C3.27393 9.22949 3.59473 9.16064 3.79688 9.02295C3.99902 8.88232 4.1001 8.64502 4.1001 8.31104C4.1001 8.00928 3.99023 7.79102 3.77051 7.65625C3.55371 7.52148 3.20801 7.4541 2.7334 7.4541H1.82373V9.22949ZM1.82373 10.082V12.1167H2.93994C3.37939 12.1167 3.71045 12.0332 3.93311 11.8662C4.15869 11.6963 4.27148 11.4297 4.27148 11.0664C4.27148 10.7324 4.15723 10.4849 3.92871 10.3237C3.7002 10.1626 3.35303 10.082 2.88721 10.082H1.82373Z' fill='white'/%3E%3Cpath d='M13.011 6.5752V10.7324C13.011 11.207 12.9084 11.623 12.7034 11.9805C12.5012 12.335 12.2068 12.6089 11.8201 12.8022C11.4363 12.9927 10.9763 13.0879 10.4402 13.0879C9.6433 13.0879 9.02368 12.877 8.5813 12.4551C8.13892 12.0332 7.91772 11.4531 7.91772 10.7148V6.5752H8.9724V10.6401C8.9724 11.1704 9.09546 11.5615 9.34155 11.8135C9.58765 12.0654 9.96557 12.1914 10.4753 12.1914C11.4656 12.1914 11.9607 11.6714 11.9607 10.6313V6.5752H13.011Z' fill='white'/%3E%3Cpath d='M15.9146 13V6.5752H16.9649V13H15.9146Z' fill='white'/%3E%3Cpath d='M19.9255 13V6.5752H20.9758V12.0991H23.696V13H19.9255Z' fill='white'/%3E%3Cpath d='M28.2828 13H27.2325V7.47607H25.3428V6.5752H30.1724V7.47607H28.2828V13Z' fill='white'/%3E%3Cpath d='M41.9472 13H40.8046L39.7148 9.16796C39.6679 9.00097 39.6093 8.76074 39.539 8.44727C39.4687 8.13086 39.4262 7.91113 39.4116 7.78809C39.3823 7.97559 39.3339 8.21875 39.2665 8.51758C39.2021 8.81641 39.1479 9.03905 39.1039 9.18554L38.0405 13H36.8979L36.0673 9.7832L35.2236 6.5752H36.2958L37.2143 10.3193C37.3578 10.9199 37.4604 11.4502 37.5219 11.9102C37.5541 11.6611 37.6025 11.3828 37.6669 11.0752C37.7314 10.7676 37.79 10.5186 37.8427 10.3281L38.8886 6.5752H39.9301L41.0024 10.3457C41.1049 10.6943 41.2133 11.2158 41.3276 11.9102C41.3715 11.4912 41.477 10.958 41.644 10.3105L42.558 6.5752H43.6215L41.9472 13Z' fill='white'/%3E%3Cpath d='M45.7957 13V6.5752H46.846V13H45.7957Z' fill='white'/%3E%3Cpath d='M52.0258 13H50.9755V7.47607H49.0859V6.5752H53.9155V7.47607H52.0258V13Z' fill='white'/%3E%3Cpath d='M61.2312 13H60.1765V10.104H57.2146V13H56.1643V6.5752H57.2146V9.20312H60.1765V6.5752H61.2312V13Z' fill='white'/%3E%3C/svg%3E"); + color: #ffffff; + background-image: url("data:image/svg+xml;charset=utf8,%3Csvg width='162' height='20' viewBox='0 0 162 20' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M83.0561 15.2457C86.675 15.2457 89.4722 12.5154 89.4722 9.14749C89.4722 5.99211 86.8443 4.06563 85.1038 4.06563C82.6801 4.06563 80.7373 5.76407 80.4605 8.28551C80.4092 8.75244 80.0387 9.14403 79.5686 9.14069C78.7871 9.13509 77.6507 9.12841 76.9314 9.13092C76.6217 9.13199 76.3658 8.88106 76.381 8.57196C76.4895 6.38513 77.2218 4.3404 78.618 2.76974C80.1695 1.02445 82.4289 0 85.1038 0C89.5979 0 93.8406 4.07791 93.8406 9.14749C93.8406 14.7608 89.1832 19.3113 83.1517 19.3113C78.8502 19.3113 74.5179 16.5041 73.0053 12.5795C72.9999 12.565 72.9986 12.5492 73.0015 12.534C73.0218 12.4179 73.0617 12.3118 73.1011 12.2074C73.1583 12.0555 73.2143 11.907 73.2062 11.7359L73.18 11.1892C73.174 11.0569 73.2075 10.9258 73.2764 10.8127C73.3452 10.6995 73.4463 10.6094 73.5666 10.554L73.7852 10.4523C73.9077 10.3957 74.0148 10.3105 74.0976 10.204C74.1803 10.0974 74.2363 9.97252 74.2608 9.83983C74.3341 9.43894 74.6865 9.14749 75.0979 9.14749C75.7404 9.14749 76.299 9.57412 76.5088 10.1806C77.5188 13.1 79.1245 15.2457 83.0561 15.2457Z' fill='white'/%3E%3Cpath d='M155.758 6.91365C155.028 6.91365 154.804 6.47916 154.804 5.98857C154.804 5.46997 154.986 5.06348 155.758 5.06348C156.53 5.06348 156.712 5.46997 156.712 5.98857C156.712 6.47905 156.516 6.91365 155.758 6.91365ZM142.441 12.9304V9.32833L141.415 9.32323V8.90392C141.415 8.44719 141.786 8.07758 142.244 8.07986L142.441 8.08095V6.55306L144.082 6.09057V8.08073H145.569V8.50416C145.569 8.61242 145.548 8.71961 145.506 8.81961C145.465 8.91961 145.404 9.01047 145.328 9.08699C145.251 9.16351 145.16 9.2242 145.06 9.26559C144.96 9.30698 144.853 9.32826 144.745 9.32822H144.082V12.7201C144.082 13.2423 144.378 13.4256 144.76 13.4887C145.209 13.5629 145.583 13.888 145.583 14.343V14.9626C144.029 14.9626 142.441 14.8942 142.441 12.9304Z' fill='white'/%3E%3Cpath d='M110.058 7.92554C108.417 7.88344 106.396 8.92062 106.396 11.5137C106.396 14.0646 108.417 15.0738 110.058 15.0318C111.742 15.0738 113.748 14.0646 113.748 11.5137C113.748 8.92062 111.742 7.88344 110.058 7.92554ZM110.07 13.7586C108.878 13.7586 108.032 12.8905 108.032 11.461C108.032 10.1013 108.878 9.20569 110.071 9.20569C111.263 9.20569 112.101 10.0995 112.101 11.459C112.101 12.8887 111.263 13.7586 110.07 13.7586Z' fill='white'/%3E%3Cpath d='M118.06 7.94098C119.491 7.94098 120.978 8.33337 120.978 11.1366V14.893H120.063C119.608 14.893 119.238 14.524 119.238 14.0689V10.9965C119.238 9.66506 118.747 9.16047 117.891 9.16047C117.414 9.16047 116.797 9.52486 116.502 9.81915V14.069C116.502 14.1773 116.481 14.2845 116.44 14.3845C116.398 14.4845 116.337 14.5753 116.261 14.6519C116.184 14.7284 116.093 14.7891 115.993 14.8305C115.893 14.8719 115.786 14.8931 115.678 14.8931H114.847V8.10918H115.773C115.932 8.10914 116.087 8.16315 116.212 8.26242C116.337 8.36168 116.424 8.50033 116.46 8.65577C116.881 8.19328 117.428 7.94098 118.06 7.94098ZM122.854 8.09713C123.024 8.09708 123.19 8.1496 123.329 8.2475C123.468 8.34541 123.574 8.48391 123.631 8.64405L125.133 12.8486L126.635 8.64415C126.692 8.48402 126.798 8.34551 126.937 8.2476C127.076 8.1497 127.242 8.09718 127.412 8.09724H128.598L126.152 14.3567C126.091 14.5112 125.986 14.6439 125.849 14.7374C125.711 14.831 125.549 14.881 125.383 14.8809H124.333L121.668 8.09713H122.854Z' fill='white'/%3E%3Cpath d='M135.085 14.5514C134.566 14.7616 133.513 15.0416 132.418 15.0416C130.496 15.0416 129.024 13.9345 129.024 11.4396C129.024 9.19701 130.451 7.99792 132.191 7.99792C134.338 7.99792 135.254 9.4378 135.158 11.3979C135.139 11.8029 134.786 12.0983 134.38 12.0983H130.679C130.763 13.1916 131.562 13.7662 132.615 13.7662C133.028 13.7662 133.462 13.7452 133.983 13.6481C134.535 13.545 135.085 13.9375 135.085 14.4985V14.5514ZM133.673 10.949C133.785 9.87621 133.061 9.28752 132.191 9.28752C131.321 9.28752 130.734 9.93979 130.679 10.9489L133.673 10.949Z' fill='white'/%3E%3Cpath d='M137.345 8.11122C137.497 8.11118 137.645 8.16229 137.765 8.25635C137.884 8.35041 137.969 8.48197 138.005 8.62993C138.566 8.20932 139.268 7.94303 139.759 7.94303C139.801 7.94303 140.068 7.94303 140.489 7.99913V8.7265C140.489 9.11748 140.15 9.4147 139.759 9.4147C139.31 9.4147 138.651 9.5829 138.131 9.8773V14.8951H136.462V8.11112L137.345 8.11122ZM156.6 14.0508V8.09104H155.769C155.314 8.09104 154.944 8.45999 154.944 8.9151V14.8748H155.775C156.23 14.8748 156.6 14.5058 156.6 14.0508ZM158.857 12.9447V9.34254H157.749V8.91912C157.749 8.46401 158.118 8.09506 158.574 8.09506H158.857V6.56739L160.499 6.10479V8.09506H161.986V8.51848C161.986 8.97359 161.617 9.34254 161.161 9.34254H160.499V12.7345C160.499 13.2566 160.795 13.44 161.177 13.503C161.626 13.5774 162 13.9024 162 14.3574V14.977C160.446 14.977 158.857 14.9086 158.857 12.9447ZM98.1929 10.1124C98.2033 6.94046 100.598 5.16809 102.895 5.16809C104.171 5.16809 105.342 5.44285 106.304 6.12953L105.914 6.6631C105.654 7.02011 105.16 7.16194 104.749 6.99949C104.169 6.7702 103.622 6.7218 103.215 6.7218C101.335 6.7218 99.9169 7.92849 99.9068 10.1123C99.9169 12.2959 101.335 13.5201 103.215 13.5201C103.622 13.5201 104.169 13.4717 104.749 13.2424C105.16 13.0799 105.654 13.2046 105.914 13.5615L106.304 14.0952C105.342 14.7819 104.171 15.0566 102.895 15.0566C100.598 15.0566 98.2033 13.2842 98.1929 10.1124ZM147.619 5.21768C148.074 5.21768 148.444 5.58663 148.444 6.04174V9.81968L151.82 5.58131C151.897 5.47733 151.997 5.39282 152.112 5.3346C152.227 5.27638 152.355 5.24607 152.484 5.24611H153.984L150.166 10.0615L153.984 14.8749H152.484C152.355 14.8749 152.227 14.8446 152.112 14.7864C151.997 14.7281 151.897 14.6436 151.82 14.5397L148.444 10.3025V14.0508C148.444 14.5059 148.074 14.8749 147.619 14.8749H146.746V5.21768H147.619Z' fill='white'/%3E%3Cpath d='M0.773438 6.5752H2.68066C3.56543 6.5752 4.2041 6.7041 4.59668 6.96191C4.99219 7.21973 5.18994 7.62695 5.18994 8.18359C5.18994 8.55859 5.09326 8.87061 4.8999 9.11963C4.70654 9.36865 4.42822 9.52539 4.06494 9.58984V9.63379C4.51611 9.71875 4.84717 9.88721 5.05811 10.1392C5.27197 10.3882 5.37891 10.7266 5.37891 11.1543C5.37891 11.7314 5.17676 12.1841 4.77246 12.5122C4.37109 12.8374 3.81152 13 3.09375 13H0.773438V6.5752ZM1.82373 9.22949H2.83447C3.27393 9.22949 3.59473 9.16064 3.79688 9.02295C3.99902 8.88232 4.1001 8.64502 4.1001 8.31104C4.1001 8.00928 3.99023 7.79102 3.77051 7.65625C3.55371 7.52148 3.20801 7.4541 2.7334 7.4541H1.82373V9.22949ZM1.82373 10.082V12.1167H2.93994C3.37939 12.1167 3.71045 12.0332 3.93311 11.8662C4.15869 11.6963 4.27148 11.4297 4.27148 11.0664C4.27148 10.7324 4.15723 10.4849 3.92871 10.3237C3.7002 10.1626 3.35303 10.082 2.88721 10.082H1.82373Z' fill='white'/%3E%3Cpath d='M13.011 6.5752V10.7324C13.011 11.207 12.9084 11.623 12.7034 11.9805C12.5012 12.335 12.2068 12.6089 11.8201 12.8022C11.4363 12.9927 10.9763 13.0879 10.4402 13.0879C9.6433 13.0879 9.02368 12.877 8.5813 12.4551C8.13892 12.0332 7.91772 11.4531 7.91772 10.7148V6.5752H8.9724V10.6401C8.9724 11.1704 9.09546 11.5615 9.34155 11.8135C9.58765 12.0654 9.96557 12.1914 10.4753 12.1914C11.4656 12.1914 11.9607 11.6714 11.9607 10.6313V6.5752H13.011Z' fill='white'/%3E%3Cpath d='M15.9146 13V6.5752H16.9649V13H15.9146Z' fill='white'/%3E%3Cpath d='M19.9255 13V6.5752H20.9758V12.0991H23.696V13H19.9255Z' fill='white'/%3E%3Cpath d='M28.2828 13H27.2325V7.47607H25.3428V6.5752H30.1724V7.47607H28.2828V13Z' fill='white'/%3E%3Cpath d='M41.9472 13H40.8046L39.7148 9.16796C39.6679 9.00097 39.6093 8.76074 39.539 8.44727C39.4687 8.13086 39.4262 7.91113 39.4116 7.78809C39.3823 7.97559 39.3339 8.21875 39.2665 8.51758C39.2021 8.81641 39.1479 9.03905 39.1039 9.18554L38.0405 13H36.8979L36.0673 9.7832L35.2236 6.5752H36.2958L37.2143 10.3193C37.3578 10.9199 37.4604 11.4502 37.5219 11.9102C37.5541 11.6611 37.6025 11.3828 37.6669 11.0752C37.7314 10.7676 37.79 10.5186 37.8427 10.3281L38.8886 6.5752H39.9301L41.0024 10.3457C41.1049 10.6943 41.2133 11.2158 41.3276 11.9102C41.3715 11.4912 41.477 10.958 41.644 10.3105L42.558 6.5752H43.6215L41.9472 13Z' fill='white'/%3E%3Cpath d='M45.7957 13V6.5752H46.846V13H45.7957Z' fill='white'/%3E%3Cpath d='M52.0258 13H50.9755V7.47607H49.0859V6.5752H53.9155V7.47607H52.0258V13Z' fill='white'/%3E%3Cpath d='M61.2312 13H60.1765V10.104H57.2146V13H56.1643V6.5752H57.2146V9.20312H60.1765V6.5752H61.2312V13Z' fill='white'/%3E%3C/svg%3E"); } @-webkit-keyframes formkit-bouncedelay-formkit-form-data-uid-882d42bb6f- { + 0%, + 80%, + 100% { + -webkit-transform: scale(0); + -ms-transform: scale(0); + transform: scale(0); + } - 0%, - 80%, - 100% { - -webkit-transform: scale(0); - -ms-transform: scale(0); - transform: scale(0); - } - - 40% { - -webkit-transform: scale(1); - -ms-transform: scale(1); - transform: scale(1); - } + 40% { + -webkit-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } } @keyframes formkit-bouncedelay-formkit-form-data-uid-882d42bb6f- { + 0%, + 80%, + 100% { + -webkit-transform: scale(0); + -ms-transform: scale(0); + transform: scale(0); + } - 0%, - 80%, - 100% { - -webkit-transform: scale(0); - -ms-transform: scale(0); - transform: scale(0); - } - - 40% { - -webkit-transform: scale(1); - -ms-transform: scale(1); - transform: scale(1); - } + 40% { + -webkit-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } } .formkit-form blockquote { - padding: 10px 20px; - margin: 0 0 20px; - border-left: 5px solid #e1e1e1; + padding: 10px 20px; + margin: 0 0 20px; + border-left: 5px solid #e1e1e1; } .formkit-form .seva-custom-content { - padding: 15px; - font-size: 16px; - color: #fff; - mix-blend-mode: difference; + padding: 15px; + font-size: 16px; + color: #fff; + mix-blend-mode: difference; } .formkit-form { - max-width: 700px; + max-width: 700px; } .formkit-form [data-style="clean"] { - width: 100%; + width: 100%; } .formkit-form .formkit-fields { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-wrap: wrap; - -ms-flex-wrap: wrap; - flex-wrap: wrap; - margin: 0 auto; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-wrap: wrap; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + margin: 0 auto; } .formkit-form .formkit-field, .formkit-form .formkit-submit { - margin: 0 0 15px 0; - -webkit-flex: 1 0 100%; - -ms-flex: 1 0 100%; - flex: 1 0 100%; + margin: 0 0 15px 0; + -webkit-flex: 1 0 100%; + -ms-flex: 1 0 100%; + flex: 1 0 100%; } .formkit-form .formkit-powered-by-convertkit-container { - margin: 0; + margin: 0; } .formkit-form .formkit-submit { - position: static; + position: static; } .formkit-form[min-width~="700"] [data-style="clean"], .formkit-form[min-width~="800"] [data-style="clean"] { - padding: 10px; + padding: 10px; } .formkit-form[min-width~="700"] .formkit-fields[data-stacked="false"], .formkit-form[min-width~="800"] .formkit-fields[data-stacked="false"] { - margin-left: -5px; - margin-right: -5px; + margin-left: -5px; + margin-right: -5px; } -.formkit-form[min-width~="700"] .formkit-fields[data-stacked="false"] .formkit-field, -.formkit-form[min-width~="800"] .formkit-fields[data-stacked="false"] .formkit-field, -.formkit-form[min-width~="700"] .formkit-fields[data-stacked="false"] .formkit-submit, -.formkit-form[min-width~="800"] .formkit-fields[data-stacked="false"] .formkit-submit { - margin: 0 5px 15px 5px; +.formkit-form[min-width~="700"] + .formkit-fields[data-stacked="false"] + .formkit-field, +.formkit-form[min-width~="800"] + .formkit-fields[data-stacked="false"] + .formkit-field, +.formkit-form[min-width~="700"] + .formkit-fields[data-stacked="false"] + .formkit-submit, +.formkit-form[min-width~="800"] + .formkit-fields[data-stacked="false"] + .formkit-submit { + margin: 0 5px 15px 5px; } -.formkit-form[min-width~="700"] .formkit-fields[data-stacked="false"] .formkit-field, -.formkit-form[min-width~="800"] .formkit-fields[data-stacked="false"] .formkit-field { - -webkit-flex: 100 1 auto; - -ms-flex: 100 1 auto; - flex: 100 1 auto; +.formkit-form[min-width~="700"] + .formkit-fields[data-stacked="false"] + .formkit-field, +.formkit-form[min-width~="800"] + .formkit-fields[data-stacked="false"] + .formkit-field { + -webkit-flex: 100 1 auto; + -ms-flex: 100 1 auto; + flex: 100 1 auto; } -.formkit-form[min-width~="700"] .formkit-fields[data-stacked="false"] .formkit-submit, -.formkit-form[min-width~="800"] .formkit-fields[data-stacked="false"] .formkit-submit { - -webkit-flex: 1 1 auto; - -ms-flex: 1 1 auto; - flex: 1 1 auto; +.formkit-form[min-width~="700"] + .formkit-fields[data-stacked="false"] + .formkit-submit, +.formkit-form[min-width~="800"] + .formkit-fields[data-stacked="false"] + .formkit-submit { + -webkit-flex: 1 1 auto; + -ms-flex: 1 1 auto; + flex: 1 1 auto; } diff --git a/src/global.scss b/src/global.scss index 68dee967..7271130a 100644 --- a/src/global.scss +++ b/src/global.scss @@ -7,421 +7,421 @@ @import "./convertkit"; :root { - --animSpeed: 200ms; - --animStyle: ease-in-out; - --cardOutlineStyle: 1px solid var(--primary); - --cardRadius: #{$baseUnit}px; - --filterBarIconSize: #{3 * $baseUnit}px; - --listViewPadding: #{1.5 * $baseUnit}px; - font-size: $rootFontSize; - line-height: 1.2; - scrollbar-color: var(--darkPrimary) var(--backgroundColor); - transition: scrollbar-color var(--animStyle) var(--animSpeed); + --animSpeed: 200ms; + --animStyle: ease-in-out; + --cardOutlineStyle: 1px solid var(--primary); + --cardRadius: #{$baseUnit}px; + --filterBarIconSize: #{3 * $baseUnit}px; + --listViewPadding: #{1.5 * $baseUnit}px; + font-size: $rootFontSize; + line-height: 1.2; + scrollbar-color: var(--darkPrimary) var(--backgroundColor); + transition: scrollbar-color var(--animStyle) var(--animSpeed); } @include from($startMediumScreenSize) { - :root { - --listViewPadding: #{$baseUnit * 2.5}px; - } + :root { + --listViewPadding: #{$baseUnit * 2.5}px; + } } :focus { - outline-color: var(--darkPrimary); + outline-color: var(--darkPrimary); } //without this all
diff --git a/src/page-components/blog-post/post-title-header/post-title-header.astro b/src/page-components/blog-post/post-title-header/post-title-header.astro index 7b48abca..5dd0e254 100644 --- a/src/page-components/blog-post/post-title-header/post-title-header.astro +++ b/src/page-components/blog-post/post-title-header/post-title-header.astro @@ -3,19 +3,15 @@ import styles from "./post-title-header.module.scss"; import { PostInfo } from "types/index"; interface PostTitleHeaderProps { - post: PostInfo; + post: PostInfo; } -const {post} = Astro.props as PostTitleHeaderProps; +const { post } = Astro.props as PostTitleHeaderProps; const { title, tags } = post; ---
-

{title}

-
    - {tags.map((tag) => ( -
  • - {tag} -
  • - ))} -
-
\ No newline at end of file +

{title}

+
    + {tags.map((tag) =>
  • {tag}
  • )} +
+
diff --git a/src/page-components/blog-post/suggested-articles/suggested-articles.astro b/src/page-components/blog-post/suggested-articles/suggested-articles.astro index 4cddf929..69c2723a 100644 --- a/src/page-components/blog-post/suggested-articles/suggested-articles.astro +++ b/src/page-components/blog-post/suggested-articles/suggested-articles.astro @@ -3,44 +3,43 @@ import suggestedStyle from "./suggested-articles.module.scss"; import { Languages, PostInfo } from "types/index"; interface TableOfContentsProps { - suggestedArticles: PostInfo[]; - lang?: Languages; + suggestedArticles: PostInfo[]; + lang?: Languages; } -const { - suggestedArticles, - lang, -} = Astro.props as TableOfContentsProps; +const { suggestedArticles, lang } = Astro.props as TableOfContentsProps; --- -{!suggestedArticles.length ? null : } \ No newline at end of file +{ + !suggestedArticles.length ? null : ( + + ) +} diff --git a/src/page-components/blog-post/suggested-articles/suggested-articles.module.scss b/src/page-components/blog-post/suggested-articles/suggested-articles.module.scss index 24d6007e..f760142c 100644 --- a/src/page-components/blog-post/suggested-articles/suggested-articles.module.scss +++ b/src/page-components/blog-post/suggested-articles/suggested-articles.module.scss @@ -1,50 +1,50 @@ -@import "../../../styles/vars"; -@import "../../../styles/text_styles"; -@import "../../../components/post-card/post-card.module"; - -.list { - list-style: none; - margin: 0; - padding: 0; -} - -.localCard { - padding: 1rem !important; - margin-bottom: 1rem; - text-decoration: none; -} - -.localCard a { - text-decoration: none; -} - -.aTag { - display: block; -} - -.localCard:hover .titleTag { - text-decoration: underline; - transition: text-decoration var(--animSpeed); -} - -.header { - @extend %headline-4; - margin-bottom: 1rem; -} - -.author { - color: var(--midImpactBlack) !important; - text-underline-style: none; -} - -.srOnly { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border-width: 0; -} +@import "../../../styles/vars"; +@import "../../../styles/text_styles"; +@import "../../../components/post-card/post-card.module"; + +.list { + list-style: none; + margin: 0; + padding: 0; +} + +.localCard { + padding: 1rem !important; + margin-bottom: 1rem; + text-decoration: none; +} + +.localCard a { + text-decoration: none; +} + +.aTag { + display: block; +} + +.localCard:hover .titleTag { + text-decoration: underline; + transition: text-decoration var(--animSpeed); +} + +.header { + @extend %headline-4; + margin-bottom: 1rem; +} + +.author { + color: var(--midImpactBlack) !important; + text-underline-style: none; +} + +.srOnly { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} diff --git a/src/page-components/blog-post/tabs-script/tabs-script.astro b/src/page-components/blog-post/tabs-script/tabs-script.astro index e94e3ddf..91eec3dd 100644 --- a/src/page-components/blog-post/tabs-script/tabs-script.astro +++ b/src/page-components/blog-post/tabs-script/tabs-script.astro @@ -1,4 +1,4 @@ ---- ---- - - diff --git a/src/page-components/layouts/blocking-theme-changer-script.astro b/src/page-components/layouts/blocking-theme-changer-script.astro index 1d2cc6be..022d71a6 100644 --- a/src/page-components/layouts/blocking-theme-changer-script.astro +++ b/src/page-components/layouts/blocking-theme-changer-script.astro @@ -1,56 +1,56 @@ ---- -import * as Terser from "terser"; - -import { - COLOR_MODE_STORAGE_KEY, -} from "../../constants"; - -/** - * Much of this code deals with dark mode. It's ripped straight from: - * @see https://joshwcomeau.com/gatsby/dark-mode/ - * - * Huge thanks to Josh for outlining how to do this - */ -/** - * DARK MODE CODE - * - * Prevents the "flash" of light mode - */ -/** - * Trust me, I know that it looks like we're reading entries from an emoji - * but what's really happening is that this function is being converted to a - * string, then mutated by "MagicScriptTag" in order to add in dynamic code - * into that string. This way, we're able to avoid duplicating - */ -function setColorsByTheme() { - const STORAGE_KEY = "COLOR_MODE_STORAGE_KEY"; - - const mql = window.matchMedia("(prefers-color-scheme: dark)"); - const prefersDarkFromMQ = mql.matches; - const prefersDarkFromLocalStorage = localStorage.getItem(STORAGE_KEY); - - let colorMode = "light"; - - const hasUsedToggle = typeof prefersDarkFromLocalStorage === "string"; - - if (hasUsedToggle) { - colorMode = prefersDarkFromLocalStorage; - } else { - colorMode = prefersDarkFromMQ ? "dark" : "light"; - } - - let root = document.documentElement; - - // TODO: migrate to `classList` - root.className = colorMode; -} - -const boundFn = String(setColorsByTheme) - .replace("COLOR_MODE_STORAGE_KEY", COLOR_MODE_STORAGE_KEY); - -let calledFunction = `(${boundFn})()`; - -calledFunction = (await Terser.minify(calledFunction)).code!; ---- - - diff --git a/src/page-components/layouts/theme-style.astro b/src/page-components/layouts/theme-style.astro index 7d6acf32..fb5e1b53 100644 --- a/src/page-components/layouts/theme-style.astro +++ b/src/page-components/layouts/theme-style.astro @@ -1,25 +1,25 @@ ---- -import { - COLORS -} from "../../constants"; - -function getThemeStyling(theme: 'light' | 'dark') { - const CSS_THEME = Object.entries(COLORS).reduce((prev, [key, val]) => { - prev += `\n--${key}: ${val[theme]};`; - return prev; - }, ""); - - return CSS_THEME; -} - -const rawStylesCSS = ` - html.light, body.light { - ${getThemeStyling('light')} - } - html.dark, body.dark { - ${getThemeStyling('dark')} - } -` ---- - - diff --git a/src/page-components/post-list/post-list-header/post-list-header.astro b/src/page-components/post-list/post-list-header/post-list-header.astro index 432df83c..01344eff 100644 --- a/src/page-components/post-list/post-list-header/post-list-header.astro +++ b/src/page-components/post-list/post-list-header/post-list-header.astro @@ -1,26 +1,38 @@ --- import styles from "./post-list-header.module.scss"; -import {Image} from '@astrojs/image/components'; +import { Image } from "@astrojs/image/components"; import unicornLogo from "../../../assets/unicorn_utterances_logo_512.png"; interface PostListHeaderProps { - siteDescription: string; + siteDescription: string; } const { siteDescription } = Astro.props as PostListHeaderProps; --- - \ No newline at end of file + diff --git a/src/page-components/post-list/post-list.astro b/src/page-components/post-list/post-list.astro index 155131ca..52f064e4 100644 --- a/src/page-components/post-list/post-list.astro +++ b/src/page-components/post-list/post-list.astro @@ -12,31 +12,30 @@ import { Page } from "astro"; import Pagination from "components/pagination/pagination.astro"; export interface PostListTemplateProps { - posts: PostInfo[]; - rootURL: string; - page: Pick, 'total' | 'currentPage' | 'size' | 'lastPage' | 'url'> + posts: PostInfo[]; + rootURL: string; + page: Pick< + Page, + "total" | "currentPage" | "size" | "lastPage" | "url" + >; } -const { - posts, - page, - rootURL -} = Astro.props as PostListTemplateProps; +const { posts, page, rootURL } = Astro.props as PostListTemplateProps; ---
- - -
- - -
- - - + +
+ + +
+ + +
diff --git a/src/page-components/unicorns/profile-header/profile-header.astro b/src/page-components/unicorns/profile-header/profile-header.astro index d9e6deba..c50a7765 100644 --- a/src/page-components/unicorns/profile-header/profile-header.astro +++ b/src/page-components/unicorns/profile-header/profile-header.astro @@ -1,117 +1,115 @@ ---- -import styles from "./profile-header.module.scss"; -import { UnicornInfo } from "uu-types"; -import {Image} from '@astrojs/image/components'; -import { Icon } from 'astro-icon'; - -import SocialBtn from "./social-button.astro"; - -const getNamePossessive = (name: string) => { - if (name.endsWith("s")) return `${name}'`; - return `${name}'s`; -}; - -interface PicTitleHeaderProps { - unicornData: UnicornInfo; -} -const { unicornData } = Astro.props as PicTitleHeaderProps; - -const possessiveName = getNamePossessive(unicornData.name); - ---- - - \ No newline at end of file +--- +import styles from "./profile-header.module.scss"; +import { UnicornInfo } from "uu-types"; +import { Image } from "@astrojs/image/components"; +import { Icon } from "astro-icon"; + +import SocialBtn from "./social-button.astro"; + +const getNamePossessive = (name: string) => { + if (name.endsWith("s")) return `${name}'`; + return `${name}'s`; +}; + +interface PicTitleHeaderProps { + unicornData: UnicornInfo; +} +const { unicornData } = Astro.props as PicTitleHeaderProps; + +const possessiveName = getNamePossessive(unicornData.name); +--- + + diff --git a/src/page-components/unicorns/profile-header/profile-header.module.scss b/src/page-components/unicorns/profile-header/profile-header.module.scss index 13c27ccf..5710effe 100644 --- a/src/page-components/unicorns/profile-header/profile-header.module.scss +++ b/src/page-components/unicorns/profile-header/profile-header.module.scss @@ -1,100 +1,100 @@ -@import "../../../styles/vars"; -@import "../../../styles/utils"; -@import "../../../styles/text_styles"; - -.container { - margin: 50px auto 58px auto; - max-width: 1032px; - display: flex; - position: relative; - align-items: center; - flex-wrap: wrap; - justify-content: center; - - @include from($endSmallScreenSize) { - margin-bottom: 24px; - flex-wrap: nowrap; - justify-content: flex-start; - } -} - -.headerPic { - $mobileImgSize: 120px; - max-width: $mobileImgSize; - max-height: $mobileImgSize; - margin-right: 0; - flex-shrink: 0; - - & > img { - height: 100%; - width: 100%; - } - - @include from($endSmallScreenSize) { - $desktopImgSize: 192px; - max-width: $desktopImgSize; - max-height: $desktopImgSize; - margin-right: 48px; - } -} - -.title { - transition: color var(--animStyle) var(--animSpeed); - color: var(--highImpactBlack); - margin: 0; - @include until($endSmallScreenSize) { - text-align: center; - } -} - -.mobileTitle { - @extend %headline-1; - margin-top: 16px; - - @include from($endSmallScreenSize) { - display: none; - } -} - -.desktopTitle { - @extend %headline-2; - - @include until($endSmallScreenSize) { - display: none; - } -} - -.noMgContainer { - flex-grow: 1; -} - -.subheader { - @extend %subheader-3; - margin: 0; - transition: color var(--animStyle) var(--animSpeed); - color: var(--midImpactBlack); - white-space: pre-line; - - @include until($endSmallScreenSize) { - margin: 16px 16px 0; - } -} - -.socialsContainer { - display: flex; - flex-direction: row; - transition: color var(--animStyle) var(--animSpeed); - color: var(--darkPrimary); - flex-wrap: wrap; - list-style: none; - padding: 0; - margin: 0 auto; - justify-content: center; - margin-top: 16px; - - @include from($endSmallScreenSize) { - padding: 6px 0; - margin: 0; - justify-content: flex-start; - } -} +@import "../../../styles/vars"; +@import "../../../styles/utils"; +@import "../../../styles/text_styles"; + +.container { + margin: 50px auto 58px auto; + max-width: 1032px; + display: flex; + position: relative; + align-items: center; + flex-wrap: wrap; + justify-content: center; + + @include from($endSmallScreenSize) { + margin-bottom: 24px; + flex-wrap: nowrap; + justify-content: flex-start; + } +} + +.headerPic { + $mobileImgSize: 120px; + max-width: $mobileImgSize; + max-height: $mobileImgSize; + margin-right: 0; + flex-shrink: 0; + + & > img { + height: 100%; + width: 100%; + } + + @include from($endSmallScreenSize) { + $desktopImgSize: 192px; + max-width: $desktopImgSize; + max-height: $desktopImgSize; + margin-right: 48px; + } +} + +.title { + transition: color var(--animStyle) var(--animSpeed); + color: var(--highImpactBlack); + margin: 0; + @include until($endSmallScreenSize) { + text-align: center; + } +} + +.mobileTitle { + @extend %headline-1; + margin-top: 16px; + + @include from($endSmallScreenSize) { + display: none; + } +} + +.desktopTitle { + @extend %headline-2; + + @include until($endSmallScreenSize) { + display: none; + } +} + +.noMgContainer { + flex-grow: 1; +} + +.subheader { + @extend %subheader-3; + margin: 0; + transition: color var(--animStyle) var(--animSpeed); + color: var(--midImpactBlack); + white-space: pre-line; + + @include until($endSmallScreenSize) { + margin: 16px 16px 0; + } +} + +.socialsContainer { + display: flex; + flex-direction: row; + transition: color var(--animStyle) var(--animSpeed); + color: var(--darkPrimary); + flex-wrap: wrap; + list-style: none; + padding: 0; + margin: 0 auto; + justify-content: center; + margin-top: 16px; + + @include from($endSmallScreenSize) { + padding: 6px 0; + margin: 0; + justify-content: flex-start; + } +} diff --git a/src/page-components/unicorns/profile-header/social-button.astro b/src/page-components/unicorns/profile-header/social-button.astro index 32610eb9..781e6a4b 100644 --- a/src/page-components/unicorns/profile-header/social-button.astro +++ b/src/page-components/unicorns/profile-header/social-button.astro @@ -1,29 +1,24 @@ ---- -interface SocialBtnProps { - text: string; - url: string; -} -const { text, url } = Astro.props as SocialBtnProps; -import styles from './social-button.module.scss'; ---- - -
  • - - - - - - {text} - -
  • \ No newline at end of file +--- +interface SocialBtnProps { + text: string; + url: string; +} +const { text, url } = Astro.props as SocialBtnProps; +import styles from "./social-button.module.scss"; +--- + +
  • + + + + + + {text} + +
  • diff --git a/src/page-components/unicorns/profile-header/social-button.module.scss b/src/page-components/unicorns/profile-header/social-button.module.scss index b74bf5a9..ee1864b9 100644 --- a/src/page-components/unicorns/profile-header/social-button.module.scss +++ b/src/page-components/unicorns/profile-header/social-button.module.scss @@ -1,60 +1,59 @@ -@import "../../../styles/vars"; -@import "../../../styles/utils"; -@import "../../../styles/text_styles"; - -.svgContainer { - display: flex; - justify-content: center; - align-items: center; -} - - -.socialBtnLink { - &:not(:last-of-type) { - margin-right: 32px; - - @include from($endSmallScreenSize) { - margin-right: 24px; - } - } - - .socialText { - margin-left: 0.5rem; - @extend %subheader-3; - - // Make it so that the next and prev label text is hidden on mobile - // but not removed from the aria-reading role - @include until($endSmallScreenSize) { - width: 1px; - height: 1px; - overflow: hidden; - opacity: 0; - display: inline-block; - } - } - - & > a { - display: flex; - flex-wrap: nowrap; - align-items: center; - - $mobileSvgSize: 32px; - - @include until($endSmallScreenSize) { - height: $mobileSvgSize; - width: $mobileSvgSize; - } - - svg { - $desktopSvgSize: 36px; - height: $desktopSvgSize; - width: $desktopSvgSize; - fill: none; - - @include until($endSmallScreenSize) { - height: $mobileSvgSize; - width: $mobileSvgSize; - } - } - } -} +@import "../../../styles/vars"; +@import "../../../styles/utils"; +@import "../../../styles/text_styles"; + +.svgContainer { + display: flex; + justify-content: center; + align-items: center; +} + +.socialBtnLink { + &:not(:last-of-type) { + margin-right: 32px; + + @include from($endSmallScreenSize) { + margin-right: 24px; + } + } + + .socialText { + margin-left: 0.5rem; + @extend %subheader-3; + + // Make it so that the next and prev label text is hidden on mobile + // but not removed from the aria-reading role + @include until($endSmallScreenSize) { + width: 1px; + height: 1px; + overflow: hidden; + opacity: 0; + display: inline-block; + } + } + + & > a { + display: flex; + flex-wrap: nowrap; + align-items: center; + + $mobileSvgSize: 32px; + + @include until($endSmallScreenSize) { + height: $mobileSvgSize; + width: $mobileSvgSize; + } + + svg { + $desktopSvgSize: 36px; + height: $desktopSvgSize; + width: $desktopSvgSize; + fill: none; + + @include until($endSmallScreenSize) { + height: $mobileSvgSize; + width: $mobileSvgSize; + } + } + } +} diff --git a/src/page-components/unicorns/unicorn-page.astro b/src/page-components/unicorns/unicorn-page.astro index abbe4260..bb0b641d 100644 --- a/src/page-components/unicorns/unicorn-page.astro +++ b/src/page-components/unicorns/unicorn-page.astro @@ -1,45 +1,42 @@ ---- -import PostList from "components/post-card-list/post-card-list.astro"; -import Pagination from "components/pagination/pagination.astro"; -import { Page } from "astro"; -import { PostInfo } from "types/PostInfo"; -import ProfileHeader from './profile-header/profile-header.astro'; - -export interface UnicornTemplateProps { - unicorn: any; - posts: PostInfo[]; - rootURL: string; - page: Pick, 'total' | 'currentPage' | 'size' | 'lastPage' | 'url'> -} - -const { - unicorn, - page, - rootURL, - posts -} = Astro.props as UnicornTemplateProps; ---- - - - - -
    - - -
    - - \ No newline at end of file +--- +import PostList from "components/post-card-list/post-card-list.astro"; +import Pagination from "components/pagination/pagination.astro"; +import { Page } from "astro"; +import { PostInfo } from "types/PostInfo"; +import ProfileHeader from "./profile-header/profile-header.astro"; + +export interface UnicornTemplateProps { + unicorn: any; + posts: PostInfo[]; + rootURL: string; + page: Pick< + Page, + "total" | "currentPage" | "size" | "lastPage" | "url" + >; +} + +const { unicorn, page, rootURL, posts } = Astro.props as UnicornTemplateProps; +--- + + + +
    + + +
    + + diff --git a/src/pages/index.astro b/src/pages/index.astro index 540c5164..e47b8fbe 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -1,13 +1,15 @@ --- -import Document from '../layouts/document.astro'; -import PostListTemplate, { PostListTemplateProps } from '../page-components/post-list/post-list.astro'; -import { getAllPostsForListView } from 'utils/api'; -import {PostInfo} from 'types/PostInfo'; +import Document from "../layouts/document.astro"; +import PostListTemplate, { + PostListTemplateProps, +} from "../page-components/post-list/post-list.astro"; +import { getAllPostsForListView } from "utils/api"; +import { PostInfo } from "types/PostInfo"; import SEO from "components/seo/seo.astro"; -const posts = await Astro.glob('../../content/blog/**/*.md') +const posts = await Astro.glob("../../content/blog/**/*.md"); -const enPosts = getAllPostsForListView(posts, 'en'); +const enPosts = getAllPostsForListView(posts, "en"); const postsToDisplay = enPosts.slice(0, 8); const page = { @@ -17,12 +19,12 @@ const page = { lastPage: Math.floor(enPosts.length / postsToDisplay.length), url: { current: Astro.url.href, - next: '/page/2' - } -} as PostListTemplateProps['page']; + next: "/page/2", + }, +} as PostListTemplateProps["page"]; --- - - \ No newline at end of file + + diff --git a/src/pages/page/[page].astro b/src/pages/page/[page].astro index e868cc7b..1759339a 100644 --- a/src/pages/page/[page].astro +++ b/src/pages/page/[page].astro @@ -1,27 +1,27 @@ ---- -import Document from '../../layouts/document.astro'; -import PostListTemplate from '../../page-components/post-list/post-list.astro'; -import { getAllPostsForListView } from 'utils/api'; -import {PostInfo} from 'types/PostInfo'; -import SEO from "components/seo/seo.astro"; -import { Page } from 'astro'; - -export async function getStaticPaths({ paginate }) { - const posts = await Astro.glob('../../../content/blog/**/*.md') - - const postsToDisplay = getAllPostsForListView(posts, 'en'); - - return paginate(postsToDisplay, { pageSize: 8 }); -} - -const { page } = Astro.props as {page: Page}; - -const pageIndex = page.currentPage; - -const SEOTitle = `Post page ${pageIndex}`; ---- - - - - - \ No newline at end of file +--- +import Document from "../../layouts/document.astro"; +import PostListTemplate from "../../page-components/post-list/post-list.astro"; +import { getAllPostsForListView } from "utils/api"; +import { PostInfo } from "types/PostInfo"; +import SEO from "components/seo/seo.astro"; +import { Page } from "astro"; + +export async function getStaticPaths({ paginate }) { + const posts = await Astro.glob("../../../content/blog/**/*.md"); + + const postsToDisplay = getAllPostsForListView(posts, "en"); + + return paginate(postsToDisplay, { pageSize: 8 }); +} + +const { page } = Astro.props as { page: Page }; + +const pageIndex = page.currentPage; + +const SEOTitle = `Post page ${pageIndex}`; +--- + + + + + diff --git a/src/pages/posts/[postid].astro b/src/pages/posts/[postid].astro index e18a8c5e..b00591c3 100644 --- a/src/pages/posts/[postid].astro +++ b/src/pages/posts/[postid].astro @@ -1,83 +1,84 @@ --- -import Document from '../../layouts/document.astro'; +import Document from "../../layouts/document.astro"; import SEO from "components/seo/seo.astro"; -import BlogPostLayout from 'components/blog-post-layout/blog-post-layout.astro'; -import PostTitleHeader from 'src/page-components/blog-post/post-title-header/post-title-header.astro'; -import PostMetadata from 'src/page-components/blog-post/post-metadata/post-metadata.astro'; -import TabsScript from 'src/page-components/blog-post/tabs-script/tabs-script.astro'; -import SuggestedArticles from 'src/page-components/blog-post/suggested-articles/suggested-articles.astro'; -import TableOfContents from 'components/table-of-contents/table-of-contents.astro'; +import BlogPostLayout from "components/blog-post-layout/blog-post-layout.astro"; +import PostTitleHeader from "src/page-components/blog-post/post-title-header/post-title-header.astro"; +import PostMetadata from "src/page-components/blog-post/post-metadata/post-metadata.astro"; +import TabsScript from "src/page-components/blog-post/tabs-script/tabs-script.astro"; +import SuggestedArticles from "src/page-components/blog-post/suggested-articles/suggested-articles.astro"; +import TableOfContents from "components/table-of-contents/table-of-contents.astro"; -import type { MarkdownInstance } from 'astro'; -import {PostInfo} from 'types/PostInfo'; -import { Languages } from 'types/index'; +import type { MarkdownInstance } from "astro"; +import { PostInfo } from "types/PostInfo"; +import { Languages } from "types/index"; export async function getStaticPaths() { - const posts = await Astro.glob('../../../content/blog/**/*.md') + const posts = await Astro.glob("../../../content/blog/**/*.md"); - return posts.map(post => { - return { - params: { - // TODO: Pass locale - postid: post.frontmatter.slug - }, - props: { - Content: post.Content, - post: post.frontmatter - } - } - }) + return posts.map((post) => { + return { + params: { + // TODO: Pass locale + postid: post.frontmatter.slug, + }, + props: { + Content: post.Content, + post: post.frontmatter, + }, + }; + }); } const { Content, post } = Astro.props as { - post: PostInfo, - Content: MarkdownInstance['Content'] -} + post: PostInfo; + Content: MarkdownInstance["Content"]; +}; const translations = post?.translations || []; const otherLangs = translations - ? (Object.keys(translations).filter( - (t) => t !== post.locale - ) as Languages[]) - : []; + ? (Object.keys(translations).filter((t) => t !== post.locale) as Languages[]) + : []; --- - - - - -
    - -
    - -
    -
    - -
    - -
    - + + +
    + +
    + +
    +
    + +
    + +
    + - - -
    -
    -
    - \ No newline at end of file +
    +
    +
    +
    diff --git a/src/pages/unicorns/[unicornid]/index.astro b/src/pages/unicorns/[unicornid]/index.astro index 22bc57d7..4dccddfb 100644 --- a/src/pages/unicorns/[unicornid]/index.astro +++ b/src/pages/unicorns/[unicornid]/index.astro @@ -1,45 +1,50 @@ ---- -import Document from '../../../layouts/document.astro'; -import SEO from "components/seo/seo.astro"; -import UnicornsPage from '../../../page-components/unicorns/unicorn-page.astro'; -import { getAllPostsForUnicornListView } from 'utils/api'; -import {PostInfo} from 'types/PostInfo'; -import { unicorns } from "utils/data"; -import { Page } from 'astro'; - -export async function getStaticPaths() { - return unicorns.map(unicorn => ({ params: {unicornid: unicorn.id}})) -} - -const params = Astro.params as {unicornid: string}; - -const unicorn = unicorns.find(unicorn => unicorn.id === params.unicornid); - -const posts = await Astro.glob('../../../../content/blog/**/*.md') -const enPosts = getAllPostsForUnicornListView(unicorn.id, posts, 'en'); -const postsToDisplay = enPosts.slice(0, 8); - -const page = { - total: enPosts.length, - currentPage: 1, - size: postsToDisplay.length, - lastPage: Math.floor(enPosts.length / postsToDisplay.length), - url: { - current: `/unicorns/${unicorn.id}`, - next: `/unicorns/${unicorn.id}/page/2` - } -} as Page; - -const rootURL = `/unicorns/${unicorn.id}/`; ---- - - - - - +--- +import Document from "../../../layouts/document.astro"; +import SEO from "components/seo/seo.astro"; +import UnicornsPage from "../../../page-components/unicorns/unicorn-page.astro"; +import { getAllPostsForUnicornListView } from "utils/api"; +import { PostInfo } from "types/PostInfo"; +import { unicorns } from "utils/data"; +import { Page } from "astro"; + +export async function getStaticPaths() { + return unicorns.map((unicorn) => ({ params: { unicornid: unicorn.id } })); +} + +const params = Astro.params as { unicornid: string }; + +const unicorn = unicorns.find((unicorn) => unicorn.id === params.unicornid); + +const posts = await Astro.glob("../../../../content/blog/**/*.md"); +const enPosts = getAllPostsForUnicornListView(unicorn.id, posts, "en"); +const postsToDisplay = enPosts.slice(0, 8); + +const page = { + total: enPosts.length, + currentPage: 1, + size: postsToDisplay.length, + lastPage: Math.floor(enPosts.length / postsToDisplay.length), + url: { + current: `/unicorns/${unicorn.id}`, + next: `/unicorns/${unicorn.id}/page/2`, + }, +} as Page; + +const rootURL = `/unicorns/${unicorn.id}/`; +--- + + + + + diff --git a/src/pages/unicorns/[unicornid]/page/[page].astro b/src/pages/unicorns/[unicornid]/page/[page].astro index 15ba769e..ece6a164 100644 --- a/src/pages/unicorns/[unicornid]/page/[page].astro +++ b/src/pages/unicorns/[unicornid]/page/[page].astro @@ -1,34 +1,48 @@ ---- -import Document from '../../../../layouts/document.astro'; -import SEO from "components/seo/seo.astro"; -import UnicornsPage from '../../../../page-components/unicorns/unicorn-page.astro'; -import { getAllPostsForUnicornListView } from 'utils/api'; -import {PostInfo} from 'types/PostInfo'; -import { unicorns } from "utils/data"; -import { Page } from 'astro'; - -export async function getStaticPaths({ paginate }) { - const posts = await Astro.glob('../../../../../content/blog/**/*.md') - return unicorns.map(unicorn => { - const postsToDisplay = getAllPostsForUnicornListView(unicorn.id, posts, 'en'); - return paginate(postsToDisplay, { params: {unicornid: unicorn.id}, pageSize: 8 }); - }) -} - -const { page } = Astro.props as {page: Page}; -const params = Astro.params as {unicornid: string}; - -const unicorn = unicorns.find(unicorn => unicorn.id === params.unicornid); -const rootURL = `/unicorns/${unicorn.id}/`; ---- - - - - - +--- +import Document from "../../../../layouts/document.astro"; +import SEO from "components/seo/seo.astro"; +import UnicornsPage from "../../../../page-components/unicorns/unicorn-page.astro"; +import { getAllPostsForUnicornListView } from "utils/api"; +import { PostInfo } from "types/PostInfo"; +import { unicorns } from "utils/data"; +import { Page } from "astro"; + +export async function getStaticPaths({ paginate }) { + const posts = await Astro.glob( + "../../../../../content/blog/**/*.md" + ); + return unicorns.map((unicorn) => { + const postsToDisplay = getAllPostsForUnicornListView( + unicorn.id, + posts, + "en" + ); + return paginate(postsToDisplay, { + params: { unicornid: unicorn.id }, + pageSize: 8, + }); + }); +} + +const { page } = Astro.props as { page: Page }; +const params = Astro.params as { unicornid: string }; + +const unicorn = unicorns.find((unicorn) => unicorn.id === params.unicornid); +const rootURL = `/unicorns/${unicorn.id}/`; +--- + + + + + diff --git a/src/shiki.scss b/src/shiki.scss index ee2dd15b..2591f887 100644 --- a/src/shiki.scss +++ b/src/shiki.scss @@ -15,7 +15,7 @@ code .line::before { margin-right: 1.5rem; display: inline-block; text-align: right; - color: rgba(115,138,148,.4) + color: rgba(115, 138, 148, 0.4); } /* Start of Shiki Twoslash CSS: @@ -77,7 +77,8 @@ pre.shiki:hover .dim { pre.shiki div.dim { opacity: 0.5; } -pre.shiki div.dim, pre.shiki div.highlight { +pre.shiki div.dim, +pre.shiki div.highlight { margin: 0; padding: 0; } @@ -90,7 +91,7 @@ pre.shiki div.line { } /** Don't show the language identifiers */ -pre.shiki .language-id{ +pre.shiki .language-id { display: none; } @@ -163,7 +164,8 @@ pre code a { } pre data-err { /* Extracted from VS Code */ - background: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%206%203'%20enable-background%3D'new%200%200%206%203'%20height%3D'3'%20width%3D'6'%3E%3Cg%20fill%3D'%23c94824'%3E%3Cpolygon%20points%3D'5.5%2C0%202.5%2C3%201.1%2C3%204.1%2C0'%2F%3E%3Cpolygon%20points%3D'4%2C0%206%2C2%206%2C0.6%205.4%2C0'%2F%3E%3Cpolygon%20points%3D'0%2C2%201%2C3%202.4%2C3%200%2C0.6'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E") repeat-x bottom left; + background: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%206%203'%20enable-background%3D'new%200%200%206%203'%20height%3D'3'%20width%3D'6'%3E%3Cg%20fill%3D'%23c94824'%3E%3Cpolygon%20points%3D'5.5%2C0%202.5%2C3%201.1%2C3%204.1%2C0'%2F%3E%3Cpolygon%20points%3D'4%2C0%206%2C2%206%2C0.6%205.4%2C0'%2F%3E%3Cpolygon%20points%3D'0%2C2%201%2C3%202.4%2C3%200%2C0.6'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E") + repeat-x bottom left; padding-bottom: 3px; } pre .query { @@ -178,7 +180,8 @@ pre .query { /* This sections keeps both of those two in in sync */ -pre .error, pre .error-behind { +pre .error, +pre .error-behind { margin-left: -14px; margin-top: 8px; margin-bottom: 4px; @@ -346,7 +349,6 @@ pre .logger.log-log svg { margin-right: 9px; } - blockquote { position: relative; margin-left: 1em; diff --git a/src/styles/_text_styles.scss b/src/styles/_text_styles.scss index 6def4a06..7ea4e302 100644 --- a/src/styles/_text_styles.scss +++ b/src/styles/_text_styles.scss @@ -132,7 +132,6 @@ $robotoMono: "Roboto Mono", monospace; } } - %headline-uniwidth-2 { font-family: $asap; font-weight: 400; diff --git a/src/tabs.scss b/src/tabs.scss index 4e32f923..9c13db84 100644 --- a/src/tabs.scss +++ b/src/tabs.scss @@ -1,59 +1,59 @@ -.tabs { - -webkit-tap-highlight-color: transparent; - - &__tab-list { - padding: 0; - margin: 0 1rem -2px; - } - - &__tab { - display: inline-block; - border: 1px solid transparent; - border-bottom: none; - bottom: -2px; - position: relative; - list-style: none; - padding: 6px 12px; - cursor: pointer; - - background: var(--darkPrimary); - color: var(--backgroundColor); - border-radius: 0.5rem 0.5rem 0 0; - margin-right: 4px; - - &[aria-selected="true"] { - background: var(--backgroundColor); - border: 2px solid var(--darkPrimary); - border-bottom: 0px; - margin-bottom: 2px; - color: var(--darkPrimary); - } - - &[aria-disabled="true"] { - color: GrayText; - cursor: default; - } - - &:focus { - box-shadow: 0 0 5px hsl(208, 99%, 50%); - border-color: hsl(208, 99%, 50%); - outline: none; - - &:after { - content: ""; - position: absolute; - height: 5px; - left: -4px; - right: -4px; - bottom: -5px; - background: var(--backgroundColor); - } - } - } - - &__tab-panel { - border: 2px solid var(--darkPrimary); - border-radius: 0.5rem; - padding: 1.5rem; - } -} +.tabs { + -webkit-tap-highlight-color: transparent; + + &__tab-list { + padding: 0; + margin: 0 1rem -2px; + } + + &__tab { + display: inline-block; + border: 1px solid transparent; + border-bottom: none; + bottom: -2px; + position: relative; + list-style: none; + padding: 6px 12px; + cursor: pointer; + + background: var(--darkPrimary); + color: var(--backgroundColor); + border-radius: 0.5rem 0.5rem 0 0; + margin-right: 4px; + + &[aria-selected="true"] { + background: var(--backgroundColor); + border: 2px solid var(--darkPrimary); + border-bottom: 0px; + margin-bottom: 2px; + color: var(--darkPrimary); + } + + &[aria-disabled="true"] { + color: GrayText; + cursor: default; + } + + &:focus { + box-shadow: 0 0 5px hsl(208, 99%, 50%); + border-color: hsl(208, 99%, 50%); + outline: none; + + &:after { + content: ""; + position: absolute; + height: 5px; + left: -4px; + right: -4px; + bottom: -5px; + background: var(--backgroundColor); + } + } + } + + &__tab-panel { + border: 2px solid var(--darkPrimary); + border-radius: 0.5rem; + padding: 1.5rem; + } +} diff --git a/src/types/CollectionInfo.ts b/src/types/CollectionInfo.ts index 7cd6091c..6b06e1a6 100644 --- a/src/types/CollectionInfo.ts +++ b/src/types/CollectionInfo.ts @@ -2,37 +2,37 @@ import { UnicornInfo } from "./UnicornInfo"; import { PostInfo } from "types/PostInfo"; export interface CollectionInfo { - slug: string; - title: string; - authors: UnicornInfo[]; - description: string; - associatedSeries: string; - published: string; - isbn?: string; - type?: "book"; - coverImg: { - height: number; - width: number; - relativePath: string; - }; - socialImg?: string; - posts: Pick< - PostInfo, - | "description" - | "excerpt" - | "title" - | "order" - | "series" - | "slug" - | "authors" - | "content" - >[]; - content: string; - buttons: Array<{ text: string; url: string }>; - chapterList?: Array<{ - title: string; - description: string; - order: string; - }>; - aboveFoldMarkdown?: string; + slug: string; + title: string; + authors: UnicornInfo[]; + description: string; + associatedSeries: string; + published: string; + isbn?: string; + type?: "book"; + coverImg: { + height: number; + width: number; + relativePath: string; + }; + socialImg?: string; + posts: Pick< + PostInfo, + | "description" + | "excerpt" + | "title" + | "order" + | "series" + | "slug" + | "authors" + | "content" + >[]; + content: string; + buttons: Array<{ text: string; url: string }>; + chapterList?: Array<{ + title: string; + description: string; + order: string; + }>; + aboveFoldMarkdown?: string; } diff --git a/src/types/LicenseInfo.ts b/src/types/LicenseInfo.ts index fd3e39ab..42cd1118 100644 --- a/src/types/LicenseInfo.ts +++ b/src/types/LicenseInfo.ts @@ -1,8 +1,8 @@ export interface LicenseInfo { - id: string; - licenceType: string; - footerImg: string; - explainLink: string; - name: string; - displayName: string; + id: string; + licenceType: string; + footerImg: string; + explainLink: string; + name: string; + displayName: string; } diff --git a/src/types/PostInfo.ts b/src/types/PostInfo.ts index 331a3fa9..d35a804d 100644 --- a/src/types/PostInfo.ts +++ b/src/types/PostInfo.ts @@ -4,35 +4,35 @@ import { Languages } from "types/index"; import { MarkdownInstance } from "astro"; export interface RawPostInfo { - title: string; - published: string; - authors: string[]; - tags: string[]; - attached: string[]; - license: string; - description?: string; - edited?: string; - series?: string; - order?: number; - originalLink?: string; + title: string; + published: string; + authors: string[]; + tags: string[]; + attached: string[]; + license: string; + description?: string; + edited?: string; + series?: string; + order?: number; + originalLink?: string; } export interface PostInfo extends RawPostInfo { - slug: string; - locale: Languages; - Content: MarkdownInstance['Content']; - authorsMeta: UnicornInfo[]; - licenseMeta: LicenseInfo; - excerpt: string; - wordCount: number; - collectionSlug?: string | null; - translations: Partial>; - suggestedArticles: [PostInfo, PostInfo, PostInfo]; - headingsWithId?: Array<{ - // Title value - value: string; - // ID - slug: string; - depth: number; - }>; -} \ No newline at end of file + slug: string; + locale: Languages; + Content: MarkdownInstance["Content"]; + authorsMeta: UnicornInfo[]; + licenseMeta: LicenseInfo; + excerpt: string; + wordCount: number; + collectionSlug?: string | null; + translations: Partial>; + suggestedArticles: [PostInfo, PostInfo, PostInfo]; + headingsWithId?: Array<{ + // Title value + value: string; + // ID + slug: string; + depth: number; + }>; +} diff --git a/src/types/PronounInfo.ts b/src/types/PronounInfo.ts index 3a749ad6..2fc70f97 100644 --- a/src/types/PronounInfo.ts +++ b/src/types/PronounInfo.ts @@ -1,8 +1,8 @@ export interface PronounInfo { - id: string; - they: string; - them: string; - their: string; - theirs: string; - themselves: string; + id: string; + they: string; + them: string; + their: string; + theirs: string; + themselves: string; } diff --git a/src/types/RolesInfo.ts b/src/types/RolesInfo.ts index 5f7c22f7..1a9ff39c 100644 --- a/src/types/RolesInfo.ts +++ b/src/types/RolesInfo.ts @@ -1,25 +1,25 @@ export type RolesEnum = - | { - id: "developer"; - prettyname: "Developer"; - } - | { - id: "designer"; - prettyname: "Designer"; - } - | { - id: "devops"; - prettyname: "Dev-ops"; - } - | { - id: "author"; - prettyname: "Author"; - } - | { - id: "translator"; - prettyname: "Translator"; - } - | { - id: "community"; - prettyname: "Community Leader"; - }; + | { + id: "developer"; + prettyname: "Developer"; + } + | { + id: "designer"; + prettyname: "Designer"; + } + | { + id: "devops"; + prettyname: "Dev-ops"; + } + | { + id: "author"; + prettyname: "Author"; + } + | { + id: "translator"; + prettyname: "Translator"; + } + | { + id: "community"; + prettyname: "Community Leader"; + }; diff --git a/src/types/UnicornInfo.ts b/src/types/UnicornInfo.ts index abc44a94..b59bc09a 100644 --- a/src/types/UnicornInfo.ts +++ b/src/types/UnicornInfo.ts @@ -2,36 +2,36 @@ import { PronounInfo } from "./PronounInfo"; import { RolesEnum } from "./RolesInfo"; export interface RawUnicornInfo { - id: string; - name: string; - firstName: string; - lastName: string; - description: string; - socials: { - twitter?: string; - github?: string; - website?: string; - linkedIn?: string; - twitch?: string; - dribbble?: string; - }; - pronouns: string; - profileImg: string; - color: string; - roles: Array; + id: string; + name: string; + firstName: string; + lastName: string; + description: string; + socials: { + twitter?: string; + github?: string; + website?: string; + linkedIn?: string; + twitch?: string; + dribbble?: string; + }; + pronouns: string; + profileImg: string; + color: string; + roles: Array; } export interface UnicornInfo extends RawUnicornInfo { - rolesMeta: RolesEnum[]; - pronounsMeta: PronounInfo; - profileImgMeta: { - // Relative to "public/unicorns" - relativePath: string; - // Relative to site root - relativeServerPath: string; - // This is not stored, it's generated at build time - absoluteFSPath: string; - height: number; - width: number; - }; + rolesMeta: RolesEnum[]; + pronounsMeta: PronounInfo; + profileImgMeta: { + // Relative to "public/unicorns" + relativePath: string; + // Relative to site root + relativeServerPath: string; + // This is not stored, it's generated at build time + absoluteFSPath: string; + height: number; + width: number; + }; } diff --git a/src/types/modules/gatsby-remark-embedder.d.ts b/src/types/modules/gatsby-remark-embedder.d.ts index 2690e491..27929bdd 100644 --- a/src/types/modules/gatsby-remark-embedder.d.ts +++ b/src/types/modules/gatsby-remark-embedder.d.ts @@ -1,6 +1,6 @@ declare module "gatsby-remark-embedder/dist/transformers/Twitch.js" { - import { Transformer } from "@remark-embedder/core"; + import { Transformer } from "@remark-embedder/core"; - const transformer: Transformer; - export = transformer; + const transformer: Transformer; + export = transformer; } diff --git a/src/types/modules/remark-behead.d.ts b/src/types/modules/remark-behead.d.ts index c763258c..e9578e3c 100644 --- a/src/types/modules/remark-behead.d.ts +++ b/src/types/modules/remark-behead.d.ts @@ -1,14 +1,14 @@ declare module "remark-behead" { - import type { Node } from "unist"; - import type { Root } from "mdast"; - import type { Plugin } from "unified"; + import type { Node } from "unist"; + import type { Root } from "mdast"; + import type { Plugin } from "unified"; - export interface BeheadOptions { - depth: number; - after: number | string | Node; - before: number | string | Node; - between: [number | string | Node, number | string | Node]; - } - declare const plugin: Plugin<[BeheadOptions?] | void[], Root, string>; - export default plugin; + export interface BeheadOptions { + depth: number; + after: number | string | Node; + before: number | string | Node; + between: [number | string | Node, number | string | Node]; + } + declare const plugin: Plugin<[BeheadOptions?] | void[], Root, string>; + export default plugin; } diff --git a/src/types/modules/window.d.ts b/src/types/modules/window.d.ts index 61f2a68a..3ac0292f 100644 --- a/src/types/modules/window.d.ts +++ b/src/types/modules/window.d.ts @@ -1,11 +1,11 @@ import lunr from "lunr"; declare global { - interface Window { - __LUNR__: { - index: lunr.Index; - store: Record; - __loaded: boolean | Promise; - }; - } + interface Window { + __LUNR__: { + index: lunr.Index; + store: Record; + __loaded: boolean | Promise; + }; + } } diff --git a/src/utils/api.ts b/src/utils/api.ts index e3f9ee94..bb6a418a 100644 --- a/src/utils/api.ts +++ b/src/utils/api.ts @@ -2,49 +2,49 @@ import { PostInfo } from "types/PostInfo"; import { Languages } from "types/index"; import { MarkdownInstance } from "astro"; -let allPostsCache = new WeakMap[]>(); +const allPostsCache = new WeakMap[]>(); export function getAllPosts( - posts: MarkdownInstance[], - language: Languages, - cacheString: null | object = null + posts: MarkdownInstance[], + language: Languages, + cacheString: null | object = null ): MarkdownInstance[] { - if (cacheString) { - const cacheData = allPostsCache.get(cacheString); - if (cacheData) return cacheData as any; - } + if (cacheString) { + const cacheData = allPostsCache.get(cacheString); + if (cacheData) return cacheData as any; + } - if (cacheString) allPostsCache.set(cacheString, posts); + if (cacheString) allPostsCache.set(cacheString, posts); - return posts - .filter(post => post.frontmatter.locale === language); + return posts.filter((post) => post.frontmatter.locale === language); } const listViewCache = {}; export const getAllPostsForListView = ( - posts: MarkdownInstance[], - language: Languages, + posts: MarkdownInstance[], + language: Languages ): PostInfo[] => { - let allPosts = getAllPosts(posts, language, listViewCache); + let allPosts = getAllPosts(posts, language, listViewCache); - // sort posts by date in descending order - allPosts = allPosts.sort((post1, post2) => { - const date1 = new Date(post1.frontmatter.published); - const date2 = new Date(post2.frontmatter.published); - return date1 > date2 ? -1 : 1; - }); + // sort posts by date in descending order + allPosts = allPosts.sort((post1, post2) => { + const date1 = new Date(post1.frontmatter.published); + const date2 = new Date(post2.frontmatter.published); + return date1 > date2 ? -1 : 1; + }); - return allPosts.map(post => post.frontmatter).filter(post => post.locale === language); + return allPosts + .map((post) => post.frontmatter) + .filter((post) => post.locale === language); }; export const getAllPostsForUnicornListView = ( - authorId: string, - posts: MarkdownInstance[], - language: Languages, + authorId: string, + posts: MarkdownInstance[], + language: Languages ): PostInfo[] => { - return getAllPostsForListView(posts, language) - .filter(post => - post.authorsMeta.find(postAuthor => postAuthor.id === authorId) - ); + return getAllPostsForListView(posts, language).filter((post) => + post.authorsMeta.find((postAuthor) => postAuthor.id === authorId) + ); }; diff --git a/src/utils/data.ts b/src/utils/data.ts index c578a70b..a29d8a9c 100644 --- a/src/utils/data.ts +++ b/src/utils/data.ts @@ -11,63 +11,61 @@ export const siteDirectory = join(process.cwd(), "content/site"); export const sponsorsDirectory = join(process.cwd(), "public/sponsors"); const unicornsRaw: Array< - Omit & { - roles: string[]; - pronouns: string; - profileImg: string; - } + Omit & { + roles: string[]; + pronouns: string; + profileImg: string; + } > = JSON.parse( - fs.readFileSync(join(dataDirectory, "unicorns.json")).toString() + fs.readFileSync(join(dataDirectory, "unicorns.json")).toString() ); const rolesRaw: RolesEnum[] = JSON.parse( - fs.readFileSync(join(dataDirectory, "roles.json")).toString() + fs.readFileSync(join(dataDirectory, "roles.json")).toString() ); const pronounsRaw: PronounInfo[] = JSON.parse( - fs.readFileSync(join(dataDirectory, "pronouns.json")).toString() + fs.readFileSync(join(dataDirectory, "pronouns.json")).toString() ); const licensesRaw: LicenseInfo[] = JSON.parse( - fs.readFileSync(join(dataDirectory, "licenses.json")).toString() + fs.readFileSync(join(dataDirectory, "licenses.json")).toString() ); const fullUnicorns: UnicornInfo[] = unicornsRaw.map((unicorn) => { - const absoluteFSPath = join(dataDirectory, unicorn.profileImg); - /** - * `getFullRelativePath` strips all prefixing `/`, so we must add one manually - */ - const relativeServerPath = '/' + getFullRelativePath( - "content/data/", - unicorn.profileImg - ); - const profileImgSize = getImageSize(unicorn.profileImg, dataDirectory); + const absoluteFSPath = join(dataDirectory, unicorn.profileImg); + /** + * `getFullRelativePath` strips all prefixing `/`, so we must add one manually + */ + const relativeServerPath = + "/" + getFullRelativePath("content/data/", unicorn.profileImg); + const profileImgSize = getImageSize(unicorn.profileImg, dataDirectory); - // Mutation go BRR - const newUnicorn: UnicornInfo = unicorn as never; + // Mutation go BRR + const newUnicorn: UnicornInfo = unicorn as never; - newUnicorn.profileImgMeta = { - height: profileImgSize.height as number, - width: profileImgSize.width as number, - relativePath: unicorn.profileImg, - relativeServerPath, - absoluteFSPath, - }; + newUnicorn.profileImgMeta = { + height: profileImgSize.height as number, + width: profileImgSize.width as number, + relativePath: unicorn.profileImg, + relativeServerPath, + absoluteFSPath, + }; - newUnicorn.rolesMeta = unicorn.roles.map( - (role) => rolesRaw.find((rRole) => rRole.id === role)! - ); + newUnicorn.rolesMeta = unicorn.roles.map( + (role) => rolesRaw.find((rRole) => rRole.id === role)! + ); - newUnicorn.pronounsMeta = pronounsRaw.find( - (proWithNouns) => proWithNouns.id === unicorn.pronouns - )!; + newUnicorn.pronounsMeta = pronounsRaw.find( + (proWithNouns) => proWithNouns.id === unicorn.pronouns + )!; - return newUnicorn; + return newUnicorn; }); export { - fullUnicorns as unicorns, - rolesRaw as roles, - pronounsRaw as pronouns, - licensesRaw as licenses, + fullUnicorns as unicorns, + rolesRaw as roles, + pronounsRaw as pronouns, + licensesRaw as licenses, }; diff --git a/src/utils/get-all-posts.ts b/src/utils/get-all-posts.ts index 5448fac6..6190d97f 100644 --- a/src/utils/get-all-posts.ts +++ b/src/utils/get-all-posts.ts @@ -1,48 +1,48 @@ -/** - * This should rare-to-never be used inside of an `.astro` file, instead, please use Astro.glob - * - * This file is really only useful when we need to get a list of all posts with metadata associated - * when the Astro runtime isn't available, such as getting suggested articles and other instances. - */ -import { rehypeUnicornPopulatePost } from "./markdown/rehype-unicorn-populate-post"; -import { isNotJunk } from "junk"; -import { postsDirectory } from "./data"; -import { Languages, PostInfo } from "types/index"; -import * as fs from "fs"; -import * as path from "path"; - -const getIndexPath = (lang: Languages) => { - const indexPath = lang !== "en" ? `index.${lang}.md` : `index.md`; - return indexPath; -}; - -export function getPostSlugs(lang: Languages) { - // Avoid errors trying to read from `.DS_Store` files - return fs - .readdirSync(postsDirectory) - .filter(isNotJunk) - .filter((dir) => - fs.existsSync(path.resolve(postsDirectory, dir, getIndexPath(lang))) - ); -} - -export const getAllPosts = (lang: Languages): PostInfo[] => { - const slugs = getPostSlugs(lang); - return slugs.map(slug => { - const file = { - path: path.join(postsDirectory, slug, getIndexPath(lang)), - data: { - astro: { - frontmatter: {}, - }, - }, - }; - - (rehypeUnicornPopulatePost as any)()(undefined, file); - - return { - ...(file.data.astro.frontmatter as any || {}).frontmatterBackup, - ...file.data.astro.frontmatter - }; - }) -} +/** + * This should rare-to-never be used inside of an `.astro` file, instead, please use Astro.glob + * + * This file is really only useful when we need to get a list of all posts with metadata associated + * when the Astro runtime isn't available, such as getting suggested articles and other instances. + */ +import { rehypeUnicornPopulatePost } from "./markdown/rehype-unicorn-populate-post"; +import { isNotJunk } from "junk"; +import { postsDirectory } from "./data"; +import { Languages, PostInfo } from "types/index"; +import * as fs from "fs"; +import * as path from "path"; + +const getIndexPath = (lang: Languages) => { + const indexPath = lang !== "en" ? `index.${lang}.md` : `index.md`; + return indexPath; +}; + +export function getPostSlugs(lang: Languages) { + // Avoid errors trying to read from `.DS_Store` files + return fs + .readdirSync(postsDirectory) + .filter(isNotJunk) + .filter((dir) => + fs.existsSync(path.resolve(postsDirectory, dir, getIndexPath(lang))) + ); +} + +export const getAllPosts = (lang: Languages): PostInfo[] => { + const slugs = getPostSlugs(lang); + return slugs.map((slug) => { + const file = { + path: path.join(postsDirectory, slug, getIndexPath(lang)), + data: { + astro: { + frontmatter: {}, + }, + }, + }; + + (rehypeUnicornPopulatePost as any)()(undefined, file); + + return { + ...((file.data.astro.frontmatter as any) || {}).frontmatterBackup, + ...file.data.astro.frontmatter, + }; + }); +}; diff --git a/src/utils/get-image-size.ts b/src/utils/get-image-size.ts index 2f2d703a..ef630f06 100644 --- a/src/utils/get-image-size.ts +++ b/src/utils/get-image-size.ts @@ -4,14 +4,14 @@ import sizeOf from "image-size"; const absolutePathRegex = /^(?:[a-z]+:)?\/\//; export function getImageSize(src, dir) { - if (absolutePathRegex.exec(src)) { - return; - } - // Treat `/` as a relative path, according to the server - const shouldJoin = !path.isAbsolute(src) || src.startsWith("/"); + if (absolutePathRegex.exec(src)) { + return; + } + // Treat `/` as a relative path, according to the server + const shouldJoin = !path.isAbsolute(src) || src.startsWith("/"); - if (dir && shouldJoin) { - src = path.join(dir, src); - } - return sizeOf(src); + if (dir && shouldJoin) { + src = path.join(dir, src); + } + return sizeOf(src); } diff --git a/src/utils/get-suggested-articles.ts b/src/utils/get-suggested-articles.ts index 6e24946d..25288bba 100644 --- a/src/utils/get-suggested-articles.ts +++ b/src/utils/get-suggested-articles.ts @@ -1,184 +1,181 @@ -import { Languages, PostInfo } from "types/index"; -import { getAllPosts } from "./get-all-posts"; - -const postLangMap = new Map>(); - -const getAllPostsByLang = ( - lang: Languages -): { suggestedPosts: PostInfo[]; dateSorted: PostInfo[] } => { - if (postLangMap.has(lang)) return postLangMap.get(lang)!; - const suggestedPosts = getAllPosts(lang); - - // We must spread, since `sort` mutates the original array - const dateSorted = [...suggestedPosts].sort((postA, postB) => { - return ( - // Newest first - new Date(postB.published) < new Date(postA.published) ? -1 : 1 - ); - }); - - postLangMap.set(lang, { suggestedPosts, dateSorted }); - - return { suggestedPosts, dateSorted }; -}; - -export type OrderSuggestPosts = ReturnType< - typeof getAllPostsByLang ->["suggestedPosts"]; - -/** - * Get 3 similar articles to suggest in sidebar. - * Base off of article series,and similar tags. - * If neither apply, simply grab latest articles - * - * However, they should take the precedence. If there are - * series articles, they should suggest higher than - * matching tags - * - * We check exactly how similar tags are in general. For example, given one - * post with 4 tags that match, and another post with only 2, the one with - * 4 tags will show above the one with 2. - * - * For suggested articles, get the articles only within - * 1 series order of each other. - * - * So, if we got "2", we could get: - * 1, 3, 4 - * - * But not: - * 1, 3, 5 - * - * Or, alternatively, if we got "3", we could get: - * 1, 2, 4 - * - * But not: - * 1, 4, 5 - */ -const howManySimilarBetween = (arr1: T[], arr2: T[]): number => { - let match = 0; - for (let item of arr1) { - if (arr2.includes(item)) match++; - } - return match; -}; - -const getOrderRange = (arr: OrderSuggestPosts) => { - return arr.reduce<{ - largest: null | OrderSuggestPosts[number]; - smallest: null | OrderSuggestPosts[number]; - }>( - (prev, curr) => { - if (prev.smallest === null || prev.largest === null) { - return { - largest: curr, - smallest: curr, - }; - } - if (curr.order! < prev.smallest.order!) { - prev.smallest = curr; - } - if (curr.order! > prev.largest.order!) { - prev.largest = curr; - } - return prev; - }, - { largest: null, smallest: null } - ) as never as { - largest: OrderSuggestPosts[number]; - smallest: OrderSuggestPosts[number]; - }; -}; - -export const getSuggestedArticles = ( - postNode: PostInfo, - lang: Languages -) => { - const { suggestedPosts, dateSorted } = getAllPostsByLang(lang); - - let extraSuggestedArticles: OrderSuggestPosts = []; - let suggestedArticles: OrderSuggestPosts = []; - let similarTags: Array<{ - post: OrderSuggestPosts[number]; - howManyTagsSimilar: number; - }> = []; - for (let post of suggestedPosts) { - // Early "return" for value - if (suggestedArticles.length >= 3) break; - // Don't return the same article - if (post.slug === postNode.slug) continue; - - if (!!post.series && post.series === postNode.series) { - const { largest, smallest } = - getOrderRange([...suggestedArticles, postNode]) || {}; - - let newArticlePushed = false; - if ( - largest && - smallest && - (post.order === smallest.order! - 1 || - post.order === largest.order! + 1) - ) { - suggestedArticles.push(post); - newArticlePushed = false; - } - /** - * Because we've just updated the `largest` and `smallest`, it's possible - * there's another match in our list of suggested articles. Go check - * - * This may seem bad to do a while loop here, but I promise that we'll - * never have a series longer than even, like, 20 articles. This is a massive - * improvement over looping through the entire list of articles. - */ - while (newArticlePushed) { - if (suggestedArticles.length >= 3) break; - if (extraSuggestedArticles.length === 0) break; - const { largest, smallest } = getOrderRange(suggestedArticles) || {}; - for (let suggestedPost of extraSuggestedArticles) { - if ( - suggestedPost.order === smallest.order! - 1 || - suggestedPost.order === largest.order! + 1 - ) { - suggestedArticles.push(suggestedPost); - } - } - } - if (suggestedArticles.length >= 3) break; - extraSuggestedArticles.push(post); - } - const howManyTagsSimilar = howManySimilarBetween( - post.tags, - postNode.tags || [] - ); - if (howManyTagsSimilar > 0) { - similarTags.push({ post, howManyTagsSimilar }); - } - } - - // Check to see if there are at least three suggested articles. - // If not, fill it with another array of suggested articles. - const fillSuggestionArrayWith = (otherArr: OrderSuggestPosts) => { - if (suggestedArticles.length < 3) { - let sizeToPush = 3 - suggestedArticles.length; - for (const item of otherArr) { - // Handle non-blog content, like about page - if (!item?.published) continue; - // Don't suggest itself - if (item.slug === postNode.slug) continue; - // No duplicates, please! - if (suggestedArticles.includes(item)) continue; - suggestedArticles.push(item); - sizeToPush--; - if (sizeToPush <= 0) return; - } - } - }; - - const tagSimilaritySorted = similarTags - .sort((a, b) => b.howManyTagsSimilar - a.howManyTagsSimilar) - .map(({ post }) => post); - fillSuggestionArrayWith(tagSimilaritySorted); - - fillSuggestionArrayWith(dateSorted); - - return suggestedArticles; -}; +import { Languages, PostInfo } from "types/index"; +import { getAllPosts } from "./get-all-posts"; + +const postLangMap = new Map>(); + +const getAllPostsByLang = ( + lang: Languages +): { suggestedPosts: PostInfo[]; dateSorted: PostInfo[] } => { + if (postLangMap.has(lang)) return postLangMap.get(lang)!; + const suggestedPosts = getAllPosts(lang); + + // We must spread, since `sort` mutates the original array + const dateSorted = [...suggestedPosts].sort((postA, postB) => { + return ( + // Newest first + new Date(postB.published) < new Date(postA.published) ? -1 : 1 + ); + }); + + postLangMap.set(lang, { suggestedPosts, dateSorted }); + + return { suggestedPosts, dateSorted }; +}; + +export type OrderSuggestPosts = ReturnType< + typeof getAllPostsByLang +>["suggestedPosts"]; + +/** + * Get 3 similar articles to suggest in sidebar. + * Base off of article series,and similar tags. + * If neither apply, simply grab latest articles + * + * However, they should take the precedence. If there are + * series articles, they should suggest higher than + * matching tags + * + * We check exactly how similar tags are in general. For example, given one + * post with 4 tags that match, and another post with only 2, the one with + * 4 tags will show above the one with 2. + * + * For suggested articles, get the articles only within + * 1 series order of each other. + * + * So, if we got "2", we could get: + * 1, 3, 4 + * + * But not: + * 1, 3, 5 + * + * Or, alternatively, if we got "3", we could get: + * 1, 2, 4 + * + * But not: + * 1, 4, 5 + */ +const howManySimilarBetween = (arr1: T[], arr2: T[]): number => { + let match = 0; + for (const item of arr1) { + if (arr2.includes(item)) match++; + } + return match; +}; + +const getOrderRange = (arr: OrderSuggestPosts) => { + return arr.reduce<{ + largest: null | OrderSuggestPosts[number]; + smallest: null | OrderSuggestPosts[number]; + }>( + (prev, curr) => { + if (prev.smallest === null || prev.largest === null) { + return { + largest: curr, + smallest: curr, + }; + } + if (curr.order! < prev.smallest.order!) { + prev.smallest = curr; + } + if (curr.order! > prev.largest.order!) { + prev.largest = curr; + } + return prev; + }, + { largest: null, smallest: null } + ) as never as { + largest: OrderSuggestPosts[number]; + smallest: OrderSuggestPosts[number]; + }; +}; + +export const getSuggestedArticles = (postNode: PostInfo, lang: Languages) => { + const { suggestedPosts, dateSorted } = getAllPostsByLang(lang); + + const extraSuggestedArticles: OrderSuggestPosts = []; + const suggestedArticles: OrderSuggestPosts = []; + const similarTags: Array<{ + post: OrderSuggestPosts[number]; + howManyTagsSimilar: number; + }> = []; + for (const post of suggestedPosts) { + // Early "return" for value + if (suggestedArticles.length >= 3) break; + // Don't return the same article + if (post.slug === postNode.slug) continue; + + if (!!post.series && post.series === postNode.series) { + const { largest, smallest } = + getOrderRange([...suggestedArticles, postNode]) || {}; + + let newArticlePushed = false; + if ( + largest && + smallest && + (post.order === smallest.order! - 1 || + post.order === largest.order! + 1) + ) { + suggestedArticles.push(post); + newArticlePushed = false; + } + /** + * Because we've just updated the `largest` and `smallest`, it's possible + * there's another match in our list of suggested articles. Go check + * + * This may seem bad to do a while loop here, but I promise that we'll + * never have a series longer than even, like, 20 articles. This is a massive + * improvement over looping through the entire list of articles. + */ + while (newArticlePushed) { + if (suggestedArticles.length >= 3) break; + if (extraSuggestedArticles.length === 0) break; + const { largest, smallest } = getOrderRange(suggestedArticles) || {}; + for (const suggestedPost of extraSuggestedArticles) { + if ( + suggestedPost.order === smallest.order! - 1 || + suggestedPost.order === largest.order! + 1 + ) { + suggestedArticles.push(suggestedPost); + } + } + } + if (suggestedArticles.length >= 3) break; + extraSuggestedArticles.push(post); + } + const howManyTagsSimilar = howManySimilarBetween( + post.tags, + postNode.tags || [] + ); + if (howManyTagsSimilar > 0) { + similarTags.push({ post, howManyTagsSimilar }); + } + } + + // Check to see if there are at least three suggested articles. + // If not, fill it with another array of suggested articles. + const fillSuggestionArrayWith = (otherArr: OrderSuggestPosts) => { + if (suggestedArticles.length < 3) { + let sizeToPush = 3 - suggestedArticles.length; + for (const item of otherArr) { + // Handle non-blog content, like about page + if (!item?.published) continue; + // Don't suggest itself + if (item.slug === postNode.slug) continue; + // No duplicates, please! + if (suggestedArticles.includes(item)) continue; + suggestedArticles.push(item); + sizeToPush--; + if (sizeToPush <= 0) return; + } + } + }; + + const tagSimilaritySorted = similarTags + .sort((a, b) => b.howManyTagsSimilar - a.howManyTagsSimilar) + .map(({ post }) => post); + fillSuggestionArrayWith(tagSimilaritySorted); + + fillSuggestionArrayWith(dateSorted); + + return suggestedArticles; +}; diff --git a/src/utils/markdown/rehype-astro-image-md.ts b/src/utils/markdown/rehype-astro-image-md.ts index 749128ea..95e3b0c1 100644 --- a/src/utils/markdown/rehype-astro-image-md.ts +++ b/src/utils/markdown/rehype-astro-image-md.ts @@ -1,77 +1,81 @@ -import { Root } from "hast"; -import { Plugin } from "unified"; - -import { visit } from "unist-util-visit"; - -import path from "path"; - -/** - * They need to be the same `getImage` with the same `globalThis` instance, thanks to the "hack" workaround. - */ -import { getImage } from "../../../node_modules/@astrojs/image"; -import sharp_service from "../../../node_modules/@astrojs/image/dist/loaders/sharp.js"; -import {getImageSize} from "../get-image-size"; -import {fileURLToPath} from "url"; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); - -interface RehypeAstroImageProps { - maxHeight?: number; - maxWidth?: number; -} - -export const rehypeAstroImageMd: Plugin< - [RehypeAstroImageProps | never], - Root -> = ({ maxHeight, maxWidth }) => { - return async (tree, file) => { - // HACK: This is a hack that heavily relies on `getImage`'s internals :( - globalThis.astroImage = { - loader: sharp_service ?? globalThis.astroImage?.loader, - }; - - let imgNodes: any[] = []; - visit(tree, (node: any) => { - if (node.tagName === "img") { - imgNodes.push(node); - } - }); - - await Promise.all( - imgNodes.map(async (node) => { - const slug = path.dirname(file.path).split('/').at(-1); - - const filePathDir = path.resolve(__dirname, '../../../public/content/blog', slug) - - // TODO: How should remote images be handled? - const dimensions = getImageSize(node.properties.src, filePathDir) || { - height: undefined, - width: undefined, - }; - - // TODO: Remote images? - if (!dimensions.height || !dimensions.width) return; - - const imgRatioHeight = dimensions.height / dimensions.width; - const imgRatioWidth = dimensions.width / dimensions.height; - if (maxHeight && dimensions.height > maxHeight) { - dimensions.height = maxHeight; - dimensions.width = maxHeight * imgRatioWidth; - } - - if (maxWidth && dimensions.width > maxWidth) { - dimensions.width = maxWidth; - dimensions.height = maxWidth * imgRatioHeight; - } - - const imgProps = await getImage({ - src: `/content/blog/${slug}/${node.properties.src}`, - height: dimensions.height, - width: dimensions.width, - }); - - node.properties.src = imgProps.src; - }) - ); - }; -}; +import { Root } from "hast"; +import { Plugin } from "unified"; + +import { visit } from "unist-util-visit"; + +import path from "path"; + +/** + * They need to be the same `getImage` with the same `globalThis` instance, thanks to the "hack" workaround. + */ +import { getImage } from "../../../node_modules/@astrojs/image"; +import sharp_service from "../../../node_modules/@astrojs/image/dist/loaders/sharp.js"; +import { getImageSize } from "../get-image-size"; +import { fileURLToPath } from "url"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +interface RehypeAstroImageProps { + maxHeight?: number; + maxWidth?: number; +} + +export const rehypeAstroImageMd: Plugin< + [RehypeAstroImageProps | never], + Root +> = ({ maxHeight, maxWidth }) => { + return async (tree, file) => { + // HACK: This is a hack that heavily relies on `getImage`'s internals :( + globalThis.astroImage = { + loader: sharp_service ?? globalThis.astroImage?.loader, + }; + + const imgNodes: any[] = []; + visit(tree, (node: any) => { + if (node.tagName === "img") { + imgNodes.push(node); + } + }); + + await Promise.all( + imgNodes.map(async (node) => { + const slug = path.dirname(file.path).split("/").at(-1); + + const filePathDir = path.resolve( + __dirname, + "../../../public/content/blog", + slug + ); + + // TODO: How should remote images be handled? + const dimensions = getImageSize(node.properties.src, filePathDir) || { + height: undefined, + width: undefined, + }; + + // TODO: Remote images? + if (!dimensions.height || !dimensions.width) return; + + const imgRatioHeight = dimensions.height / dimensions.width; + const imgRatioWidth = dimensions.width / dimensions.height; + if (maxHeight && dimensions.height > maxHeight) { + dimensions.height = maxHeight; + dimensions.width = maxHeight * imgRatioWidth; + } + + if (maxWidth && dimensions.width > maxWidth) { + dimensions.width = maxWidth; + dimensions.height = maxWidth * imgRatioHeight; + } + + const imgProps = await getImage({ + src: `/content/blog/${slug}/${node.properties.src}`, + height: dimensions.height, + width: dimensions.width, + }); + + node.properties.src = imgProps.src; + }) + ); + }; +}; diff --git a/src/utils/markdown/rehype-excerpt.ts b/src/utils/markdown/rehype-excerpt.ts index e0edf26c..d2140ba7 100644 --- a/src/utils/markdown/rehype-excerpt.ts +++ b/src/utils/markdown/rehype-excerpt.ts @@ -1,37 +1,37 @@ -import { Root } from "hast"; -import { Plugin } from "unified"; -import {visit} from 'unist-util-visit' - -interface RehypeExcerptProps { - maxLength: number; -} - -export const rehypeExcerpt: Plugin< - [RehypeExcerptProps | never], - Root -> = ({maxLength}) => { - return (tree, file) => { - const getFileExcerpt = () => (file?.data?.astro as any)?.frontmatter?.excerpt as string; - const setFileExcerpt = (val) => { - (file.data.astro as any).frontmatter.excerpt = val; - } - if (!getFileExcerpt()) { - setFileExcerpt(""); - } - - visit(tree, 'element', node => { - const fileExcerpt = getFileExcerpt(); - if (fileExcerpt.length >= maxLength) return; - // Don't get headers or anything other than text - if (node.tagName === 'p') { - visit(node, 'text', textNode => { - let newVal = fileExcerpt + textNode.value; - if (newVal.length > maxLength) { - newVal = newVal.slice(0, maxLength - 3) + "..."; - } - setFileExcerpt(newVal); - }) - } - }); - }; -}; +import { Root } from "hast"; +import { Plugin } from "unified"; +import { visit } from "unist-util-visit"; + +interface RehypeExcerptProps { + maxLength: number; +} + +export const rehypeExcerpt: Plugin<[RehypeExcerptProps | never], Root> = ({ + maxLength, +}) => { + return (tree, file) => { + const getFileExcerpt = () => + (file?.data?.astro as any)?.frontmatter?.excerpt as string; + const setFileExcerpt = (val) => { + (file.data.astro as any).frontmatter.excerpt = val; + }; + if (!getFileExcerpt()) { + setFileExcerpt(""); + } + + visit(tree, "element", (node) => { + const fileExcerpt = getFileExcerpt(); + if (fileExcerpt.length >= maxLength) return; + // Don't get headers or anything other than text + if (node.tagName === "p") { + visit(node, "text", (textNode) => { + let newVal = fileExcerpt + textNode.value; + if (newVal.length > maxLength) { + newVal = newVal.slice(0, maxLength - 3) + "..."; + } + setFileExcerpt(newVal); + }); + } + }); + }; +}; diff --git a/src/utils/markdown/rehype-header-text.ts b/src/utils/markdown/rehype-header-text.ts index 32bd6988..4dc941c9 100644 --- a/src/utils/markdown/rehype-header-text.ts +++ b/src/utils/markdown/rehype-header-text.ts @@ -2,35 +2,35 @@ import { headingRank } from "hast-util-heading-rank"; import { hasProperty } from "hast-util-has-property"; import { toString } from "hast-util-to-string"; import { Root, Parent } from "hast"; -import {visit} from "unist-util-visit"; +import { visit } from "unist-util-visit"; /** * Plugin to add `data-header-text`s to headings. */ export const rehypeHeaderText = () => { - return (tree: Root, file) => { - visit(tree, "element", (node: Parent["children"][number]) => { - if ( - headingRank(node) && - "properties" in node && - node.properties && - !hasProperty(node, "data-header-text") - ) { - const headerText = toString(node); - node.properties["data-header-text"] = headerText; + return (tree: Root, file) => { + visit(tree, "element", (node: Parent["children"][number]) => { + if ( + headingRank(node) && + "properties" in node && + node.properties && + !hasProperty(node, "data-header-text") + ) { + const headerText = toString(node); + node.properties["data-header-text"] = headerText; - const headingWithID = { - value: headerText, - depth: headingRank(node)!, - slug: node.properties["id"] as string, - }; + const headingWithID = { + value: headerText, + depth: headingRank(node)!, + slug: node.properties["id"] as string, + }; - if (file.data.astro.frontmatter.headingsWithId) { - file.data.astro.frontmatter.headingsWithId.push(headingWithID) - } else { - file.data.astro.frontmatter.headingsWithId = [headingWithID]; - } - } - }); - }; - }; + if (file.data.astro.frontmatter.headingsWithId) { + file.data.astro.frontmatter.headingsWithId.push(headingWithID); + } else { + file.data.astro.frontmatter.headingsWithId = [headingWithID]; + } + } + }); + }; +}; diff --git a/src/utils/markdown/rehype-unicorn-element-map.ts b/src/utils/markdown/rehype-unicorn-element-map.ts index af4268b5..6cc8fba2 100644 --- a/src/utils/markdown/rehype-unicorn-element-map.ts +++ b/src/utils/markdown/rehype-unicorn-element-map.ts @@ -1,115 +1,116 @@ -import { Root } from "hast"; -import { Plugin } from "unified"; - -import { visit } from "unist-util-visit"; - -import { EMBED_SIZE } from "./constants"; -import { isRelativePath } from "../url-paths"; -import { fromHtml } from "hast-util-from-html"; - -import path from "path"; - -interface RehypeUnicornElementMapProps { -} - -function escapeHTML(s) { - if (!s) return s; - return s - .replace(/&/g, "&") - .replace(/"/g, """) - .replace(//g, ">"); -} - -// TODO: Add switch/case and dedicated files ala "Components" -export const rehypeUnicornElementMap: Plugin< - [RehypeUnicornElementMapProps | never], - Root -> = () => { - return async (tree, file) => { - visit(tree, (node: any) => { - if (node.tagName === "iframe") { - node.properties.width ??= EMBED_SIZE.w; - node.properties.height ??= EMBED_SIZE.h; - node.properties.loading ??= "lazy"; - } - - if (node.tagName === "video") { - node.properties.muted ??= true; - node.properties.autoPlay ??= true; - node.properties.controls ??= true; - node.properties.loop ??= true; - node.properties.width ??= "100%"; - node.properties.height ??= "auto"; - } - - if (node.tagName === "a") { - const href = node.properties.href; - const isInternalLink = isRelativePath(href || ""); - if (!isInternalLink) { - node.properties.target = "_blank"; - node.properties.rel = "nofollow noopener noreferrer"; - } - } - - if (node.tagName === "table" && !node.properties["has-changed"]) { - const children = [...node.children]; - const properties = { ...node.properties, "has-changed": true }; - node.tagName = "div"; - node.properties = { - class: "table-container", - }; - node.children = [ - { - tagName: "table", - type: "element", - children, - properties, - }, - ]; - } - - if ( - node.tagName === "h1" || - node.tagName === "h2" || - node.tagName === "h3" || - node.tagName === "h4" || - node.tagName === "h5" || - node.tagName === "h6" - ) { - const id = node.properties.id; - const headerText = node.properties["data-header-text"]; - node.properties.style = - (node.properties.style || "") + "position: relative;"; - - const headerLinkHTML = ` - - - - - - - `; - - const hastHeader = fromHtml(headerLinkHTML, { fragment: true }); - node.children = [hastHeader, ...node.children]; - } - }); - }; -}; +import { Root } from "hast"; +import { Plugin } from "unified"; + +import { visit } from "unist-util-visit"; + +import { EMBED_SIZE } from "./constants"; +import { isRelativePath } from "../url-paths"; +import { fromHtml } from "hast-util-from-html"; + +import path from "path"; + +interface RehypeUnicornElementMapProps {} + +function escapeHTML(s) { + if (!s) return s; + return s + .replace(/&/g, "&") + .replace(/"/g, """) + .replace(//g, ">"); +} + +// TODO: Add switch/case and dedicated files ala "Components" +export const rehypeUnicornElementMap: Plugin< + [RehypeUnicornElementMapProps | never], + Root +> = () => { + return async (tree, file) => { + visit(tree, (node: any) => { + if (node.tagName === "iframe") { + node.properties.width ??= EMBED_SIZE.w; + node.properties.height ??= EMBED_SIZE.h; + node.properties.loading ??= "lazy"; + } + + if (node.tagName === "video") { + node.properties.muted ??= true; + node.properties.autoPlay ??= true; + node.properties.controls ??= true; + node.properties.loop ??= true; + node.properties.width ??= "100%"; + node.properties.height ??= "auto"; + } + + if (node.tagName === "a") { + const href = node.properties.href; + const isInternalLink = isRelativePath(href || ""); + if (!isInternalLink) { + node.properties.target = "_blank"; + node.properties.rel = "nofollow noopener noreferrer"; + } + } + + if (node.tagName === "table" && !node.properties["has-changed"]) { + const children = [...node.children]; + const properties = { ...node.properties, "has-changed": true }; + node.tagName = "div"; + node.properties = { + class: "table-container", + }; + node.children = [ + { + tagName: "table", + type: "element", + children, + properties, + }, + ]; + } + + if ( + node.tagName === "h1" || + node.tagName === "h2" || + node.tagName === "h3" || + node.tagName === "h4" || + node.tagName === "h5" || + node.tagName === "h6" + ) { + const id = node.properties.id; + const headerText = node.properties["data-header-text"]; + node.properties.style = + (node.properties.style || "") + "position: relative;"; + + const headerLinkHTML = ` + + + + + + + `; + + const hastHeader = fromHtml(headerLinkHTML, { fragment: true }); + node.children = [hastHeader, ...node.children]; + } + }); + }; +}; diff --git a/src/utils/markdown/rehype-unicorn-get-suggested-posts.ts b/src/utils/markdown/rehype-unicorn-get-suggested-posts.ts index 112de4a7..2d4aa3de 100644 --- a/src/utils/markdown/rehype-unicorn-get-suggested-posts.ts +++ b/src/utils/markdown/rehype-unicorn-get-suggested-posts.ts @@ -1,25 +1,24 @@ -import { Root } from "hast"; -import { Plugin } from "unified"; -import {getSuggestedArticles} from "../get-suggested-articles"; - -interface RehypeUnicornGetSuggestedPostsProps { -} - -export const rehypeUnicornGetSuggestedPosts: Plugin< - [RehypeUnicornGetSuggestedPostsProps | never], - Root -> = () => { - return (_, file) => { - function setData(key: string, val: any) { - (file.data.astro as any).frontmatter[key] = val; - } - - const post = { - ...(file.data.astro as any).frontmatter.frontmatterBackup, - ...(file.data.astro as any).frontmatter - } - - const suggestedArticles = getSuggestedArticles(post, 'en'); - setData("suggestedArticles", suggestedArticles); - }; -}; +import { Root } from "hast"; +import { Plugin } from "unified"; +import { getSuggestedArticles } from "../get-suggested-articles"; + +interface RehypeUnicornGetSuggestedPostsProps {} + +export const rehypeUnicornGetSuggestedPosts: Plugin< + [RehypeUnicornGetSuggestedPostsProps | never], + Root +> = () => { + return (_, file) => { + function setData(key: string, val: any) { + (file.data.astro as any).frontmatter[key] = val; + } + + const post = { + ...(file.data.astro as any).frontmatter.frontmatterBackup, + ...(file.data.astro as any).frontmatter, + }; + + const suggestedArticles = getSuggestedArticles(post, "en"); + setData("suggestedArticles", suggestedArticles); + }; +}; diff --git a/src/utils/markdown/rehype-unicorn-populate-post.ts b/src/utils/markdown/rehype-unicorn-populate-post.ts index aea20486..c0938e25 100644 --- a/src/utils/markdown/rehype-unicorn-populate-post.ts +++ b/src/utils/markdown/rehype-unicorn-populate-post.ts @@ -1,81 +1,77 @@ -import { Root } from "hast"; -import { Plugin } from "unified"; -import matter from "gray-matter"; -import { readFileSync } from "fs"; -import * as path from "path"; -import { licenses, unicorns } from "../data"; - -interface RehypeUnicornPopulatePostProps { -} - -export const rehypeUnicornPopulatePost: Plugin< - [RehypeUnicornPopulatePostProps | never], - Root -> = () => { - return (_, file) => { - - function setData(key: string, val: any) { - (file.data.astro as any).frontmatter[key] = val; - } - - const fileContents = readFileSync(file.path, "utf8"); - const { data: frontmatter } = matter(fileContents); - - const directorySplit = file.path.split(path.sep); - - // This is the folder name, AKA how we generate the slug ID - const slug = directorySplit.at(-2); - - // Calculate post locale - // index.md or index.es.md - const indexName = directorySplit.at(-1); - const indexSplit = indexName.split('.'); - let locale = indexSplit.at(-2); - if (locale === 'index') { - locale = 'en'; - } - - // // TODO: Add translations - // if (fields.translations) { - // const langsToQuery: Languages[] = Object.keys(languages).filter( - // (l) => l !== lang - // ) as never; - // pickedData.translations = langsToQuery - // .filter((lang) => - // fs.existsSync(resolve(dirname(fullPath), getIndexPath(lang))) - // ) - // .reduce((prev, lang) => { - // prev[lang] = languages[lang]; - // return prev; - // }, {} as Record); - // } - - // // TODO: Add collection slug - // if (fields.collectionSlug) { - // if (frontmatterData.series) { - // pickedData.collectionSlug = collectionsByName.find( - // (collection) => collection.associatedSeries === frontmatterData.series - // )?.slug; - // } - // if (!pickedData.collectionSlug) pickedData.collectionSlug = null; - // } - - const authorsMeta = (frontmatter.authors as string[]).map( - (author) => unicorns.find((unicorn) => unicorn.id === author)! - ); - - let license; - if (frontmatter.license) { - license = licenses.find( - (l) => l.id === frontmatter.license - ); - } - if (!license) license = null; - - setData('slug', slug); - setData('locale', locale); - setData('authorsMeta', authorsMeta); - setData('license', license); - setData('frontmatterBackup', frontmatter); - }; -}; +import { Root } from "hast"; +import { Plugin } from "unified"; +import matter from "gray-matter"; +import { readFileSync } from "fs"; +import * as path from "path"; +import { licenses, unicorns } from "../data"; + +interface RehypeUnicornPopulatePostProps {} + +export const rehypeUnicornPopulatePost: Plugin< + [RehypeUnicornPopulatePostProps | never], + Root +> = () => { + return (_, file) => { + function setData(key: string, val: any) { + (file.data.astro as any).frontmatter[key] = val; + } + + const fileContents = readFileSync(file.path, "utf8"); + const { data: frontmatter } = matter(fileContents); + + const directorySplit = file.path.split(path.sep); + + // This is the folder name, AKA how we generate the slug ID + const slug = directorySplit.at(-2); + + // Calculate post locale + // index.md or index.es.md + const indexName = directorySplit.at(-1); + const indexSplit = indexName.split("."); + let locale = indexSplit.at(-2); + if (locale === "index") { + locale = "en"; + } + + // // TODO: Add translations + // if (fields.translations) { + // const langsToQuery: Languages[] = Object.keys(languages).filter( + // (l) => l !== lang + // ) as never; + // pickedData.translations = langsToQuery + // .filter((lang) => + // fs.existsSync(resolve(dirname(fullPath), getIndexPath(lang))) + // ) + // .reduce((prev, lang) => { + // prev[lang] = languages[lang]; + // return prev; + // }, {} as Record); + // } + + // // TODO: Add collection slug + // if (fields.collectionSlug) { + // if (frontmatterData.series) { + // pickedData.collectionSlug = collectionsByName.find( + // (collection) => collection.associatedSeries === frontmatterData.series + // )?.slug; + // } + // if (!pickedData.collectionSlug) pickedData.collectionSlug = null; + // } + + const authorsMeta = (frontmatter.authors as string[]).map( + (author) => unicorns.find((unicorn) => unicorn.id === author)! + ); + + let license; + if (frontmatter.license) { + license = licenses.find((l) => l.id === frontmatter.license); + } + if (!license) license = null; + + setData("slug", slug); + setData("locale", locale); + setData("authorsMeta", authorsMeta); + setData("license", license); + setData("frontmatterBackup", frontmatter); + }; +}; diff --git a/src/utils/markdown/rehype-word-count.ts b/src/utils/markdown/rehype-word-count.ts index bd0386f7..bcb802a7 100644 --- a/src/utils/markdown/rehype-word-count.ts +++ b/src/utils/markdown/rehype-word-count.ts @@ -1,72 +1,76 @@ -/** - * An ode to words - * - * Oh words, what can be said of thee? - * - * Not much me. - * - * See, it's concieved that ye might have intreging definitions from one-to-another - * - * This is to say: "What is a word?" - * - * An existential question at best, a sisyphean effort at worst. - * - * See, while `forms` and `angular` might be considered one word each: what of `@angular/forms`? Is that 2? - * - * Or, what of `@someone mentioned Angular's forms`? Is that 4? - * - * This is a long-winded way of saying "We know our word counter is inaccurate, but so is yours." - * - * Please do let us know if you have strong thoughts/answers on the topic, - * we're happy to hear them. - */ -import { Root, Parent, Text } from "hast"; -import { Node } from "unist"; -import { Plugin } from "unified"; -import { visit } from "unist-util-visit"; - -import { unified } from "unified"; -import english from "retext-english"; -import rehypeRetext from 'rehype-retext'; -import { validateConfig } from "astro/dist/types/core/config"; - -interface RemarkCountProps {} - -function count(counts: Record) { - return () => counter; - - function counter(tree: Root) { - visit(tree, visitor); - - function visitor(node: Node) { - if (node.type === 'SourceNode') { - const inlineCount = (node as never as {value: string}).value.split(/\b/g).length; - counts["InlineCodeWords"] = (counts["InlineCodeWords"] || 0) + inlineCount; - } - counts[node.type] = (counts[node.type] || 0) + 1; - } - } -} - -export const rehypeWordCount: Plugin<[RemarkCountProps | never], Root> = () => { - return async (tree, file) => { - const counts = {} as { - InlineCodeWords: number; - RootNode: number; - ParagraphNode: number; - SentenceNode: number; - WordNode: number; - TextNode: number; - WhiteSpaceNode: number; - PunctuationNode: number; - SymbolNode: number; - SourceNode: number; - }; - - await unified() - .use(rehypeRetext, unified().use(english).use(count(counts))) - .run(tree); - - (file.data.astro as any).frontmatter.wordCount = (counts.InlineCodeWords || 0) + (counts.TextNode || 0); - }; -}; +/** + * An ode to words + * + * Oh words, what can be said of thee? + * + * Not much me. + * + * See, it's concieved that ye might have intreging definitions from one-to-another + * + * This is to say: "What is a word?" + * + * An existential question at best, a sisyphean effort at worst. + * + * See, while `forms` and `angular` might be considered one word each: what of `@angular/forms`? Is that 2? + * + * Or, what of `@someone mentioned Angular's forms`? Is that 4? + * + * This is a long-winded way of saying "We know our word counter is inaccurate, but so is yours." + * + * Please do let us know if you have strong thoughts/answers on the topic, + * we're happy to hear them. + */ +import { Root, Parent, Text } from "hast"; +import { Node } from "unist"; +import { Plugin } from "unified"; +import { visit } from "unist-util-visit"; + +import { unified } from "unified"; +import english from "retext-english"; +import rehypeRetext from "rehype-retext"; +import { validateConfig } from "astro/dist/types/core/config"; + +interface RemarkCountProps {} + +function count(counts: Record) { + return () => counter; + + function counter(tree: Root) { + visit(tree, visitor); + + function visitor(node: Node) { + if (node.type === "SourceNode") { + const inlineCount = (node as never as { value: string }).value.split( + /\b/g + ).length; + counts["InlineCodeWords"] = + (counts["InlineCodeWords"] || 0) + inlineCount; + } + counts[node.type] = (counts[node.type] || 0) + 1; + } + } +} + +export const rehypeWordCount: Plugin<[RemarkCountProps | never], Root> = () => { + return async (tree, file) => { + const counts = {} as { + InlineCodeWords: number; + RootNode: number; + ParagraphNode: number; + SentenceNode: number; + WordNode: number; + TextNode: number; + WhiteSpaceNode: number; + PunctuationNode: number; + SymbolNode: number; + SourceNode: number; + }; + + await unified() + .use(rehypeRetext, unified().use(english).use(count(counts))) + .run(tree); + + (file.data.astro as any).frontmatter.wordCount = + (counts.InlineCodeWords || 0) + (counts.TextNode || 0); + }; +}; diff --git a/src/utils/markdown/tabs/index.ts b/src/utils/markdown/tabs/index.ts index c2d1b4e9..811d3d4a 100644 --- a/src/utils/markdown/tabs/index.ts +++ b/src/utils/markdown/tabs/index.ts @@ -1 +1 @@ -export * from './tabs'; +export * from "./tabs"; diff --git a/src/utils/markdown/tabs/tabs.ts b/src/utils/markdown/tabs/tabs.ts index c334c049..22e31c3e 100644 --- a/src/utils/markdown/tabs/tabs.ts +++ b/src/utils/markdown/tabs/tabs.ts @@ -5,29 +5,29 @@ import { Plugin } from "unified"; import { getHeaderNodeId, slugs } from "rehype-slug-custom-id"; interface ElementNode extends Parent { - tagName: string; - properties: any; + tagName: string; + properties: any; } const isNodeHeading = (n: ElementNode) => - n.type === "element" && /h[1-6]/.exec(n.tagName); + n.type === "element" && /h[1-6]/.exec(n.tagName); const findLargestHeading = (nodes: ElementNode[]) => { - let largestSize = Infinity; - for (let node of nodes) { - if (!isNodeHeading(node)) continue; - const size = parseInt(node.tagName.substr(1), 10); - largestSize = Math.min(largestSize, size); - } - return largestSize; + let largestSize = Infinity; + for (const node of nodes) { + if (!isNodeHeading(node)) continue; + const size = parseInt(node.tagName.substr(1), 10); + largestSize = Math.min(largestSize, size); + } + return largestSize; }; const isNodeLargestHeading = (n: ElementNode, largestSize: number) => - isNodeHeading(n) && parseInt(n.tagName.substr(1), 10) === largestSize; + isNodeHeading(n) && parseInt(n.tagName.substr(1), 10) === largestSize; export interface RehypeTabsProps { - injectSubheaderProps?: boolean; - tabSlugifyProps?: Parameters[1]; + injectSubheaderProps?: boolean; + tabSlugifyProps?: Parameters[1]; } /** @@ -48,127 +48,127 @@ export interface RehypeTabsProps { * @see https://github.com/reactjs/react-tabs */ export const rehypeTabs: Plugin<[RehypeTabsProps | never], Root> = ({ - injectSubheaderProps = false, - tabSlugifyProps = {}, + injectSubheaderProps = false, + tabSlugifyProps = {}, }) => { - return (tree) => { - const replaceTabNodes = (nodes: Node[]) => { - let sectionStarted = false; + return (tree) => { + const replaceTabNodes = (nodes: Node[]) => { + let sectionStarted = false; - const largestSize = findLargestHeading(nodes as ElementNode[]); + const largestSize = findLargestHeading(nodes as ElementNode[]); - const tabsContainer = { - type: "element", - tagName: "div", - properties: { - class: "tabs" - }, - children: [ - { - type: "element", - tagName: "ul", - properties: { - role: 'tablist', - class: "tabs__tab-list" - }, - children: [] as ElementNode[], - }, - ], - }; + const tabsContainer = { + type: "element", + tagName: "div", + properties: { + class: "tabs", + }, + children: [ + { + type: "element", + tagName: "ul", + properties: { + role: "tablist", + class: "tabs__tab-list", + }, + children: [] as ElementNode[], + }, + ], + }; - for (const localNode of nodes as ElementNode[]) { - if (!sectionStarted && !isNodeLargestHeading(localNode, largestSize)) { - continue; - } - sectionStarted = true; + for (const localNode of nodes as ElementNode[]) { + if (!sectionStarted && !isNodeLargestHeading(localNode, largestSize)) { + continue; + } + sectionStarted = true; - if (isNodeLargestHeading(localNode, largestSize)) { - // Make sure that all tabs labeled "thing" aren't also labeled "thing2" - slugs.reset(); - const { id: headerSlug } = getHeaderNodeId( - localNode, - tabSlugifyProps - ); + if (isNodeLargestHeading(localNode, largestSize)) { + // Make sure that all tabs labeled "thing" aren't also labeled "thing2" + slugs.reset(); + const { id: headerSlug } = getHeaderNodeId( + localNode, + tabSlugifyProps + ); - // - 1 because the tabs are part of the header - const idx = tabsContainer.children.length - 1; + // - 1 because the tabs are part of the header + const idx = tabsContainer.children.length - 1; - const header = { - type: "element", - tagName: "li", - children: localNode.children, - properties: { - role: 'tab', - class: "tabs__tab", - "data-tabname": headerSlug, - "aria-selected": idx === 0 ? "true" : 'false', - "aria-controls": `panel-${idx}`, - "id": `tab-${idx}`, - tabIndex: idx === 0 ? "0" : "-1" - }, - }; + const header = { + type: "element", + tagName: "li", + children: localNode.children, + properties: { + role: "tab", + class: "tabs__tab", + "data-tabname": headerSlug, + "aria-selected": idx === 0 ? "true" : "false", + "aria-controls": `panel-${idx}`, + id: `tab-${idx}`, + tabIndex: idx === 0 ? "0" : "-1", + }, + }; - const contents = { - type: "element", - tagName: "div", - children: [], - properties: { - id: `panel-${idx}`, - role: "tabpanel", - class: "tabs__tab-panel", - tabindex: 0, - "aria-labelledby": `tab-${idx}`, - ...(idx === 0 ? {} : {hidden: "true"}) - }, - }; + const contents = { + type: "element", + tagName: "div", + children: [], + properties: { + id: `panel-${idx}`, + role: "tabpanel", + class: "tabs__tab-panel", + tabindex: 0, + "aria-labelledby": `tab-${idx}`, + ...(idx === 0 ? {} : { hidden: "true" }), + }, + }; - tabsContainer.children[0].children.push(header); + tabsContainer.children[0].children.push(header); - tabsContainer.children.push(contents); - continue; - } + tabsContainer.children.push(contents); + continue; + } - if (isNodeHeading(localNode) && injectSubheaderProps) { - // This is `tagName: tab` - const lastTab = - tabsContainer.children[0].children[ - tabsContainer.children[0].children.length - 1 - ]; + if (isNodeHeading(localNode) && injectSubheaderProps) { + // This is `tagName: tab` + const lastTab = + tabsContainer.children[0].children[ + tabsContainer.children[0].children.length - 1 + ]; - // Store the related tab ID in the attributes of the header - localNode.properties["data-tabname"] = - // Get the last tab's `data-tabname` property - lastTab.properties["data-tabname"]; + // Store the related tab ID in the attributes of the header + localNode.properties["data-tabname"] = + // Get the last tab's `data-tabname` property + lastTab.properties["data-tabname"]; - // Add header ID to array - lastTab.properties["data-headers"] = JSON.stringify( - JSON.parse(lastTab.properties["data-headers"] ?? "[]").concat( - localNode.properties.id - ) - ); - } + // Add header ID to array + lastTab.properties["data-headers"] = JSON.stringify( + JSON.parse(lastTab.properties["data-headers"] ?? "[]").concat( + localNode.properties.id + ) + ); + } - // Push into last `tab-panel` - tabsContainer.children[tabsContainer.children.length - 1].children.push( - localNode - ); - } + // Push into last `tab-panel` + tabsContainer.children[tabsContainer.children.length - 1].children.push( + localNode + ); + } - return [tabsContainer]; - }; + return [tabsContainer]; + }; - replaceAllBetween( - tree, - { type: "raw", value: "" } as never, - { type: "raw", value: "" } as never, - replaceTabNodes - ); - replaceAllBetween( - tree, - { type: "comment", value: " tabs:start " } as never, - { type: "comment", value: " tabs:end " } as never, - replaceTabNodes - ); - return tree; - }; + replaceAllBetween( + tree, + { type: "raw", value: "" } as never, + { type: "raw", value: "" } as never, + replaceTabNodes + ); + replaceAllBetween( + tree, + { type: "comment", value: " tabs:start " } as never, + { type: "comment", value: " tabs:end " } as never, + replaceTabNodes + ); + return tree; + }; }; diff --git a/src/utils/translations.ts b/src/utils/translations.ts index afa690da..c4947f56 100644 --- a/src/utils/translations.ts +++ b/src/utils/translations.ts @@ -8,13 +8,13 @@ import { languages } from "constants/index"; * code handles the parsing and converting of translation formats */ export function fileToOpenGraphConverter( - lang: T + lang: T ): T extends `${infer Lang}-${infer Region}` - ? `${Lang}_${Uppercase}` - : T { - const splitLang = lang.split("-"); - if (splitLang.length === 1) return lang as never; - return `${splitLang[0]}_${splitLang[1].toUpperCase()}` as never; + ? `${Lang}_${Uppercase}` + : T { + const splitLang = lang.split("-"); + if (splitLang.length === 1) return lang as never; + return `${splitLang[0]}_${splitLang[1].toUpperCase()}` as never; } /** @@ -30,12 +30,12 @@ export function fileToOpenGraphConverter( * @example "es-es/posts/test" -> "posts/test" */ export function removePrefixLanguageFromPath(path: string) { - const langs = Object.keys(languages) as Languages[]; - const matchedLang = langs.find( - (lang) => path.startsWith(lang) || path.startsWith("/" + lang) - ); - if (!matchedLang) return path; - if (path.startsWith("/")) return "/" + path.slice(matchedLang.length + 2); - // +1 since "es/path" needs to axe the trailing "/" - return path.slice(matchedLang.length + 1); + const langs = Object.keys(languages) as Languages[]; + const matchedLang = langs.find( + (lang) => path.startsWith(lang) || path.startsWith("/" + lang) + ); + if (!matchedLang) return path; + if (path.startsWith("/")) return "/" + path.slice(matchedLang.length + 2); + // +1 since "es/path" needs to axe the trailing "/" + return path.slice(matchedLang.length + 1); } diff --git a/src/utils/url-paths.ts b/src/utils/url-paths.ts index 44f3ff85..67d86a2a 100644 --- a/src/utils/url-paths.ts +++ b/src/utils/url-paths.ts @@ -9,33 +9,35 @@ import slash from "slash"; export const absolutePathRegex = /^(?:[a-z]+:)?\/\//; export const isRelativePath = (str: string) => { - const isAbsolute = absolutePathRegex.exec(str); - if (isAbsolute) return false; - return true; + const isAbsolute = absolutePathRegex.exec(str); + if (isAbsolute) return false; + return true; }; -var pathJoin = function(...pathArr){ - return pathArr.map(function(path){ - if(path[0] === "/"){ - path = path.slice(1); - } - if (path.startsWith('./')) { - path = path.slice(2); - } - if(path[path.length - 1] === "/"){ - path = path.slice(0, path.length - 1); - } - return path; - }).join("/"); -} +const pathJoin = function (...pathArr) { + return pathArr + .map(function (path) { + if (path[0] === "/") { + path = path.slice(1); + } + if (path.startsWith("./")) { + path = path.slice(2); + } + if (path[path.length - 1] === "/") { + path = path.slice(0, path.length - 1); + } + return path; + }) + .join("/"); +}; export const getFullRelativePath = (...paths: string[]) => { - return isRelativePath(paths[paths.length - 1]) - ? slash(pathJoin(...paths)) - : paths[paths.length - 1]; + return isRelativePath(paths[paths.length - 1]) + ? slash(pathJoin(...paths)) + : paths[paths.length - 1]; }; export const trimTrailingSlash = (path: string) => { - if (path.endsWith("/")) return path.slice(0, path.length - 1); - return path; + if (path.endsWith("/")) return path.slice(0, path.length - 1); + return path; }; diff --git a/tsconfig.json b/tsconfig.json index a9e7fcc1..15331f16 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,30 +1,30 @@ { - "compilerOptions": { - // Enable top-level await, and other modern ESM features. - "target": "ESNext", - "module": "ESNext", - // Enable node-style module resolution, for things like npm package imports. - "moduleResolution": "node", - // Enable JSON imports. - "resolveJsonModule": true, - // Enable stricter transpilation for better output. - "isolatedModules": true, - "esModuleInterop": true, - "jsx": "preserve", - "jsxImportSource": "preact", - "allowSyntheticDefaultImports": true, - // Add type definitions for our Vite runtime. - "types": ["@astrojs/image/client"], - "baseUrl": ".", - "paths": { - "constants/*": ["./src/constants/*"], - "uu-constants": ["./src/constants"], - "types/*": ["./src/types/*"], - "uu-types": ["./src/types"], - "components/*": ["./src/components/*"], - "utils/*": ["./src/utils/*"], - "uu-utils": ["./src/utils"], - "assets/*": ["./src/assets/*"], - } - } + "compilerOptions": { + // Enable top-level await, and other modern ESM features. + "target": "ESNext", + "module": "ESNext", + // Enable node-style module resolution, for things like npm package imports. + "moduleResolution": "node", + // Enable JSON imports. + "resolveJsonModule": true, + // Enable stricter transpilation for better output. + "isolatedModules": true, + "esModuleInterop": true, + "jsx": "preserve", + "jsxImportSource": "preact", + "allowSyntheticDefaultImports": true, + // Add type definitions for our Vite runtime. + "types": ["@astrojs/image/client"], + "baseUrl": ".", + "paths": { + "constants/*": ["./src/constants/*"], + "uu-constants": ["./src/constants"], + "types/*": ["./src/types/*"], + "uu-types": ["./src/types"], + "components/*": ["./src/components/*"], + "utils/*": ["./src/utils/*"], + "uu-utils": ["./src/utils"], + "assets/*": ["./src/assets/*"] + } + } } diff --git a/vercel.json b/vercel.json index 871aa422..bb67ef89 100644 --- a/vercel.json +++ b/vercel.json @@ -1,20 +1,20 @@ -{ - "framework": "astro", - "redirects": [ - { - "source": "/authors/crutchcorn/", - "destination": "/unicorns/crutchcorn", - "permanent": true - }, - { - "source": "/unicorns/", - "destination": "/about", - "permanent": false - }, - { - "source": "/posts/", - "destination": "/", - "permanent": true - } - ] -} +{ + "framework": "astro", + "redirects": [ + { + "source": "/authors/crutchcorn/", + "destination": "/unicorns/crutchcorn", + "permanent": true + }, + { + "source": "/unicorns/", + "destination": "/about", + "permanent": false + }, + { + "source": "/posts/", + "destination": "/", + "permanent": true + } + ] +}