From 181926803d575cca3913139f5c087f3167df9e8d Mon Sep 17 00:00:00 2001 From: Jesus Ordosgoitty Date: Sat, 11 Apr 2026 16:32:20 -0400 Subject: [PATCH] feat: implement Modern Blueprint design system with square-cornered components and updated button styles --- BRAND_GUIDELINES.md | 28 +++++++++++++++++ public/locales/en/common.json | 4 +-- public/locales/es/common.json | 4 +-- src/components/AvailabilityBadge.astro | 2 +- src/components/ContactActions.astro | 43 ++++++++++++++++++++------ src/components/ContactForm.tsx | 40 ++++++++++++++---------- src/components/HeaderInteractive.tsx | 8 ++--- src/components/islands/HeroIsland.tsx | 19 +++--------- src/components/ui/ScrollButton.tsx | 39 +++++++++++++++++++++++ src/components/ui/button.tsx | 22 ++++++------- src/components/views/About.tsx | 12 ++----- src/index.css | 12 +++++-- src/pages/es/index.astro | 1 - src/pages/index.astro | 1 - 14 files changed, 157 insertions(+), 78 deletions(-) create mode 100644 BRAND_GUIDELINES.md create mode 100644 src/components/ui/ScrollButton.tsx diff --git a/BRAND_GUIDELINES.md b/BRAND_GUIDELINES.md new file mode 100644 index 0000000..53dfa8b --- /dev/null +++ b/BRAND_GUIDELINES.md @@ -0,0 +1,28 @@ +# Brand Guidelines + +## Visual Language: "Modern Blueprint" +The website follows a "Modern Blueprint" aesthetic, characterized by: +- **Grid-based layouts**: Consistent use of 60px grids. +- **Sharp Corners**: All containers, input fields, and buttons MUST have square corners (`rounded-none`). +- **Precision Borders**: Use 2px borders (`border-2`) for primary elements. +- **High Contrast**: Dark backgrounds with vibrant accent colors (Brilliant Blue). + +## Components + +### Buttons +All buttons must follow these rules: +1. **Square Corners**: Always use `rounded-none`. +2. **Outlined by Default**: Buttons should have a 2px border and transparent background. +3. **Filled on Hover**: On hover, the button should fill with the accent color and text should change color for contrast. +4. **Typography**: Bold, often uppercase with wide tracking for a technical look. + +### Input Fields +- **Corners**: Always `rounded-none`. +- **Borders**: 2px border (`border-2`). +- **Interaction**: Highlight border color on focus. + +## Color Palette +Defined in `src/index.css`. +- **Primary**: Brilliant Blue (#0b5ef3) - `hsl(221 91% 50%)` +- **Background**: Off-white (#edeceb) - `hsl(30 14% 93%)` +- **Foreground**: Dark Navy (#161B24) - `hsl(217 57% 13%)` diff --git a/public/locales/en/common.json b/public/locales/en/common.json index df401f0..4e4c6f3 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -39,8 +39,7 @@ "line1": "Transform Your", "line2": "Digital Presence", "description": "I create innovative and cutting-edge digital products, developing personalized solutions, websites, and extraordinary applications that offer unique experiences and maximize success in the market.", - "ctaPrimary": "Start Your Project", - "ctaSecondary": "Learn More" + "ctaPrimary": "Start Your Project" }, "services": { "title": "What I can do ", @@ -126,7 +125,6 @@ "line2": "Ordosgoitty", "description": "Frontend Developer, Full Stack Engineer, and passionate about software engineering.", "ctaPrimary": "Start Your Project", - "ctaSecondary": "Learn More", "intro": "Hi, I'm Jesus Ordosgoitty. I design and build fast, accessible, and scalable digital products. This page is coming soon." }, "experience": { diff --git a/public/locales/es/common.json b/public/locales/es/common.json index 2d6f796..a155c7d 100644 --- a/public/locales/es/common.json +++ b/public/locales/es/common.json @@ -39,8 +39,7 @@ "line1": "Transforma tu", "line2": "presencia Digital", "description": "Creo productos digitales innovadores y de vanguardia, desarrollando soluciones personalizadas, sitios web y aplicaciones extraordinarias que ofrecen experiencias únicas y maximizan el éxito en el mercado.", - "ctaPrimary": "Comenzar tu Proyecto", - "ctaSecondary": "Saber Más" + "ctaPrimary": "Comenzar tu Proyecto" }, "services": { "title": "Lo que puedo hacer ", @@ -126,7 +125,6 @@ "line2": "Ordosgoitty", "description": "Desarrollador Frontend, Ingeniero Full Stack y apasionado por la ingeniería de software.", "ctaPrimary": "Comenzar tu Proyecto", - "ctaSecondary": "Saber Más", "intro": "Hola, soy Jesús Ordosgoitty. Diseño y desarrollo productos digitales rápidos, accesibles y escalables. Esta página estará disponible pronto." }, "experience": { diff --git a/src/components/AvailabilityBadge.astro b/src/components/AvailabilityBadge.astro index 3451527..91dc8ed 100644 --- a/src/components/AvailabilityBadge.astro +++ b/src/components/AvailabilityBadge.astro @@ -16,7 +16,7 @@ const labels = { const currentLabels = lang === 'es' ? labels.es : labels.en; --- -
+
{isAvailable && ( diff --git a/src/components/ContactActions.astro b/src/components/ContactActions.astro index 61405e1..370e70a 100644 --- a/src/components/ContactActions.astro +++ b/src/components/ContactActions.astro @@ -8,13 +8,13 @@ const config = { const labels = { en: { - whatsapp: "Chat on WhatsApp", - telegram: "Message on Telegram", + whatsapp: "WhatsApp", + telegram: "Telegram", fastResponse: "Fast response (under 2h)" }, es: { - whatsapp: "Hablar por WhatsApp", - telegram: "Mensaje por Telegram", + whatsapp: "WhatsApp", + telegram: "Telegram", fastResponse: "Respuesta rápida (menos de 2h)" } }; @@ -28,10 +28,21 @@ const t = lang === 'es' ? labels.es : labels.en; href={config.whatsapp} target="_blank" rel="noopener noreferrer" - class="flex-1 flex items-center justify-center gap-2 px-6 py-3 bg-[#25D366] hover:bg-[#20ba56] text-white rounded-xl font-bold transition-all shadow-elegant hover:scale-[1.02] active:scale-[0.98]" + class="flex-1 flex items-center justify-center gap-2 p-3 border-2 border-[#25D366] text-[#25D366] hover:bg-[#25D366] hover:text-white rounded-none font-bold transition-all shadow-elegant hover:scale-[1.02] active:scale-[0.98]" > - - + + {t.whatsapp} @@ -40,10 +51,22 @@ const t = lang === 'es' ? labels.es : labels.en; href={config.telegram} target="_blank" rel="noopener noreferrer" - class="flex-1 flex items-center justify-center gap-2 px-6 py-3 bg-[#0088cc] hover:bg-[#0077b5] text-white rounded-xl font-bold transition-all shadow-elegant hover:scale-[1.02] active:scale-[0.98]" + class="flex-1 flex items-center justify-center gap-2 p-3 border-2 border-[#0088cc] text-[#0088cc] hover:bg-[#0088cc] hover:text-white rounded-none font-bold transition-all shadow-elegant hover:scale-[1.02] active:scale-[0.98]" > - - + + + {t.telegram} diff --git a/src/components/ContactForm.tsx b/src/components/ContactForm.tsx index 401b36a..6ffed92 100644 --- a/src/components/ContactForm.tsx +++ b/src/components/ContactForm.tsx @@ -1,4 +1,5 @@ import React, { useState } from 'react'; +import { Send } from 'lucide-react'; interface ContactFormProps { lang?: string; @@ -55,56 +56,61 @@ const ContactForm: React.FC = ({ lang = 'en' }) => { }; return ( -
-
-
- +
+
+
+
-
- +
+
-
- +
+
{status === 'success' && ( -

{t.success}

+

{t.success}

)} {status === 'error' && ( -

{t.error}

+

{t.error}

)} ); diff --git a/src/components/HeaderInteractive.tsx b/src/components/HeaderInteractive.tsx index 862f605..381d80f 100644 --- a/src/components/HeaderInteractive.tsx +++ b/src/components/HeaderInteractive.tsx @@ -105,10 +105,10 @@ const HeaderInteractive = ({ navItems, logoSrc, lang, altLangHref, isOpaque = fa @@ -161,7 +161,7 @@ const HeaderInteractive = ({ navItems, logoSrc, lang, altLangHref, isOpaque = fa aria-label={`Switch to ${altLang}`} > Language: - {altLang} + {altLang}
diff --git a/src/components/islands/HeroIsland.tsx b/src/components/islands/HeroIsland.tsx index 12033e2..0b1262a 100644 --- a/src/components/islands/HeroIsland.tsx +++ b/src/components/islands/HeroIsland.tsx @@ -1,7 +1,7 @@ // src/components/islands/HeroIsland.tsx // React Island — scroll button interactivity + animations -import { ChevronDown } from 'lucide-react'; import { Button } from '@/components/ui/button'; +import ScrollButton from '@/components/ui/ScrollButton'; import ColorBends from '@/components/ColorBends'; interface Props { @@ -9,10 +9,9 @@ interface Props { line2: string; description: string; ctaPrimary: string; - ctaSecondary: string; } -const HeroIsland = ({ line1, line2, description, ctaPrimary, ctaSecondary }: Props) => { +const HeroIsland = ({ line1, line2, description, ctaPrimary }: Props) => { const scrollToSection = (sectionId: string) => { const element = document.getElementById(sectionId); if (element) { @@ -32,7 +31,7 @@ const HeroIsland = ({ line1, line2, description, ctaPrimary, ctaSecondary }: Pro className="flex flex-col justify-center text-white space-y-8 animate-fade-in h-full" id="scroll" > -

+

{line1} {line2}

@@ -51,22 +50,12 @@ const HeroIsland = ({ line1, line2, description, ctaPrimary, ctaSecondary }: Pro {ctaPrimary} - -
-
-
- -
-
+ ); }; diff --git a/src/components/ui/ScrollButton.tsx b/src/components/ui/ScrollButton.tsx new file mode 100644 index 0000000..bca4e12 --- /dev/null +++ b/src/components/ui/ScrollButton.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { ChevronDown } from 'lucide-react'; +import { Button } from './button'; + +interface ScrollButtonProps { + targetId: string; + className?: string; + ariaLabel?: string; +} + +const ScrollButton: React.FC = ({ + targetId, + className = "", + ariaLabel = "Scroll down" +}) => { + const scrollToSection = () => { + const element = document.getElementById(targetId); + if (element) { + element.scrollIntoView({ behavior: 'smooth' }); + } + }; + + return ( +
+
+ +
+
+ ); +}; + +export default ScrollButton; diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index 4d7fa72..47e4714 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -5,25 +5,25 @@ import { cva, type VariantProps } from "class-variance-authority"; import { cn } from "@/lib/utils"; const buttonVariants = cva( - "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-none text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", { variants: { variant: { - default: "bg-primary text-primary-foreground hover:bg-primary/90", - destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90", - outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground", - secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80", + default: "border-2 border-primary bg-transparent text-primary hover:bg-primary hover:text-primary-foreground", + destructive: "border-2 border-destructive bg-transparent text-destructive hover:bg-destructive hover:text-destructive-foreground", + outline: "border-2 border-input bg-transparent hover:bg-accent hover:text-accent-foreground", + secondary: "border-2 border-secondary bg-transparent text-secondary hover:bg-secondary hover:text-secondary-foreground", ghost: "hover:bg-accent hover:text-accent-foreground", link: "text-primary underline-offset-4 hover:underline", - hero: "bg-primary text-primary-foreground shadow-glow hover:shadow-elegant hover:scale-105 transition-all duration-300 font-semibold", + hero: "bg-primary text-primary-foreground shadow-glow hover:bg-primary/90 hover:shadow-elegant hover:scale-105 transition-all duration-300 font-semibold border-2 border-primary", "outline-hero": "border-2 border-white text-white bg-transparent hover:bg-white hover:text-accent transition-all duration-300 font-semibold", - scroll: "bg-white/10 text-white border border-white/20 hover:bg-white/20 rounded-full p-3 hover:scale-110 transition-all duration-300", + scroll: "bg-transparent text-white hover:bg-transparent focus:bg-transparent p-3 hover:scale-110 transition-all duration-300", }, size: { - default: "h-10 px-4 py-2", - sm: "h-9 rounded-md px-3", - lg: "h-11 rounded-md px-8", - xl: "h-12 rounded-md px-10 text-base", + default: "p-3", + sm: "p-2", + lg: "p-4", + xl: "p-5 text-lg", icon: "h-10 w-10", "icon-lg": "h-12 w-12", }, diff --git a/src/components/views/About.tsx b/src/components/views/About.tsx index e4e4501..dadb1d4 100644 --- a/src/components/views/About.tsx +++ b/src/components/views/About.tsx @@ -1,6 +1,6 @@ // src/components/views/About.tsx // React Island — accepts string props from Astro parent (no react-i18next) -import { ChevronDown } from 'lucide-react'; +import ScrollButton from '@/components/ui/ScrollButton'; import founderImg from '@/assets/images/pic.jpg'; import heroImg from '@/assets/hero.jpeg'; @@ -51,15 +51,7 @@ const AboutView = ({ strings }: Props) => { -
- -
+ ); }; diff --git a/src/index.css b/src/index.css index b0c5481..0d94f39 100644 --- a/src/index.css +++ b/src/index.css @@ -129,9 +129,17 @@ All colors MUST be HSL. --sidebar-border: 240 3.7% 15.9%; --sidebar-ring: 217.2 91.2% 59.8%; } -} -@layer base { + html { + font-size: 93.75%; /* Mobile base (15px if default is 16px) */ + } + + @media (min-width: 768px) { + html { + font-size: 100%; /* Desktop base (16px if default is 16px) */ + } + } + * { @apply border-border; } diff --git a/src/pages/es/index.astro b/src/pages/es/index.astro index 0615b5c..a01bb48 100644 --- a/src/pages/es/index.astro +++ b/src/pages/es/index.astro @@ -16,7 +16,6 @@ const heroProps = { line2: t('hero.line2'), description: t('hero.description'), ctaPrimary: t('hero.ctaPrimary'), - ctaSecondary: t('hero.ctaSecondary'), }; const projects = es.portfolio.projects; diff --git a/src/pages/index.astro b/src/pages/index.astro index ac3107b..c142174 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -16,7 +16,6 @@ const heroProps = { line2: t('hero.line2'), description: t('hero.description'), ctaPrimary: t('hero.ctaPrimary'), - ctaSecondary: t('hero.ctaSecondary'), }; const projects = en.portfolio.projects;