diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index c20b5f5..5029acf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,10 +10,12 @@ "dependencies": { "@astrojs/react": "^4.2.7", "@astrojs/tailwind": "^6.0.2", + "@nanostores/react": "^1.0.0", "@tailwindcss/vite": "^4.1.6", "@types/react": "^19.1.3", "@types/react-dom": "^19.1.3", "astro": "^5.7.12", + "nanostores": "^1.0.1", "react": "^19.1.0", "react-dom": "^19.1.0", "swiper": "^11.2.6", @@ -1616,6 +1618,25 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@nanostores/react": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@nanostores/react/-/react-1.0.0.tgz", + "integrity": "sha512-eDduyNy+lbQJMg6XxZ/YssQqF6b4OXMFEZMYKPJCCmBevp1lg0g+4ZRi94qGHirMtsNfAWKNwsjOhC+q1gvC+A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "engines": { + "node": "^20.0.0 || >=22.0.0" + }, + "peerDependencies": { + "nanostores": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^1.0.0", + "react": ">=18.0.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -7375,6 +7396,21 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/nanostores": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/nanostores/-/nanostores-1.0.1.tgz", + "integrity": "sha512-kNZ9xnoJYKg/AfxjrVL4SS0fKX++4awQReGqWnwTRHxeHGZ1FJFVgTqr/eMrNQdp0Tz7M7tG/TDaX8QfHDwVCw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "engines": { + "node": "^20.0.0 || >=22.0.0" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", diff --git a/package.json b/package.json index c07ad25..2977235 100644 --- a/package.json +++ b/package.json @@ -15,10 +15,12 @@ "dependencies": { "@astrojs/react": "^4.2.7", "@astrojs/tailwind": "^6.0.2", + "@nanostores/react": "^1.0.0", "@tailwindcss/vite": "^4.1.6", "@types/react": "^19.1.3", "@types/react-dom": "^19.1.3", "astro": "^5.7.12", + "nanostores": "^1.0.1", "react": "^19.1.0", "react-dom": "^19.1.0", "swiper": "^11.2.6", diff --git a/public/docs/oferta.pdf b/public/docs/oferta.pdf new file mode 100644 index 0000000..50f772b Binary files /dev/null and b/public/docs/oferta.pdf differ diff --git a/src/assets/icons/Spinner.tsx b/src/assets/icons/Spinner.tsx new file mode 100644 index 0000000..dd42733 --- /dev/null +++ b/src/assets/icons/Spinner.tsx @@ -0,0 +1,15 @@ +import { cn } from '@/libs/cn' +import React from 'react' + +export type SpinnerProps = { + className?: string +} + +export const Spinner: React.FC = ({ className }: SpinnerProps) => ( +
+) diff --git a/src/components/Drawer.tsx b/src/components/Drawer.tsx new file mode 100644 index 0000000..7d6e12f --- /dev/null +++ b/src/components/Drawer.tsx @@ -0,0 +1,81 @@ +import { Spinner } from '@/assets/icons/Spinner' +import { cn } from '@/libs/cn' +import React, { useCallback, useEffect } from 'react' + +export interface DrawerProps { + isOpen: boolean + onClose: () => void + loading?: boolean + children: React.ReactNode +} + +const Drawer: React.FC = ({ isOpen, onClose, loading = false, children }) => { + const handleBackdropClick = useCallback( + (e: React.MouseEvent) => { + if (e.target === e.currentTarget) { + onClose() + } + }, + [onClose] + ) + + const handleDrawerClick = useCallback((e: React.MouseEvent) => { + e.stopPropagation() + }, []) + + useEffect(() => { + document.body.style.overflow = isOpen ? 'hidden' : 'auto' + }, [isOpen]) + + return ( +
+ {/* Backdrop */} +
+ +
+ + +
+ {loading ? ( +
+ +
+ ) : ( + children + )} +
+
+
+ ) +} + +export default Drawer diff --git a/src/components/Footer.astro b/src/components/Footer.astro index 89731b6..30e6b18 100644 --- a/src/components/Footer.astro +++ b/src/components/Footer.astro @@ -26,6 +26,13 @@ const t = useTranslations(lang)

© {new Date().getFullYear()} {t('footer.copyright')} + + {t('oferta')} +

{ socialMediaLinks && ( diff --git a/src/components/services/CharachteristicCard.tsx b/src/components/services/CharachteristicCard.tsx index 66c346b..594d2b8 100644 --- a/src/components/services/CharachteristicCard.tsx +++ b/src/components/services/CharachteristicCard.tsx @@ -1,5 +1,6 @@ import type { linkSchema } from '@/content.config' import type { z } from 'astro:content' +import { YClientsWidgetButton } from '../yclients-widget/YclientsWidgetButton' type Props = { title: string @@ -22,11 +23,7 @@ export const CharachteristicCard: React.FC = ({ title, description, price dangerouslySetInnerHTML={{ __html: price }} /> )} - {link && ( - - {link.title} - - )} + {link?.title}
) diff --git a/src/components/services/Services.tsx b/src/components/services/Services.tsx index 0008562..5aba367 100644 --- a/src/components/services/Services.tsx +++ b/src/components/services/Services.tsx @@ -5,6 +5,7 @@ import { type SwiperRef, SwiperSlide } from 'swiper/react' import { CharachteristicCard } from './CharachteristicCard' import { cn } from '@/libs/cn' import { SimpleSwiper } from '../swiper/SimpleSwiper' +import React from 'react' export type ServicesProps = { services: z.infer[] diff --git a/src/components/yclients-widget/YclientsWidget.tsx b/src/components/yclients-widget/YclientsWidget.tsx new file mode 100644 index 0000000..f069fc2 --- /dev/null +++ b/src/components/yclients-widget/YclientsWidget.tsx @@ -0,0 +1,23 @@ +import React, { useState, useRef } from 'react' +import Drawer from '../Drawer' +import { isYClientsWidgetOpen, toggleYClientsWidget } from '@/stores/yclientsWidgetStore' +import { useStore } from '@nanostores/react' + +const YclientsWidget: React.FC = () => { + const [loading, setLoading] = useState(false) + const iframe = useRef(null) + const $isYClientsWidgetOpen = useStore(isYClientsWidgetOpen) + + return ( + +