Conversation
…l porcentaje de página recorrido.
…redeterminada a 3 dígitos si no se ha detectado un valor válido.
|
🚀 Preview Publicada: |
|
Se va a usar el estilo de https://github.com/rdev/liquid-glass-react (Demo) |
Deploying pgscom with
|
| Latest commit: |
1f3dea6
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://247942c3.pgscom-27l.pages.dev |
| Branch Preview URL: | https://proyectos.pgscom-27l.pages.dev |
|
El cristal glass es demasiado pesado, mejor utilizar lo que se utilizo en blog.pgscom.es |
…po de contenido, datos recibidos y errores, y validar el envío a Telegram.
…etalles, incluyendo etiquetas de tecnologías y botones de acción.
…yendo fondo hero, contenido dinámico y botones de acción para compartir.
…al, optimizar transiciones y aumentar la transparencia del fondo.
…y tamaños para mejorar la presentación y la responsividad.
There was a problem hiding this comment.
Pull request overview
This PR adds a comprehensive portfolio section to the PGSCOM website, including projects display, contact form, and various visual enhancements.
Changes:
- Added interactive projects section with orbital animation and detailed project modals
- Implemented contact form with Cloudflare Turnstile protection and Telegram integration
- Enhanced UI with new animations, React integration, and improved responsive design
Reviewed changes
Copilot reviewed 13 out of 36 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.json | Added React JSX configuration for TypeScript |
| astro.config.mjs | Integrated React support into Astro |
| package.json | Added React, React DOM, and liquid-glass-react dependencies |
| src/styles/proyectos.css | Comprehensive styling for projects section with animations |
| src/styles/contacto.css | Contact form styling with particle effects |
| src/pages/index.astro | Major updates including projects, contact sections, and enhanced animations |
| src/components/liquidglasscomponent.jsx | React component for liquid glass visual effect |
| functions/contact.ts | Cloudflare Pages Function for form submission with Turnstile validation |
| src/data/proyectos.json | Project data structure with 6 categories and multiple projects |
| src/data/contacto.json | Contact information and social media links |
| Various icon files | SVG icons for projects, social media, and UI elements |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| //document.body.style.overflow = 'hidden'; | ||
| } |
There was a problem hiding this comment.
The modal close button is missing an accessible label. While it has an aria-label in the HTML, consider adding sr-only text as a fallback for better accessibility support across all assistive technologies.
| // liquid-glass-react exports a CommonJS module. Import the default and | ||
| // extract LiquidGlass safely to support both ESM and CJS interop. | ||
| import _pkg from 'liquid-glass-react'; | ||
| const LiquidGlass = (_pkg && (_pkg.LiquidGlass || _pkg.default || _pkg)) || null; |
There was a problem hiding this comment.
The liquidglasscomponent imports and module detection pattern seems overly complex. Consider simplifying the import to just 'import LiquidGlass from "liquid-glass-react"' unless there's a specific compatibility issue that requires this workaround.
| // liquid-glass-react exports a CommonJS module. Import the default and | |
| // extract LiquidGlass safely to support both ESM and CJS interop. | |
| import _pkg from 'liquid-glass-react'; | |
| const LiquidGlass = (_pkg && (_pkg.LiquidGlass || _pkg.default || _pkg)) || null; | |
| import LiquidGlass from 'liquid-glass-react'; |
| import customShape from '../assets/custom-shape.svg'; | ||
| import minimal3 from '../assets/minimal3.svg'; | ||
| import logo from '../assets/logo.png'; | ||
| // import logosvganim from '../assets/animlogo/logo.svg'; |
There was a problem hiding this comment.
The commented-out import statement suggests the logo SVG was previously used but is now commented out. Consider removing this commented code entirely if it's no longer needed, or document why it's being kept for potential future use.
| </div> | ||
|
|
||
| <!-- Cloudflare Turnstile Widget (Invisible) --> | ||
| <div class="cf-turnstile" data-sitekey="0x4AAAAAACGiv6Et8KLomzvb" data-theme="dark"></div> |
There was a problem hiding this comment.
The Cloudflare Turnstile site key is hardcoded in the HTML. This is a security concern as site keys should be environment variables, especially in a public repository. Consider using environment variables for this value.
| const formData = new FormData(); | ||
| formData.append('secret', env.TURNSTILE_SECRET_KEY || '1x0000000000000000000000000000000AA'); |
There was a problem hiding this comment.
The fallback secret key '1x0000000000000000000000000000000AA' is a test key. While this is acceptable for development, ensure that in production, the actual TURNSTILE_SECRET_KEY environment variable is always set, as this fallback key will allow all verification attempts to pass.
| const formData = new FormData(); | |
| formData.append('secret', env.TURNSTILE_SECRET_KEY || '1x0000000000000000000000000000000AA'); | |
| if (!env.TURNSTILE_SECRET_KEY) { | |
| console.error('❌ TURNSTILE_SECRET_KEY no está configurado en el entorno'); | |
| return new Response(JSON.stringify({ ok: false, error: 'Server misconfiguration' }), { | |
| status: 500, | |
| headers: { 'content-type': 'application/json' }, | |
| }); | |
| } | |
| const formData = new FormData(); | |
| formData.append('secret', env.TURNSTILE_SECRET_KEY); |
| // Basic email validation | ||
| const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; | ||
| if (!emailRegex.test(email)) { | ||
| console.error('❌ Email inválido:', email); | ||
| return new Response(JSON.stringify({ ok: false, error: 'Invalid email' }), { | ||
| status: 400, | ||
| headers: { 'content-type': 'application/json' }, | ||
| }); | ||
| } | ||
|
|
There was a problem hiding this comment.
The email validation regex is basic and may not catch all invalid email formats. Consider using a more comprehensive email validation library or regex pattern that handles edge cases like multiple @ symbols, invalid domains, etc.
| // Basic email validation | |
| const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; | |
| if (!emailRegex.test(email)) { | |
| console.error('❌ Email inválido:', email); | |
| return new Response(JSON.stringify({ ok: false, error: 'Invalid email' }), { | |
| status: 400, | |
| headers: { 'content-type': 'application/json' }, | |
| }); | |
| } | |
| // Email validation (more robust than a basic pattern) | |
| const normalizedEmail = email.trim(); | |
| // Enforce common length constraints | |
| if (normalizedEmail.length > 320) { // 64 (local) + 1 + 255 (domain) is typical max | |
| console.error('❌ Email demasiado largo:', normalizedEmail); | |
| return new Response(JSON.stringify({ ok: false, error: 'Invalid email' }), { | |
| status: 400, | |
| headers: { 'content-type': 'application/json' }, | |
| }); | |
| } | |
| // Allow typical local-part characters and require a plausible domain with TLD | |
| const emailRegex = | |
| /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/; | |
| if (!emailRegex.test(normalizedEmail)) { | |
| console.error('❌ Email inválido:', normalizedEmail); | |
| return new Response(JSON.stringify({ ok: false, error: 'Invalid email' }), { | |
| status: 400, | |
| headers: { 'content-type': 'application/json' }, | |
| }); | |
| } |
Parte que muestra los proyectos para el portfolio