diff --git a/.yarn/install-state.gz b/.yarn/install-state.gz index ba8be9f7..f2eda2ae 100644 Binary files a/.yarn/install-state.gz and b/.yarn/install-state.gz differ diff --git a/astro.config.mjs b/astro.config.mjs index d1479652..d58e69e6 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -12,7 +12,7 @@ export default defineConfig({ mdx(), sitemap(), react(), - million.vite({mode: 'react', server: true, auto: true}), + million.vite({ mode: 'react', server: true, auto: true }), partytown({ config: { forward: ['dataLayer.push'], diff --git a/package.json b/package.json index ac034651..0c80b7da 100644 --- a/package.json +++ b/package.json @@ -45,10 +45,10 @@ "@fontsource-variable/nunito-sans": "^5.0.9", "@fontsource/baskervville": "^5.0.18", "@hookform/resolvers": "^3.3.4", - "@types/node": "^20.11.20", - "@types/react": "^18.2.58", + "@types/node": "^20.11.22", + "@types/react": "^18.2.60", "@types/react-dom": "^18.2.19", - "astro": "^4.4.4", + "astro": "^4.4.6", "gsap": "^3.12.5", "markdown-it": "^14.0.0", "million": "^3.0.3", @@ -57,22 +57,22 @@ "react-globe.gl": "^2.27.2", "react-google-recaptcha-v3": "^1.10.1", "react-hook-form": "^7.50.1", - "react-router-dom": "^6.22.1", - "swiper": "^11.0.6", + "react-router-dom": "^6.22.2", + "swiper": "^11.0.7", "three": "^0.161.0", "typescript": "^5.3.3", "zod": "^3.22.4" }, "devDependencies": { - "@commitlint/cli": "^19.0.2", - "@commitlint/config-conventional": "^18.6.2", + "@commitlint/cli": "^19.0.3", + "@commitlint/config-conventional": "^19.0.3", "@testing-library/react": "^14.2.1", "@testing-library/react-hooks": "^8.0.1", - "@types/eslint": "^8.56.3", + "@types/eslint": "^8.56.5", "@types/markdown-it": "^13.0.7", "@types/three": "^0.161.2", - "@typescript-eslint/eslint-plugin": "^7.0.2", - "@typescript-eslint/parser": "^7.0.2", + "@typescript-eslint/eslint-plugin": "^7.1.0", + "@typescript-eslint/parser": "^7.1.0", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-astro": "^0.31.4", diff --git a/src/pages/index.astro b/src/pages/index.astro index d645beb0..9d837d67 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -5,7 +5,7 @@ import Testimonials from '@components/organisms/testimonials/Testimonials.astro' import MyWork from '@components/organisms/myWork/MyWork.astro'; import LatestArticles from '@components/organisms/latestArticles/LatestArticles.astro'; -// current send button +// current: contact intro // todo: responsive // todo: add resume (PDF) in about? // todo: add calendly (https://www.kelseyohalloran.com/chat) + form in contact diff --git a/src/ui/components/organisms/contactForm/ContactForm.tsx b/src/ui/components/organisms/contactForm/ContactForm.tsx index e04f0aa2..0c6a3c7b 100644 --- a/src/ui/components/organisms/contactForm/ContactForm.tsx +++ b/src/ui/components/organisms/contactForm/ContactForm.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useState } from 'react'; +import React, { useCallback, useRef, useState } from 'react'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; @@ -7,6 +7,7 @@ import './contact-form.css'; import { autosize } from '@components/organisms/contactForm/utils/autosize'; import { CONTACT_FORM_REQUEST_PARAMETERS } from 'src/consts.ts'; import { encode } from '@components/organisms/contactForm/utils/encode'; +import { flyPlane } from '@components/organisms/contactForm/utils/flyPlane'; const schema = z.object({ name: z.string().trim().min(1, 'Please insert your name'), @@ -40,6 +41,7 @@ export const ContactForm = () => { }); const [formStatus, setFormStatus] = useState(FormStatus.INITIAL); const { executeRecaptcha } = useGoogleReCaptcha(); + const submitRef = useRef(null); const verifyRecaptcha = useCallback( async (data: FormData, event: React.FormEvent) => { @@ -60,21 +62,28 @@ export const ContactForm = () => { const submitForm = useCallback(async (data: FormData, event: React.FormEvent) => { event.preventDefault(); + try { + setFormStatus(FormStatus.LOADING); + const requestParams: RequestInit = { + ...CONTACT_FORM_REQUEST_PARAMETERS, + body: encode({ ...data }), + }; - const requestParams: RequestInit = { - ...CONTACT_FORM_REQUEST_PARAMETERS, - body: encode({ ...data }), - }; - setFormStatus(FormStatus.LOADING); - fetch(`/`, requestParams) - .then(() => { - reset(); - setFormStatus(FormStatus.SUCCESS); - }) - .catch((error) => { - console.log(error); - setFormStatus(FormStatus.ERROR); - }); + const response = await fetch(`/`, requestParams); + + if (response.ok) { + flyPlane(submitRef.current!); + setTimeout(() => { + setFormStatus(FormStatus.SUCCESS); + reset(); + }, 2000); + } else { + throw new Error('Failed to submit form'); + } + } catch (error) { + console.error(error); + setFormStatus(FormStatus.ERROR); + } }, []); return ( @@ -142,10 +151,15 @@ export const ContactForm = () => {

{errors.recaptcha.message}

)} - + ) : ( -

Form sent correctly! Will be in touch soon

+

Form sent correctly! Will be in touch soon

)} ); diff --git a/src/ui/components/organisms/contactForm/contact-form.css b/src/ui/components/organisms/contactForm/contact-form.css index bf23e83a..e900d67d 100644 --- a/src/ui/components/organisms/contactForm/contact-form.css +++ b/src/ui/components/organisms/contactForm/contact-form.css @@ -64,11 +64,10 @@ } .contact-form__textarea { + min-height: 4rem; resize: vertical; text-align: start; width: 100%; - /*form-sizing: content;*/ - z-index: 10; &:is(:focus, :not(:placeholder-shown), :focus-within) + .contact-form__textarea-label { font-size: 1rem; @@ -129,4 +128,121 @@ .contact-form__recaptcha-wrapper { width: 100%; } + + .contact-form__success-message { + text-align: center; + } + + .contact-form__submit { + --text-opacity: 1; + --overflow: hidden; + --rotate: 0; + --plane-x: 0; + --plane-y: 0; + --plane-opacity: 1; + --left-wing-background: var(--neutral-main); + --left-wing-first-x: 0; + --left-wing-first-y: 0; + --left-wing-second-x: 50; + --left-wing-second-y: 0; + --left-wing-third-x: 0; + --left-wing-third-y: 100; + --left-body-background: var(--neutral-main); + --left-body-first-x: 50; + --left-body-first-y: 0; + --left-body-second-x: 50; + --left-body-second-y: 100; + --left-body-third-x: 0; + --left-body-third-y: 100; + --right-wing-background: var(--neutral-main); + --right-wing-first-x: 50; + --right-wing-first-y: 0; + --right-wing-second-x: 100; + --right-wing-second-y: 0; + --right-wing-third-x: 100; + --right-wing-third-y: 100; + --right-body-background: var(--neutral-main); + --right-body-first-x: 50; + --right-body-first-y: 0; + --right-body-second-x: 50; + --right-body-second-y: 100; + --right-body-third-x: 100; + --right-body-third-y: 100; + color: var(--white); + display: block; + min-width: 150px; + padding: 0.75rem 0; + position: relative; + -webkit-tap-highlight-color: transparent; + text-align: center; + transform: rotate(calc(var(--rotate) * 1deg)) translateZ(0); + } + + .contact-form__submit .plane__left-wing, + .contact-form__submit .plane__right-wing { + inset: 0; + opacity: var(--plane-opacity); + position: absolute; + transform: translate(calc(var(--plane-x) * 1px), calc(var(--plane-y) * 1px)) translateZ(0); + + &::after, + &::before { + background: var(--background, var(--left-wing-background)); + clip-path: polygon( + calc(var(--first-x, var(--left-wing-first-x)) * 1%) calc(var(--first-y, var(--left-wing-first-y)) * 1%), + calc(var(--second-x, var(--left-wing-second-x)) * 1%) + calc(var(--second-y, var(--left-wing-second-y)) * 1%), + calc(var(--third-x, var(--left-wing-third-x)) * 1%) calc(var(--third-y, var(--left-wing-third-y)) * 1%) + ); + content: ''; + inset: 0; + position: absolute; + transform: translate(var(--inner-x, 0.4%), var(--inner-y, 0)) translateZ(0); + z-index: var(--z-index, 2); + } + } + + .plane__left-wing:after { + --inner-x: 0; + --z-index: 1; + --background: var(--left-body-background); + --first-x: var(--left-body-first-x); + --first-y: var(--left-body-first-y); + --second-x: var(--left-body-second-x); + --second-y: var(--left-body-second-y); + --third-x: var(--left-body-third-x); + --third-y: var(--left-body-third-y); + } + + .plane__right-wing:before { + --inner-x: -0.4%; + --z-index: 2; + --background: var(--right-wing-background); + --first-x: var(--right-wing-first-x); + --first-y: var(--right-wing-first-y); + --second-x: var(--right-wing-second-x); + --second-y: var(--right-wing-second-y); + --third-x: var(--right-wing-third-x); + --third-y: var(--right-wing-third-y); + } + + .plane__right-wing:after { + --inner-x: 0; + --z-index: 1; + --background: var(--right-body-background); + --first-x: var(--right-body-first-x); + --first-y: var(--right-body-first-y); + --second-x: var(--right-body-second-x); + --second-y: var(--right-body-second-y); + --third-x: var(--right-body-third-x); + --third-y: var(--right-body-third-y); + } + + .contact-form__submit span { + display: block; + opacity: var(--text-opacity); + position: relative; + text-shadow: 0 0 0 var(--white); + z-index: 1; + } } diff --git a/src/ui/components/organisms/contactForm/utils/flyPlane/flyPlane.ts b/src/ui/components/organisms/contactForm/utils/flyPlane/flyPlane.ts new file mode 100644 index 00000000..efee6c0d --- /dev/null +++ b/src/ui/components/organisms/contactForm/utils/flyPlane/flyPlane.ts @@ -0,0 +1,93 @@ +import { gsap } from 'gsap'; + +export const flyPlane = (button: HTMLButtonElement) => { + if (!button.classList.contains('--is-active')) { + button.classList.add('--is-active'); + + const getPropertyValue = (variable: string) => window.getComputedStyle(button).getPropertyValue(variable); + + gsap.timeline().to(button, { + keyframes: [ + { + '--left-wing-first-x': 50, + '--left-wing-first-y': 100, + '--right-wing-second-x': 50, + '--right-wing-second-y': 100, + duration: 0.5, + onComplete: () => { + gsap.set(button, { + '--left-wing-first-y': 0, + '--left-wing-second-x': 40, + '--left-wing-second-y': 100, + '--left-wing-third-x': 0, + '--left-wing-third-y': 100, + '--left-body-third-x': 40, + '--right-wing-first-x': 50, + '--right-wing-first-y': 0, + '--right-wing-second-x': 60, + '--right-wing-second-y': 100, + '--right-wing-third-x': 100, + '--right-wing-third-y': 100, + '--right-body-third-x': 60, + }); + }, + }, + { + '--left-wing-third-x': 20, + '--left-wing-third-y': 90, + '--left-wing-second-y': 90, + '--left-body-third-y': 90, + '--right-wing-third-x': 80, + '--right-wing-third-y': 90, + '--right-body-third-y': 90, + '--right-wing-second-y': 90, + duration: 0.2, + }, + { + '--rotate': 50, + '--left-wing-third-y': 95, + '--left-wing-third-x': 27, + '--right-body-third-x': 45, + '--right-wing-second-x': 45, + '--right-wing-third-x': 60, + '--right-wing-third-y': 83, + duration: 0.25, + }, + { + '--rotate': 55, + '--plane-x': -8, + '--plane-y': 24, + duration: 0.2, + }, + { + '--rotate': 40, + '--plane-x': 45, + '--plane-y': -180, + '--plane-opacity': 0, + duration: 0.3, + }, + ], + }); + + gsap.to(button, { + keyframes: [ + { + '--text-opacity': 0, + '--left-wing-background': getPropertyValue('--primary-dark-2'), + '--right-wing-background': getPropertyValue('--primary-dark-2'), + duration: 0.2, + }, + { + '--left-wing-background': getPropertyValue('--neutral-main'), + '--right-wing-background': getPropertyValue('--neutral-main'), + duration: 0.1, + }, + { + '--left-body-background': getPropertyValue('--primary-dark-1'), + '--right-body-background': getPropertyValue('--primary-dark-2'), + duration: 0.4, + }, + ], + }); + } +}; diff --git a/src/ui/components/organisms/contactForm/utils/flyPlane/index.ts b/src/ui/components/organisms/contactForm/utils/flyPlane/index.ts new file mode 100644 index 00000000..b665ec29 --- /dev/null +++ b/src/ui/components/organisms/contactForm/utils/flyPlane/index.ts @@ -0,0 +1 @@ +export * from './flyPlane.ts'; diff --git a/src/ui/components/organisms/siteHead/SiteHead.astro b/src/ui/components/organisms/siteHead/SiteHead.astro index 07263f37..0616e4b8 100644 --- a/src/ui/components/organisms/siteHead/SiteHead.astro +++ b/src/ui/components/organisms/siteHead/SiteHead.astro @@ -39,8 +39,7 @@ const { title, description, image = '/blog-placeholder-1.jpg' } = Astro.props as +> diff --git a/src/ui/styles/base/base.css b/src/ui/styles/base/base.css index 94391724..0063e2f9 100644 --- a/src/ui/styles/base/base.css +++ b/src/ui/styles/base/base.css @@ -96,6 +96,12 @@ letter-spacing: 0.25rem; } + textarea { + @supports (form-sizing: content) { + form-sizing: content; + } + } + h1, h2, h3, diff --git a/src/ui/styles/global/variables.css b/src/ui/styles/global/variables.css index 94d33f5d..bd73b922 100644 --- a/src/ui/styles/global/variables.css +++ b/src/ui/styles/global/variables.css @@ -22,7 +22,6 @@ --white: oklch(100% 0 0); --black: oklch(0 0 0); --header-height: 80px; - --testimonial-translation: 4rem; --global-max-width: 1440px; --base-font-size: 16px; --base-line-height: calc(var(--base-font-size) * 1.25); @@ -175,12 +174,6 @@ initial-value: 80px; } -@property --testimonial-translation { - syntax: ''; - inherits: false; - initial-value: 4rem; -} - @property --global-max-width { syntax: ''; inherits: false; diff --git a/src/ui/styles/vendor/swiper.css b/src/ui/styles/vendor/swiper.css index ee5dc32d..f9569ecc 100644 --- a/src/ui/styles/vendor/swiper.css +++ b/src/ui/styles/vendor/swiper.css @@ -14,6 +14,8 @@ } .testimonials-initialized { + --testimonial-translation: 4rem; + .swiper-wrapper { align-items: center; } diff --git a/yarn.lock b/yarn.lock index 931d3a57..8adaa941 100644 --- a/yarn.lock +++ b/yarn.lock @@ -576,54 +576,54 @@ __metadata: languageName: node linkType: hard -"@commitlint/cli@npm:^19.0.2": - version: 19.0.2 - resolution: "@commitlint/cli@npm:19.0.2" - dependencies: - "@commitlint/format": "npm:^19.0.0" - "@commitlint/lint": "npm:^19.0.0" - "@commitlint/load": "npm:^19.0.2" - "@commitlint/read": "npm:^19.0.0" - "@commitlint/types": "npm:^19.0.0" +"@commitlint/cli@npm:^19.0.3": + version: 19.0.3 + resolution: "@commitlint/cli@npm:19.0.3" + dependencies: + "@commitlint/format": "npm:^19.0.3" + "@commitlint/lint": "npm:^19.0.3" + "@commitlint/load": "npm:^19.0.3" + "@commitlint/read": "npm:^19.0.3" + "@commitlint/types": "npm:^19.0.3" execa: "npm:^8.0.1" yargs: "npm:^17.0.0" bin: commitlint: cli.js - checksum: 0f88b2a68bce681c484720d177830f83e92759e56bc2d0792cde5bef5aa11c0e11cab4487dc79a520a6dfc7acf70cd76a818516dadc33d550994ef25bcd368bd + checksum: fb8f31ffc08e6c5313a70d1a355d949b8c05a8a35ae8d3c394f78c42038428bc3f1b1510cdcc2001fb054da35718e868f4e3e4348593deb6e7a3ba4924952f01 languageName: node linkType: hard -"@commitlint/config-conventional@npm:^18.6.2": - version: 18.6.2 - resolution: "@commitlint/config-conventional@npm:18.6.2" +"@commitlint/config-conventional@npm:^19.0.3": + version: 19.0.3 + resolution: "@commitlint/config-conventional@npm:19.0.3" dependencies: - "@commitlint/types": "npm:^18.6.1" + "@commitlint/types": "npm:^19.0.3" conventional-changelog-conventionalcommits: "npm:^7.0.2" - checksum: ff4ccff3c2992c209703eb7d08f8e1c6d8471d4f0778f384dc0fef490cc023227f1b662f7136a301804d650518e00c7f859aa3eb1a156448f837b2a50206430d + checksum: 3495238f6c5f7402055b104eea00e378701ac760452df8be4254269f49e406f74713f69022a9c912a85275d6cd050ff3bcd0066aea049841201f6bf98a87f0ff languageName: node linkType: hard -"@commitlint/config-validator@npm:^19.0.0": - version: 19.0.0 - resolution: "@commitlint/config-validator@npm:19.0.0" +"@commitlint/config-validator@npm:^19.0.3": + version: 19.0.3 + resolution: "@commitlint/config-validator@npm:19.0.3" dependencies: - "@commitlint/types": "npm:^19.0.0" + "@commitlint/types": "npm:^19.0.3" ajv: "npm:^8.11.0" - checksum: f5ddf1304a6d10a8e7a02d6d3447f2255004fd54a632aabe51bbbdc2d96dc299c0c043a476c08839b166e231ba07dc4f1f5d5f53d3b37253cae193bda9aac400 + checksum: 7a0d55837fb88b1f05892fed67a9582669331a452de96e4caec0c9a397cd6083701265b066e6e32a259b43737187cd31b15ab02b0459c817ea9e7b75602db3c7 languageName: node linkType: hard -"@commitlint/ensure@npm:^19.0.0": - version: 19.0.0 - resolution: "@commitlint/ensure@npm:19.0.0" +"@commitlint/ensure@npm:^19.0.3": + version: 19.0.3 + resolution: "@commitlint/ensure@npm:19.0.3" dependencies: - "@commitlint/types": "npm:^19.0.0" + "@commitlint/types": "npm:^19.0.3" lodash.camelcase: "npm:^4.3.0" lodash.kebabcase: "npm:^4.1.1" lodash.snakecase: "npm:^4.1.1" lodash.startcase: "npm:^4.4.0" lodash.upperfirst: "npm:^4.3.1" - checksum: 8ab2acdb4eaf2c55e54672819a558c70f0a8d434f7faf84ec0ffa0dbf3330972fa47f591ce53062db3e7762b6592ef292fc0007ba7e368f347518b81fb37ced2 + checksum: 66785aeddec70e26766f6bb11b1f78892cabdb97b0b77fb97ca6457578e663188903933d5f64559205dd54754e8c2c4a902e73e1749e34cbe07a4b296e374d72 languageName: node linkType: hard @@ -634,53 +634,53 @@ __metadata: languageName: node linkType: hard -"@commitlint/format@npm:^19.0.0": - version: 19.0.0 - resolution: "@commitlint/format@npm:19.0.0" +"@commitlint/format@npm:^19.0.3": + version: 19.0.3 + resolution: "@commitlint/format@npm:19.0.3" dependencies: - "@commitlint/types": "npm:^19.0.0" + "@commitlint/types": "npm:^19.0.3" chalk: "npm:^5.3.0" - checksum: 5a4912dddc830f9cac881970560eb3b9daed6c940f90ca44b0352271fedc5cd0ca5843c8dd7096ea67af4cdb250dc1237e079ee9a6347611f5c74631253378a8 + checksum: 9d8a5b55ca8e35351c6f1dbbec8f749fe3f7c66f01ba0e248574530fa1dac944b87ee5bd63153a14e3748068a2e9b0b8341cec21c768f384bb5a5c8124902a1f languageName: node linkType: hard -"@commitlint/is-ignored@npm:^19.0.0": - version: 19.0.0 - resolution: "@commitlint/is-ignored@npm:19.0.0" +"@commitlint/is-ignored@npm:^19.0.3": + version: 19.0.3 + resolution: "@commitlint/is-ignored@npm:19.0.3" dependencies: - "@commitlint/types": "npm:^19.0.0" + "@commitlint/types": "npm:^19.0.3" semver: "npm:^7.6.0" - checksum: 71682e3919f3b49828cde6646db8a51a44937fc3c18aea5ce0c01afd8747e4b56c97277ae29d03d4afe6ee6253d04c960a36b21d88bdd078057d980368709b02 + checksum: aa9d8d0db4625a0b631c8a811844ea90594764e5f7a1131d99a69dde743ef66ad0157d5f5df224bad645b5978c2c1e25ce0e22d9ade8c8e46a3577063d5bbe90 languageName: node linkType: hard -"@commitlint/lint@npm:^19.0.0": - version: 19.0.0 - resolution: "@commitlint/lint@npm:19.0.0" +"@commitlint/lint@npm:^19.0.3": + version: 19.0.3 + resolution: "@commitlint/lint@npm:19.0.3" dependencies: - "@commitlint/is-ignored": "npm:^19.0.0" - "@commitlint/parse": "npm:^19.0.0" - "@commitlint/rules": "npm:^19.0.0" - "@commitlint/types": "npm:^19.0.0" - checksum: 583cdf7eac85b0258a8a80f6a1b8eaf5a68c4de31a8dc7448d619f74a11f94ad74459155a04dfe5755c5cda057dea03c29ab24fdd7cff87f202631cf629dd87c + "@commitlint/is-ignored": "npm:^19.0.3" + "@commitlint/parse": "npm:^19.0.3" + "@commitlint/rules": "npm:^19.0.3" + "@commitlint/types": "npm:^19.0.3" + checksum: cb2830c1a19e2bc201c15a80ad875605431f4b75e4a9fe16de23eb5e1987d5b907337519214c17d3cb9f4955709f11b929070e433a5a401a33f9ec3e1f5a99e8 languageName: node linkType: hard -"@commitlint/load@npm:^19.0.2": - version: 19.0.2 - resolution: "@commitlint/load@npm:19.0.2" +"@commitlint/load@npm:^19.0.3": + version: 19.0.3 + resolution: "@commitlint/load@npm:19.0.3" dependencies: - "@commitlint/config-validator": "npm:^19.0.0" + "@commitlint/config-validator": "npm:^19.0.3" "@commitlint/execute-rule": "npm:^19.0.0" - "@commitlint/resolve-extends": "npm:^19.0.2" - "@commitlint/types": "npm:^19.0.0" + "@commitlint/resolve-extends": "npm:^19.0.3" + "@commitlint/types": "npm:^19.0.3" chalk: "npm:^5.3.0" cosmiconfig: "npm:^8.3.6" cosmiconfig-typescript-loader: "npm:^5.0.0" lodash.isplainobject: "npm:^4.0.6" lodash.merge: "npm:^4.6.2" lodash.uniq: "npm:^4.5.0" - checksum: 38042afeac5afd765a86a12c7a97f442e069c98ff65f02c0fc4587b9fef9b685e53b9ac194431bed63623abf773cebf9dec3079ae4ef29bc7128b727ea3bb42f + checksum: 88528e7d49fbc9dff6ea50ecba2358fc37f6a85024b357d143de8e50648c9814bd727554e060a6c9ab0a2f6818154cb2f38d262a3d66e0707e9b50a8a19a8abb languageName: node linkType: hard @@ -691,53 +691,53 @@ __metadata: languageName: node linkType: hard -"@commitlint/parse@npm:^19.0.0": - version: 19.0.0 - resolution: "@commitlint/parse@npm:19.0.0" +"@commitlint/parse@npm:^19.0.3": + version: 19.0.3 + resolution: "@commitlint/parse@npm:19.0.3" dependencies: - "@commitlint/types": "npm:^19.0.0" + "@commitlint/types": "npm:^19.0.3" conventional-changelog-angular: "npm:^7.0.0" conventional-commits-parser: "npm:^5.0.0" - checksum: 773d1d34bb1b09a046184cd92586547f44ccc55acc72066845cf77bd42fc692d969bff084797419bcf7b9e9c3b50e103c0a8fa92859125594df91b4c7109455d + checksum: ede8d5bfb37520337ea7836a68f280cdb4b9788d0586b8be676394b3dd8a7a9626391178c4f94d334c5b8d95ea75c73939c40c8c9d81c372cf7743f5bff3d0e1 languageName: node linkType: hard -"@commitlint/read@npm:^19.0.0": - version: 19.0.0 - resolution: "@commitlint/read@npm:19.0.0" +"@commitlint/read@npm:^19.0.3": + version: 19.0.3 + resolution: "@commitlint/read@npm:19.0.3" dependencies: "@commitlint/top-level": "npm:^19.0.0" - "@commitlint/types": "npm:^19.0.0" + "@commitlint/types": "npm:^19.0.3" git-raw-commits: "npm:^4.0.0" minimist: "npm:^1.2.8" - checksum: 0955a9a1e2b5e94c72ca22f81728eef12f3c99b27f1eabcd6c70f6c263f15d2a5f14daab84b5f19614af1a0a5224ee248017c6ea9386662ec1e494a6090750f7 + checksum: 0ad975acc672c661498a7327f937fd4ecf09f5ca9945682b15f14de1ab91a5e1b9877d15bd46423c1dd45d1b3c2f5cec749414fe01e48477056586276f933553 languageName: node linkType: hard -"@commitlint/resolve-extends@npm:^19.0.2": - version: 19.0.2 - resolution: "@commitlint/resolve-extends@npm:19.0.2" +"@commitlint/resolve-extends@npm:^19.0.3": + version: 19.0.3 + resolution: "@commitlint/resolve-extends@npm:19.0.3" dependencies: - "@commitlint/config-validator": "npm:^19.0.0" - "@commitlint/types": "npm:^19.0.0" + "@commitlint/config-validator": "npm:^19.0.3" + "@commitlint/types": "npm:^19.0.3" global-directory: "npm:^4.0.1" import-meta-resolve: "npm:^4.0.0" lodash.mergewith: "npm:^4.6.2" resolve-from: "npm:^5.0.0" - checksum: 160fb09f4800f6367ffa2597f1fc93a3de30c478a23f3c9b1e4890633316c51851859c332889ab228fe8520915fb07f822c8add0b5067e48b73f06cd665129de + checksum: 2b73d1f575c688fbabc1945322b3764ce51620ffcc6227c410050d41ce9c69e299fc408cc66c8df9b46eae1c572e551107def9de656234c4e3d70c9b34fc4747 languageName: node linkType: hard -"@commitlint/rules@npm:^19.0.0": - version: 19.0.0 - resolution: "@commitlint/rules@npm:19.0.0" +"@commitlint/rules@npm:^19.0.3": + version: 19.0.3 + resolution: "@commitlint/rules@npm:19.0.3" dependencies: - "@commitlint/ensure": "npm:^19.0.0" + "@commitlint/ensure": "npm:^19.0.3" "@commitlint/message": "npm:^19.0.0" "@commitlint/to-lines": "npm:^19.0.0" - "@commitlint/types": "npm:^19.0.0" + "@commitlint/types": "npm:^19.0.3" execa: "npm:^8.0.1" - checksum: 189610bc8bd1042430fba269c0a496ff4d6858510752007830275b86dc0c0e353a15e0e3760b17b54728ffcc91ee5d17aff68122582779b7c876ba2fc9730dea + checksum: 4a9a3f2fb838949707650a6bf2a016ec2b0ec570cb151d1005d01bdeb2e27adff5e5eab3c06a302c6834a88e2ec39090a5482bb57f2da51e6609c2b89e33d948 languageName: node linkType: hard @@ -757,21 +757,13 @@ __metadata: languageName: node linkType: hard -"@commitlint/types@npm:^18.6.1": - version: 18.6.1 - resolution: "@commitlint/types@npm:18.6.1" - dependencies: - chalk: "npm:^4.1.0" - checksum: 5728f5cb62bcaad5158dd8982ab5d44c1ea1aee9ac251026cd91b9a4795bb912505c904f75cbd3ae0d1bb7b4dd1e5d84990b76093230018166af8e111b658685 - languageName: node - linkType: hard - -"@commitlint/types@npm:^19.0.0": - version: 19.0.0 - resolution: "@commitlint/types@npm:19.0.0" +"@commitlint/types@npm:^19.0.3": + version: 19.0.3 + resolution: "@commitlint/types@npm:19.0.3" dependencies: + "@types/conventional-commits-parser": "npm:^5.0.0" chalk: "npm:^5.3.0" - checksum: fee7ab32b16e69d7e9ebbc54369cd0a11e4170adedfb8c23a45b89f38c2914d8fb3a5f7415e53666220c09ecb4c9a57fa0aeb10e63fca2e5094d590a4eebc50e + checksum: 279454409771097432cb3ecd4930b8f10e99e150b9306e931b69e4e80011a4251f326523bfaba59fcf9a9db7978c76073b7c7c07fbad6b90e045cb0fa2b70047 languageName: node linkType: hard @@ -1268,10 +1260,10 @@ __metadata: languageName: node linkType: hard -"@remix-run/router@npm:1.15.1": - version: 1.15.1 - resolution: "@remix-run/router@npm:1.15.1" - checksum: 2f84d998defe9943a40fd5bf8794ee6ede521116ff24275cc2294830adb039ef86e34dbdd6555300600016fd8a58a244d4f4df73ff0b2cec7bd749f63d172587 +"@remix-run/router@npm:1.15.2": + version: 1.15.2 + resolution: "@remix-run/router@npm:1.15.2" + checksum: 7bcad98a91e8a2e822f3776360d284bee48f9ba2d3b7ee2235f95b8701da2f06de3db880a205c4fd4e78c9198eaf6272229a2e66574a8cf563befd428fdefeee languageName: node linkType: hard @@ -1531,6 +1523,15 @@ __metadata: languageName: node linkType: hard +"@types/conventional-commits-parser@npm:^5.0.0": + version: 5.0.0 + resolution: "@types/conventional-commits-parser@npm:5.0.0" + dependencies: + "@types/node": "npm:*" + checksum: 16c748ce01cb3b3ea5947950acd695569c0daa8da62cc7e0eb98b15c4d7f812f95c079fe2c853325509f8aa73cfd388390319ae4621c8dfb21eeacb63accdb25 + languageName: node + linkType: hard + "@types/debug@npm:^4.0.0": version: 4.1.12 resolution: "@types/debug@npm:4.1.12" @@ -1540,13 +1541,13 @@ __metadata: languageName: node linkType: hard -"@types/eslint@npm:^8.56.3": - version: 8.56.3 - resolution: "@types/eslint@npm:8.56.3" +"@types/eslint@npm:^8.56.5": + version: 8.56.5 + resolution: "@types/eslint@npm:8.56.5" dependencies: "@types/estree": "npm:*" "@types/json-schema": "npm:*" - checksum: c5d81d0001fae211451b39d82b2bc8d7224b00d52a514954a33840a3665f36f3bde3be602eec6ad08d1fff59108052cd7746ced4237116bc3d8ac01a7cf5b5fe + checksum: 1d5d70ea107c63adfaf63020f85859c404f90c21ada2a655376b8e76109df354643797e30c7afc3b2de84797d9f5ce9f03f53a5d29a186706a44afd90f76597c languageName: node linkType: hard @@ -1654,12 +1655,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^20.11.20": - version: 20.11.20 - resolution: "@types/node@npm:20.11.20" +"@types/node@npm:^20.11.22": + version: 20.11.22 + resolution: "@types/node@npm:20.11.22" dependencies: undici-types: "npm:~5.26.4" - checksum: 8e8de211e6d54425c603388a9b5cc9c434101985d0a1c88aabbf65d10df2b1fccd71855c20e61ae8a75c7aea56cb0f64e722cf7914cff1247d0b62ce21996ac4 + checksum: 304a25607108cbc314417ba1cd0ca7061090cf9444c13f4a70c183164dc189d0e3f4cfda12619c85e5f0fc7a652e3b32501fd0e347b8425dbd5a66c3ec85c7a6 languageName: node linkType: hard @@ -1699,14 +1700,14 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:^18.2.58": - version: 18.2.58 - resolution: "@types/react@npm:18.2.58" +"@types/react@npm:^18.2.60": + version: 18.2.60 + resolution: "@types/react@npm:18.2.60" dependencies: "@types/prop-types": "npm:*" "@types/scheduler": "npm:*" csstype: "npm:^3.0.2" - checksum: 80145b707b780d682092b51d520f58a0171c4067ff36cf488d3346d92b715b27fd334acd0fabb8eb21a4eb6c4061f1535e8bfa6642a7f4025e63ebec868fb6d1 + checksum: e1d8763259c75ebcdf241dbbbfb7e8f606a8abdc98b1acf1a23e741681ebb20e82b490402a32ce10b81ce7e51f00f8009a162a72136333613b4f247549a3ab8d languageName: node linkType: hard @@ -1773,15 +1774,15 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^7.0.2": - version: 7.0.2 - resolution: "@typescript-eslint/eslint-plugin@npm:7.0.2" +"@typescript-eslint/eslint-plugin@npm:^7.1.0": + version: 7.1.0 + resolution: "@typescript-eslint/eslint-plugin@npm:7.1.0" dependencies: "@eslint-community/regexpp": "npm:^4.5.1" - "@typescript-eslint/scope-manager": "npm:7.0.2" - "@typescript-eslint/type-utils": "npm:7.0.2" - "@typescript-eslint/utils": "npm:7.0.2" - "@typescript-eslint/visitor-keys": "npm:7.0.2" + "@typescript-eslint/scope-manager": "npm:7.1.0" + "@typescript-eslint/type-utils": "npm:7.1.0" + "@typescript-eslint/utils": "npm:7.1.0" + "@typescript-eslint/visitor-keys": "npm:7.1.0" debug: "npm:^4.3.4" graphemer: "npm:^1.4.0" ignore: "npm:^5.2.4" @@ -1794,35 +1795,35 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 76727ad48f01c1bb4ef37690e7ed12754930ce3a4bbe5dcd52f24d42f4625fc0b151db8189947f3956b4a09a562eb2da683ff65b57a13a15426eee3b680f80a5 + checksum: e5644a987969cbb614bbf766b6bf51341e123c774953690548610147eae0041d70e48ef42be97b68a6e2f5ed9aae37fe040e8054d35bb0568c14194ba564b2d8 languageName: node linkType: hard -"@typescript-eslint/parser@npm:^7.0.2": - version: 7.0.2 - resolution: "@typescript-eslint/parser@npm:7.0.2" +"@typescript-eslint/parser@npm:^7.1.0": + version: 7.1.0 + resolution: "@typescript-eslint/parser@npm:7.1.0" dependencies: - "@typescript-eslint/scope-manager": "npm:7.0.2" - "@typescript-eslint/types": "npm:7.0.2" - "@typescript-eslint/typescript-estree": "npm:7.0.2" - "@typescript-eslint/visitor-keys": "npm:7.0.2" + "@typescript-eslint/scope-manager": "npm:7.1.0" + "@typescript-eslint/types": "npm:7.1.0" + "@typescript-eslint/typescript-estree": "npm:7.1.0" + "@typescript-eslint/visitor-keys": "npm:7.1.0" debug: "npm:^4.3.4" peerDependencies: eslint: ^8.56.0 peerDependenciesMeta: typescript: optional: true - checksum: acffdbea0bba24398ba8bd1ccf5b59438bc093e41d7a325019383094f39d676b5cf2f5963bfa5e332e54728e5b9e14be3984752ee91da6f0e1a3e0b613422d0e + checksum: 8fcbfc8c0c86abb750173096e7ca09e1cd44aba3f6115bdb94ffb6b409b86ee23526e9d5a44935b69a6be2385893e66d8e55d92063206028dc48f70d379afcab languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:7.0.2": - version: 7.0.2 - resolution: "@typescript-eslint/scope-manager@npm:7.0.2" +"@typescript-eslint/scope-manager@npm:7.1.0": + version: 7.1.0 + resolution: "@typescript-eslint/scope-manager@npm:7.1.0" dependencies: - "@typescript-eslint/types": "npm:7.0.2" - "@typescript-eslint/visitor-keys": "npm:7.0.2" - checksum: 60241a0dbed7605133b6242d7fc172e8ee649e1033b8a179cebe3e21c60e0c08c12679fd37644cfef57c95a5d75a3927afc9d6365a5f9684c1d043285db23c66 + "@typescript-eslint/types": "npm:7.1.0" + "@typescript-eslint/visitor-keys": "npm:7.1.0" + checksum: 2fd167730bbe984343ab94739b00bd82e8cdeea9e63674b099cc5c89b420b28dbf79f40dab48022dc717db8d14ae6ee2739e0fcbdcc0321bc9da5f2602b55788 languageName: node linkType: hard @@ -1836,12 +1837,12 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:7.0.2": - version: 7.0.2 - resolution: "@typescript-eslint/type-utils@npm:7.0.2" +"@typescript-eslint/type-utils@npm:7.1.0": + version: 7.1.0 + resolution: "@typescript-eslint/type-utils@npm:7.1.0" dependencies: - "@typescript-eslint/typescript-estree": "npm:7.0.2" - "@typescript-eslint/utils": "npm:7.0.2" + "@typescript-eslint/typescript-estree": "npm:7.1.0" + "@typescript-eslint/utils": "npm:7.1.0" debug: "npm:^4.3.4" ts-api-utils: "npm:^1.0.1" peerDependencies: @@ -1849,7 +1850,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: fa7957aa65cb0d7366c7c9be94e45cc2f1ebe9981cbf393054b505c6d555a01b2a2fe7cd1254d668f30183a275032f909186ce0b9f213f64b776bd7872144a6e + checksum: 3e3eea6c03692a643bf4ed11646b0679c6ff13baf1647d97e793f3d8c3adb83061e27a17c2a1470166a3c6c444b974bebc8096d36e0b4b3c36c289ff38bcfc9b languageName: node linkType: hard @@ -1860,19 +1861,19 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:7.0.2": - version: 7.0.2 - resolution: "@typescript-eslint/types@npm:7.0.2" - checksum: 5f95266cc2cd0e6cf1239dcd36b53c7d98b01ba12c61947316f0d879df87b912b4d23f0796324e2ab0fb8780503a338da41a4695fa91d90392b6c6aca5239fa7 +"@typescript-eslint/types@npm:7.1.0": + version: 7.1.0 + resolution: "@typescript-eslint/types@npm:7.1.0" + checksum: 095cde3e773b7605c5e0c86642002768ced09e94def7f3c6f49a67863f47d7c8ae15413a4ab1a2407f779d1b5ede5fb3000bc98b1cf9ed7ec938acc38cac89e7 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:7.0.2": - version: 7.0.2 - resolution: "@typescript-eslint/typescript-estree@npm:7.0.2" +"@typescript-eslint/typescript-estree@npm:7.1.0": + version: 7.1.0 + resolution: "@typescript-eslint/typescript-estree@npm:7.1.0" dependencies: - "@typescript-eslint/types": "npm:7.0.2" - "@typescript-eslint/visitor-keys": "npm:7.0.2" + "@typescript-eslint/types": "npm:7.1.0" + "@typescript-eslint/visitor-keys": "npm:7.1.0" debug: "npm:^4.3.4" globby: "npm:^11.1.0" is-glob: "npm:^4.0.3" @@ -1882,24 +1883,24 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 2f6795b05fced9f2e0887f6735aa1a0b20516952792e4be13cd94c5e56db8ad013ba27aeb56f89fedff8b7af587f854482f00aac75b418611c74e42169c29aeb + checksum: 063845dc8526dfda722d1b00960443a5158d1bce2bc39bf49bd353f33f42aa30116105a87b55a04df3eaef99c0d1c13fb987c53848dff43de6152c66dd3ba41c languageName: node linkType: hard -"@typescript-eslint/utils@npm:7.0.2": - version: 7.0.2 - resolution: "@typescript-eslint/utils@npm:7.0.2" +"@typescript-eslint/utils@npm:7.1.0": + version: 7.1.0 + resolution: "@typescript-eslint/utils@npm:7.1.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.4.0" "@types/json-schema": "npm:^7.0.12" "@types/semver": "npm:^7.5.0" - "@typescript-eslint/scope-manager": "npm:7.0.2" - "@typescript-eslint/types": "npm:7.0.2" - "@typescript-eslint/typescript-estree": "npm:7.0.2" + "@typescript-eslint/scope-manager": "npm:7.1.0" + "@typescript-eslint/types": "npm:7.1.0" + "@typescript-eslint/typescript-estree": "npm:7.1.0" semver: "npm:^7.5.4" peerDependencies: eslint: ^8.56.0 - checksum: b4ae9a36393c92b332e99d70219d1ee056271261f7433924db804e5f06d97ca60408b9c7a655afce8a851982e7153243a625d6cc76fea764f767f96c8f3e16da + checksum: 3fefd51307d0e294462106c57c4b12cd610bfe1bdcc5ca0142bfac6a5d0d37c18d14be5ec89740eb85515f5512f45219a6048df0efccd457e96f9d0612af4abf languageName: node linkType: hard @@ -1913,13 +1914,13 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:7.0.2": - version: 7.0.2 - resolution: "@typescript-eslint/visitor-keys@npm:7.0.2" +"@typescript-eslint/visitor-keys@npm:7.1.0": + version: 7.1.0 + resolution: "@typescript-eslint/visitor-keys@npm:7.1.0" dependencies: - "@typescript-eslint/types": "npm:7.0.2" + "@typescript-eslint/types": "npm:7.1.0" eslint-visitor-keys: "npm:^3.4.1" - checksum: 4146d1ad6ce9374e6b5a75677fc709816bdc5fe324b1a857405f21dad23bb28c79cfd0555bc2a01c4af1d9e9ee81ff5e29ec41cc9d05b0b1101cc4264e7f21d1 + checksum: 9015a10e6ee2a99fc99e0f7a3f274496a813c2c239e868f29e7c0da919c825fe192fe21d3410c43d8a801e8186b51f08ef06523d2c3010570d893a1486ac293d languageName: node linkType: hard @@ -2360,9 +2361,9 @@ __metadata: languageName: node linkType: hard -"astro@npm:^4.4.4": - version: 4.4.4 - resolution: "astro@npm:4.4.4" +"astro@npm:^4.4.6": + version: 4.4.6 + resolution: "astro@npm:4.4.6" dependencies: "@astrojs/compiler": "npm:^2.5.3" "@astrojs/internal-helpers": "npm:0.2.1" @@ -2434,7 +2435,7 @@ __metadata: optional: true bin: astro: astro.js - checksum: 880a3d424138d7ca898d44942aafdcf04147735adf18ae25527e9e906704a0ff5d106f30595707baa3ae72c15aa3ffedd0cca2b91659e40743e5249e6299b9e4 + checksum: 22f7274ef31027231a44d8b251611b3f1971108e2436894394c2e912140f9b6a7239e37bedafe6bbf58adb19b5e60c191b6c04e6111d32449bca2da1ea77af23 languageName: node linkType: hard @@ -2542,22 +2543,22 @@ __metadata: "@astrojs/react": "npm:^3.0.10" "@astrojs/rss": "npm:^4.0.5" "@astrojs/sitemap": "npm:^3.1.1" - "@commitlint/cli": "npm:^19.0.2" - "@commitlint/config-conventional": "npm:^18.6.2" + "@commitlint/cli": "npm:^19.0.3" + "@commitlint/config-conventional": "npm:^19.0.3" "@fontsource-variable/nunito-sans": "npm:^5.0.9" "@fontsource/baskervville": "npm:^5.0.18" "@hookform/resolvers": "npm:^3.3.4" "@testing-library/react": "npm:^14.2.1" "@testing-library/react-hooks": "npm:^8.0.1" - "@types/eslint": "npm:^8.56.3" + "@types/eslint": "npm:^8.56.5" "@types/markdown-it": "npm:^13.0.7" - "@types/node": "npm:^20.11.20" - "@types/react": "npm:^18.2.58" + "@types/node": "npm:^20.11.22" + "@types/react": "npm:^18.2.60" "@types/react-dom": "npm:^18.2.19" "@types/three": "npm:^0.161.2" - "@typescript-eslint/eslint-plugin": "npm:^7.0.2" - "@typescript-eslint/parser": "npm:^7.0.2" - astro: "npm:^4.4.4" + "@typescript-eslint/eslint-plugin": "npm:^7.1.0" + "@typescript-eslint/parser": "npm:^7.1.0" + astro: "npm:^4.4.6" eslint: "npm:^8.57.0" eslint-config-prettier: "npm:^9.1.0" eslint-plugin-astro: "npm:^0.31.4" @@ -2577,11 +2578,11 @@ __metadata: react-globe.gl: "npm:^2.27.2" react-google-recaptcha-v3: "npm:^1.10.1" react-hook-form: "npm:^7.50.1" - react-router-dom: "npm:^6.22.1" + react-router-dom: "npm:^6.22.2" stylelint: "npm:^16.2.1" stylelint-config-recommended: "npm:^14.0.0" stylelint-order: "npm:^6.0.4" - swiper: "npm:^11.0.6" + swiper: "npm:^11.0.7" three: "npm:^0.161.0" typescript: "npm:^5.3.3" vitest: "npm:^1.3.1" @@ -8258,27 +8259,27 @@ __metadata: languageName: node linkType: hard -"react-router-dom@npm:^6.22.1": - version: 6.22.1 - resolution: "react-router-dom@npm:6.22.1" +"react-router-dom@npm:^6.22.2": + version: 6.22.2 + resolution: "react-router-dom@npm:6.22.2" dependencies: - "@remix-run/router": "npm:1.15.1" - react-router: "npm:6.22.1" + "@remix-run/router": "npm:1.15.2" + react-router: "npm:6.22.2" peerDependencies: react: ">=16.8" react-dom: ">=16.8" - checksum: 1e6ec4596f134204934d4f701b8acc426867532342c8aec1b5c4ffeaf23afa0099727f58ab8687f7838db069616b8d6ed05a065570f23b3b60cbff405b3fbccd + checksum: 5dc5a54a72b0470cce571f95021516f1afbe978f9b5103a0f7de9e8585d2f5f8d084f810f3eb648b9701a941a17f3a68517b07a4827dfc4bdb5f0ff0c18920a8 languageName: node linkType: hard -"react-router@npm:6.22.1": - version: 6.22.1 - resolution: "react-router@npm:6.22.1" +"react-router@npm:6.22.2": + version: 6.22.2 + resolution: "react-router@npm:6.22.2" dependencies: - "@remix-run/router": "npm:1.15.1" + "@remix-run/router": "npm:1.15.2" peerDependencies: react: ">=16.8" - checksum: bb33c3a6457e73fa9977133be0c27b60accfc6452cc5d7b62c729cdd2d091a1345a9567cf852c651315548f1f16adac258eeab8ad193b46e4ce926c911dc857c + checksum: e0a0d1a0c8566b377cda632691a7c39d4009cbc8fced4fe06f13789a8acc38c474a366984b536b109e3685f3d7e1f839d6bec7b28fb96d311d86d02fc8999379 languageName: node linkType: hard @@ -9472,10 +9473,10 @@ __metadata: languageName: node linkType: hard -"swiper@npm:^11.0.6": - version: 11.0.6 - resolution: "swiper@npm:11.0.6" - checksum: efdf2a207fb4534aced2db42c14b249eebba76ad497e14d6bd0a07019e2afe2509e02602e2e51167b362f65e27e4ab9c4f86e23764dbeba341745549a6f28ff3 +"swiper@npm:^11.0.7": + version: 11.0.7 + resolution: "swiper@npm:11.0.7" + checksum: d27b8c3b5deccde730317c2fe868350fad039e9776c8c6dfd11a89d9e732a66c1292292ca635141a7e0bbb363fcac1291c9fd716bf7a8e3b85d320e58ff94eba languageName: node linkType: hard