From 1afa2f3cd877d9bcc66067aa241e8f557c1d5632 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 28 Jan 2026 01:56:37 +0000 Subject: [PATCH 1/5] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[HIGH]?= =?UTF-8?q?=20Add=20HSTS=20and=20Permissions-Policy=20headers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added Strict-Transport-Security (HSTS) and Permissions-Policy headers to firebase.json to improve security posture. - HSTS ensures browsers only connect via HTTPS for 1 year. - Permissions-Policy restricts usage of sensitive features (camera, mic, geolocation). Co-authored-by: ragusa-it <196988693+ragusa-it@users.noreply.github.com> --- firebase.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/firebase.json b/firebase.json index 50e9a41..1fc4858 100644 --- a/firebase.json +++ b/firebase.json @@ -24,6 +24,14 @@ "key": "X-Frame-Options", "value": "DENY" }, + { + "key": "Strict-Transport-Security", + "value": "max-age=31536000; includeSubDomains" + }, + { + "key": "Permissions-Policy", + "value": "camera=(), microphone=(), geolocation=()" + }, { "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" From 669e96a77ca1ae2a0738153f2d61b17969ce5cee Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 28 Jan 2026 01:58:55 +0000 Subject: [PATCH 2/5] feat: optimize Hero component by isolating typing effect state Extracted the high-frequency typing animation logic into a new, memoized `TypedText` component. This prevents the entire `Hero` component (including the heavy `GradientBlinds`) from re-rendering on every character update. - Created `TypedText` component in `Hero.tsx` - Wrapped `TypedText` in `React.memo` - Moved `useTypingEffect` call into `TypedText` - Updated `Hero` to use `TypedText` Co-authored-by: ragusa-it <196988693+ragusa-it@users.noreply.github.com> --- .jules/bolt.md | 4 ++++ src/components/sections/Hero.tsx | 26 +++++++++++++++++--------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index a7efe75..8242db8 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -1,3 +1,7 @@ ## 2024-05-22 - Missing Scripts and Environment **Learning:** The project lacks `lint` script in `package.json`. Running `pnpm lint` might invoke system tools (like Android Lint?) instead of failing or doing nothing useful. Always check `package.json` scripts first. **Action:** Use specific commands like `pnpm exec tsc --noEmit` or `npx vitest` as discovered/documented, rather than assuming standard scripts exist. + +## 2024-05-22 - High-Frequency State Isolation +**Learning:** High-frequency state updates (like typing effects) in large parent components (`Hero`) trigger massive unnecessary re-renders of expensive sub-trees (`GradientBlinds`, `Button`). +**Action:** Isolate high-frequency state into small, leaf-node components (e.g., `TypedText`) and wrap them in `React.memo` if necessary, keeping the heavy parent static. diff --git a/src/components/sections/Hero.tsx b/src/components/sections/Hero.tsx index b2c0d21..e9ef169 100644 --- a/src/components/sections/Hero.tsx +++ b/src/components/sections/Hero.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect, useRef } from "react"; +import { useState, useEffect, useRef, memo } from "react"; import { Link } from "react-router-dom"; import { motion } from "motion/react"; import { useTranslation } from "../../i18n"; @@ -9,6 +9,21 @@ import styles from "./Hero.module.css"; const GRADIENT_COLORS = ["#26a269", "#8ff0a4"]; +interface TypedTextProps { + words: string[]; +} + +const TypedText = memo(({ words }: TypedTextProps) => { + const { text } = useTypingEffect({ + words, + typingSpeed: 80, + deletingSpeed: 40, + pauseDuration: 2500, + }); + + return <>{text}; +}); + export function Hero() { const { t } = useTranslation(); const [showScrollIndicator, setShowScrollIndicator] = useState(true); @@ -29,13 +44,6 @@ export function Hero() { return () => observer.disconnect(); }, []); - const { text } = useTypingEffect({ - words: t.hero.rotatingWords, - typingSpeed: 80, - deletingSpeed: 40, - pauseDuration: 2500, - }); - return (
{t.hero.tagline} - {text} + | From e14ce38f615faab9715ad27d3c4cd861cf688196 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 28 Jan 2026 02:10:17 +0000 Subject: [PATCH 3/5] feat: add accessible required field indicators and alerts - Add visual asterisk for required inputs in Input.tsx - Add .required style in Input.module.css - Update Contact form to use required props and noValidate - Add role="alert" to Contact form success/error messages - Add tests for required field rendering Co-authored-by: ragusa-it <196988693+ragusa-it@users.noreply.github.com> --- .jules/palette.md | 3 +++ src/components/ui/Input.module.css | 5 +++++ src/components/ui/Input.tsx | 10 +++++++++ src/components/ui/__tests__/Input.test.tsx | 24 ++++++++++++++++++++++ src/pages/Contact.tsx | 14 ++++++++++++- 5 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 .jules/palette.md diff --git a/.jules/palette.md b/.jules/palette.md new file mode 100644 index 0000000..8c4d7fb --- /dev/null +++ b/.jules/palette.md @@ -0,0 +1,3 @@ +## 2024-05-22 - Semantic Required Fields with Custom Validation +**Learning:** To combine custom validation UI with semantic `required` attributes (vital for a11y), add `noValidate` to the `
`. This prevents native browser bubbles while keeping the accessibility benefits. +**Action:** Use `noValidate` on forms when implementing custom validation but keep `required` attributes on inputs. diff --git a/src/components/ui/Input.module.css b/src/components/ui/Input.module.css index 6cb7aa9..3acc481 100644 --- a/src/components/ui/Input.module.css +++ b/src/components/ui/Input.module.css @@ -10,6 +10,11 @@ color: var(--md-sys-color-on-surface); } +.required { + color: var(--md-sys-color-error); + margin-left: 0.25rem; +} + .input { padding: var(--space-md); font-family: var(--md-sys-typescale-body-font); diff --git a/src/components/ui/Input.tsx b/src/components/ui/Input.tsx index b3d0c24..185bfbe 100644 --- a/src/components/ui/Input.tsx +++ b/src/components/ui/Input.tsx @@ -15,6 +15,11 @@ export const Input = forwardRef(
(