-
Notifications
You must be signed in to change notification settings - Fork 0
Fix pages build: restore missing files dropped in merge #196
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,125 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useCallback } from "react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useReducedMotion } from "framer-motion"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| interface AnimatedScrollOptions { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Duration of the fade animation in milliseconds | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @default 400 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| duration?: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Offset to apply to the final scroll position (useful for sticky headers) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @default 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| offset?: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Custom hook that provides animated scrolling with fade effects | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * to make content appear to "come to you" without showing the scroll journey | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export function useAnimatedScroll(options: AnimatedScrollOptions = {}) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { duration = 400, offset = 0 } = options; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const prefersReducedMotion = useReducedMotion(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const scrollToElement = useCallback( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (targetId: string) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const element = document.getElementById(targetId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!element) return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // For reduced motion, use instant browser scroll | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (prefersReducedMotion) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| element.scrollIntoView({ behavior: "auto", block: "start" }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const main = document.querySelector("main"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!main) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| element.scrollIntoView({ behavior: "auto", block: "start" }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const targetPosition = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| element.getBoundingClientRect().top + window.scrollY + offset; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+30
to
+44
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // For reduced motion, use instant browser scroll | |
| if (prefersReducedMotion) { | |
| element.scrollIntoView({ behavior: "auto", block: "start" }); | |
| return; | |
| } | |
| const main = document.querySelector("main"); | |
| if (!main) { | |
| element.scrollIntoView({ behavior: "auto", block: "start" }); | |
| return; | |
| } | |
| const targetPosition = | |
| element.getBoundingClientRect().top + window.scrollY + offset; | |
| const targetPosition = | |
| element.getBoundingClientRect().top + window.scrollY + offset; | |
| // For reduced motion, use instant browser scroll while still respecting offset | |
| if (prefersReducedMotion) { | |
| window.scrollTo({ top: targetPosition, behavior: "auto" }); | |
| return; | |
| } | |
| const main = document.querySelector("main"); | |
| if (!main) { | |
| window.scrollTo({ top: targetPosition, behavior: "auto" }); | |
| return; | |
| } |
Copilot
AI
Mar 26, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There’s a "Trigger reflow" comment followed by an eslint-disable-next-line @typescript-eslint/no-unused-expressions, but no statement on the next line. This is misleading and makes it unclear whether a reflow was intended; either add the actual reflow trigger (e.g., by reading a layout property) or remove the comment/disable directive.
Copilot
AI
Mar 26, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above in scrollToTop: the reflow comment and eslint-disable-next-line directive aren’t followed by any statement. This should either perform the intended reflow or be removed to avoid dead/misleading lint directives.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| import { useEffect } from "react"; | ||
|
|
||
| /** | ||
| * Custom hook to lock/unlock body scroll | ||
| * @param isLocked - Whether the body scroll should be locked | ||
| */ | ||
| export function useBodyScrollLock(isLocked: boolean) { | ||
| useEffect(() => { | ||
| // Early return if not in browser environment | ||
| if (globalThis.window === undefined || typeof document === "undefined") { | ||
| return undefined; | ||
| } | ||
|
|
||
| if (!isLocked) return undefined; | ||
|
|
||
| // Store original body overflow and padding | ||
| const originalOverflow = document.body.style.overflow; | ||
| const originalPaddingRight = document.body.style.paddingRight; | ||
|
|
||
| // Get scrollbar width to prevent layout shift | ||
| const scrollbarWidth = | ||
| globalThis.window.innerWidth - document.documentElement.clientWidth; | ||
|
|
||
| // Lock scroll | ||
| document.body.style.overflow = "hidden"; | ||
|
|
||
| // Add padding to compensate for scrollbar disappearance | ||
| if (scrollbarWidth > 0) { | ||
| // Get computed padding in pixels | ||
| const computedStyle = globalThis.window.getComputedStyle(document.body); | ||
| const currentPadding = Number.parseFloat(computedStyle.paddingRight) || 0; | ||
| document.body.style.paddingRight = `${currentPadding + scrollbarWidth}px`; | ||
| } | ||
|
|
||
| // Cleanup function to restore original state | ||
| return () => { | ||
| // Restore or remove overflow property | ||
| if (originalOverflow) { | ||
| document.body.style.overflow = originalOverflow; | ||
| } else { | ||
| document.body.style.removeProperty("overflow"); | ||
| } | ||
|
|
||
| // Restore or remove padding-right property | ||
| if (originalPaddingRight) { | ||
| document.body.style.paddingRight = originalPaddingRight; | ||
| } else { | ||
| document.body.style.removeProperty("padding-right"); | ||
| } | ||
| }; | ||
| }, [isLocked]); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| { | ||
| "nav": { | ||
| "home": "Inici", | ||
| "about": "Jo", | ||
| "experience": "Feina", | ||
| "education": "Educació", | ||
| "certifications": "Llicència", | ||
| "projects": "Afició", | ||
| "skills": "Habilitats", | ||
| "contact": "Contacte" | ||
| }, | ||
| "hero": { | ||
| "greeting": "Hola, sóc", | ||
| "name": "Kiya Rose", | ||
| "wave": "👋", | ||
| "headline": "Treballadors de TI aprenent suport sanitari", | ||
| "description": "Dedico el meu temps lliure a construir projectes de codi mentre em preparo per ajudar equips a temps complet en TI de salut i suport tècnic." | ||
| }, | ||
| "about": { | ||
| "title": "Sobre mi", | ||
| "eyebrow": "Perfil", | ||
| "description": "Sóc un professional de TI que busca adquirir experiència en administració d'oficines mentre persegueixo el meu Certificat de Facturació i Codificació. M'encanten els jocs d'un sol jugador amb història i pensar massa. També m'agrada escriure de tant en tant :3" | ||
| }, | ||
| "experience": { | ||
| "title": "Experiència", | ||
| "eyebrow": "Trajectòria Professional" | ||
| }, | ||
| "education": { | ||
| "title": "Educació", | ||
| "eyebrow": "Formació Acadèmica" | ||
| }, | ||
| "certifications": { | ||
| "title": "Certificacions", | ||
| "eyebrow": "Credencials Professionals" | ||
| }, | ||
| "projects": { | ||
| "title": "Projectes Personals", | ||
| "eyebrow": "Projectes Personals" | ||
| }, | ||
| "skills": { | ||
| "title": "Habilitats", | ||
| "eyebrow": "Capacitats Tècniques" | ||
| }, | ||
| "contact": { | ||
| "title": "Contacte", | ||
| "eyebrow": "Posa't en Contacte" | ||
| }, | ||
| "theme": { | ||
| "darkMode": "Mode fosc", | ||
| "lightMode": "Mode clar" | ||
| }, | ||
| "language": { | ||
| "select": "Idioma" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| { | ||
| "nav": { | ||
| "home": "Accueil", | ||
| "about": "Moi", | ||
| "experience": "Expérience", | ||
| "education": "Éducation", | ||
| "certifications": "Certifications", | ||
| "projects": "Passe-temps", | ||
| "skills": "Capacités", | ||
| "contact": "Courrier" | ||
| }, | ||
| "hero": { | ||
| "greeting": "Bonjour, je suis", | ||
| "name": "Kiya Rose", | ||
| "wave": "👋", | ||
| "headline": "Professionnelle en Formation en TI Santé et Support", | ||
| "description": "Je passe mon temps libre à créer des projets de code tout en me préparant à aider des équipes à temps plein dans les domaines de la TI santé et du support technique." | ||
| }, | ||
| "about": { | ||
| "title": "À propos", | ||
| "eyebrow": "Profil", | ||
| "description": "Je suis une professionnelle en TI cherchant à acquérir de l'expérience en administration de bureau tout en poursuivant mon Certificat de Facturation et Codage. J'adore les jeux solo avec une histoire et réfléchir trop. J'aime aussi écrire de temps en temps :3" | ||
| }, | ||
| "experience": { | ||
| "title": "Expérience", | ||
| "eyebrow": "Parcours Professionnel" | ||
| }, | ||
| "education": { | ||
| "title": "Éducation", | ||
| "eyebrow": "Formation Académique" | ||
| }, | ||
| "certifications": { | ||
| "title": "Certifications", | ||
| "eyebrow": "Accréditations Professionnelles" | ||
| }, | ||
| "projects": { | ||
| "title": "Projets Personnels", | ||
| "eyebrow": "Projets Personnels" | ||
| }, | ||
| "skills": { | ||
| "title": "Compétences", | ||
| "eyebrow": "Capacités Techniques" | ||
| }, | ||
| "contact": { | ||
| "title": "Contact", | ||
| "eyebrow": "Entrer en Contact" | ||
| }, | ||
| "theme": { | ||
| "darkMode": "Mode sombre", | ||
| "lightMode": "Mode clair" | ||
| }, | ||
| "language": { | ||
| "select": "Langue" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| { | ||
| "nav": { | ||
| "home": "ホーム", | ||
| "about": "プロフ", | ||
| "experience": "経験", | ||
| "education": "学", | ||
| "certifications": "資格", | ||
| "projects": "趣味のプロジ", | ||
| "skills": "スキル", | ||
| "contact": "お問" | ||
| }, | ||
| "hero": { | ||
| "greeting": "こんにちは、私は", | ||
| "name": "Kiya Rose", | ||
| "wave": "👋", | ||
| "headline": "ヘルスケアIT&サポート専門家トレーニング中", | ||
| "description": "ヘルスケアITとテクニカルサポートでフルタイムでチームを支援する準備をしながら、自由時間にコードプロジェクトを構築しています。" | ||
| }, | ||
| "about": { | ||
| "title": "プロフィール", | ||
| "eyebrow": "プロフィール", | ||
| "description": "私は請求とコーディングの資格取得を目指しながら、オフィス管理の経験を積もうとしているIT専門家です。シングルプレイヤーのストーリーゲームと考えすぎることが大好きです。時々書くことも好きです :3" | ||
| }, | ||
| "experience": { | ||
| "title": "経験", | ||
| "eyebrow": "職業の歩み" | ||
| }, | ||
| "education": { | ||
| "title": "学歴", | ||
| "eyebrow": "学術的背景" | ||
| }, | ||
| "certifications": { | ||
| "title": "資格", | ||
| "eyebrow": "専門資格" | ||
| }, | ||
| "projects": { | ||
| "title": "趣味のプロジェクト", | ||
| "eyebrow": "個人プロジェクト" | ||
| }, | ||
| "skills": { | ||
| "title": "スキル", | ||
| "eyebrow": "技術的能力" | ||
| }, | ||
| "contact": { | ||
| "title": "お問い合わせ", | ||
| "eyebrow": "連絡する" | ||
| }, | ||
| "theme": { | ||
| "darkMode": "ダーク", | ||
| "lightMode": "ライト" | ||
| }, | ||
| "language": { | ||
| "select": "言語" | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor consistency: most components in this repo coerce
useReducedMotion()to a strict boolean viauseReducedMotion() ?? false(e.g.src/components/ScrollSpy.tsx:24). Here it’s assigned directly, so the type/behaviour may differ from the rest of the codebase depending on framer-motion’s return value. Consider matching the existing pattern for consistency.