-
Inicio de sesión
+
{t("login.title")}
diff --git a/src/components/Auth/PasswordInput.jsx b/src/components/Auth/PasswordInput.jsx
index 8ee4201..ff27e11 100644
--- a/src/components/Auth/PasswordInput.jsx
+++ b/src/components/Auth/PasswordInput.jsx
@@ -4,9 +4,11 @@ import '@/css/PasswordInput.css';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faEye, faEyeSlash, faKey } from '@fortawesome/free-solid-svg-icons';
+import { useTranslation } from 'react-i18next';
const PasswordInput = ({ value, onChange, name = "password" }) => {
const [show, setShow] = useState(false);
+ const { t } = useTranslation();
const toggleShow = () => setShow(prev => !prev);
@@ -15,10 +17,7 @@ const PasswordInput = ({ value, onChange, name = "password" }) => {
-
- Contraseña
- >
+ t("login.password_label")
}
>
{
return (
-
- {children}
+
+
+ {children}
+
);
}
diff --git a/src/components/Header.jsx b/src/components/Header.jsx
index 579022b..96a2f86 100644
--- a/src/components/Header.jsx
+++ b/src/components/Header.jsx
@@ -1,10 +1,15 @@
import '@/css/Header.css';
+import { useTranslation } from 'react-i18next';
-const Header = () => (
-
-);
+const Header = () => {
+ const { t } = useTranslation();
+
+ return (
+
+ Adeptus Miniaturium
+ {t("header.subtitle")}
+
+ );
+};
export default Header;
\ No newline at end of file
diff --git a/src/components/Home/AboutMeSection.jsx b/src/components/Home/AboutMeSection.jsx
deleted file mode 100644
index c23e7b4..0000000
--- a/src/components/Home/AboutMeSection.jsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import TechCard from "@/components/TechCard";
-
-const AboutMeSection = () => (
-
- +++ Archivo: Markcus +++
-
-
-
-
- [ESTADO] : Operativo
- [UBICACIÓN] : Andalucía
- [ESPECIALIDAD] : Grimdark Realista, Weathering pesado, OSL.
-
-
- Markcus no pinta para que queden bonitos en la estantería. Pinta para que parezca que tus muñecos han sobrevivido a un bombardeo orbital en Istvaan V. Aquí hay barro, sangre y oscuridad.
-
-
-
-
-
-);
-
-export default AboutMeSection;
\ No newline at end of file
diff --git a/src/components/Home/SamplesSection.jsx b/src/components/Home/SamplesSection.jsx
deleted file mode 100644
index 2609172..0000000
--- a/src/components/Home/SamplesSection.jsx
+++ /dev/null
@@ -1,29 +0,0 @@
-const SamplesSection = () => {
- const muestras = [
- { icon: '☠', title: 'Muestra A-1: Astartes Pattern' },
- { icon: '⚙', title: 'Muestra B-2: Engine War' },
- { icon: '⚔', title: 'Muestra C-3: Xenos Filth' },
- ];
-
- return (
-
- +++ Muestras +++
-
- {muestras.map((m, i) => (
-
-
-
- {m.icon}
-
-
- {m.title}
-
-
-
- ))}
-
-
- );
-};
-
-export default SamplesSection;
\ No newline at end of file
diff --git a/src/components/Home/ScrollBackgroundSpin.jsx b/src/components/Home/ScrollBackgroundSpin.jsx
new file mode 100644
index 0000000..6d5aa0a
--- /dev/null
+++ b/src/components/Home/ScrollBackgroundSpin.jsx
@@ -0,0 +1,37 @@
+import { useEffect, useState } from "react";
+
+const images = [
+ "/images/mini_1.jpeg",
+ "/images/mini_2.jpeg",
+ "/images/mini_3.jpeg",
+ "/images/mini_4.jpeg",
+ "/images/mini_5.jpeg",
+];
+
+const TOTAL_FRAMES = images.length;
+
+const ScrollBackgroundSpin = () => {
+ const [frame, setFrame] = useState(0);
+
+ useEffect(() => {
+ const handleScroll = () => {
+ const scrollTop = window.scrollY;
+ const maxScroll = document.body.scrollHeight - window.innerHeight;
+ const progress = scrollTop / maxScroll;
+
+ const currentFrame = Math.floor(progress * TOTAL_FRAMES);
+ setFrame(Math.min(currentFrame, TOTAL_FRAMES - 1));
+ };
+
+ window.addEventListener("scroll", handleScroll);
+ return () => window.removeEventListener("scroll", handleScroll);
+ }, []);
+
+ return (
+
+
+
+ );
+};
+
+export default ScrollBackgroundSpin;
\ No newline at end of file
diff --git a/src/components/Home/StartSection.jsx b/src/components/Home/StartSection.jsx
deleted file mode 100644
index 9ce75be..0000000
--- a/src/components/Home/StartSection.jsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import TechCard from "@/components/TechCard";
-
-const StartSection = () => (
-
- +++ INICIALIZANDO +++
-
-
- // PENSAMIENTO DEL DÍA: LA ESPERANZA ES EL PRIMER PASO HACIA LA DECEPCIÓN.
-
-
-
- Bienvenido al manufactorum personal de Markcus . Aquí, las miniaturas grises son purgadas de su falta de color y bendecidas con pigmentos sagrados, lavados de Nuln Oil y pincel seco ritual.
-
- No pintamos juguetes. Forjamos veteranos de la Larga Guerra.
-
-
-
-);
-
-export default StartSection;
\ No newline at end of file
diff --git a/src/components/Home/VoxSection.jsx b/src/components/Home/VoxSection.jsx
deleted file mode 100644
index 2a81b19..0000000
--- a/src/components/Home/VoxSection.jsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import TechCard from "@/components/TechCard";
-
-const VoxSection = () => (
-
- +++ Súplica al Manufactorum +++
-
- Rellena los datos para solicitar la atención del Artífice. Sé preciso, el tiempo es un recurso limitado del Emperador.
-
-
-
-);
-
-export default VoxSection;
\ No newline at end of file
diff --git a/src/components/LanguageButton.jsx b/src/components/LanguageButton.jsx
new file mode 100644
index 0000000..55fa3ca
--- /dev/null
+++ b/src/components/LanguageButton.jsx
@@ -0,0 +1,33 @@
+import { useTranslation } from "react-i18next";
+import NavItem from '@/components/NavBar/NavItem';
+
+const LanguageButton = ({ as = "button", index = null }) => {
+ const { i18n } = useTranslation();
+
+ const toggleLanguage = () => {
+ console.log(i18n.language);
+ const nextLang = i18n.language === "es" ? "en" : "es";
+ i18n.changeLanguage(nextLang);
+ };
+
+ if (as === "navitem") {
+ return (
+
+ );
+ }
+
+ return (
+
+ {i18n.language === "es" ? "🇪🇸" : "🇺🇸"}
+
+ );
+};
+
+export default LanguageButton;
\ No newline at end of file
diff --git a/src/components/NavBar/NavBar.jsx b/src/components/NavBar/NavBar.jsx
index 1eef646..df36751 100644
--- a/src/components/NavBar/NavBar.jsx
+++ b/src/components/NavBar/NavBar.jsx
@@ -1,18 +1,21 @@
import '@/css/NavBar.css';
import NavItem from './NavItem';
-
-const navItems = [
- { label: 'Inicio', href: '/#inicio' },
- { label: 'Muestras', href: '/#muestras' },
- { label: 'Pedidos', href: '/#pedidos' },
- { label: 'Sobre Markcus', href: '/#sobre-mi' },
- { label: "🇪🇸", href: '#' },
- { label: "Login", href: '/login' }
-];
+import LanguageButton from '../LanguageButton';
+import { useTranslation } from 'react-i18next';
const NavBar = () => {
- const centerItems = navItems.slice(0, navItems.length - 2);
- const rightItems = navItems.slice(-2);
+ const { t } = useTranslation();
+
+ const navItems = [
+ { label: t("nav.inicio.label"), href: `/#${t("nav.inicio.href")}` },
+ { label: t("nav.muestras.label"), href: `/#${t("nav.muestras.href")}` },
+ { label: t("nav.pedidos.label"), href: `/#${t("nav.pedidos.href")}` },
+ { label: t("nav.sobre.label"), href: `/#${t("nav.sobre.href")}` },
+ { label: t("nav.login.label"), href: `/${t("nav.login.href")}` }
+ ];
+
+ const centerItems = navItems.slice(0, navItems.length - 1);
+ const rightItems = navItems.slice(-1);
return (
@@ -23,8 +26,9 @@ const NavBar = () => {
))}
+
{rightItems.map((item, index) => (
-
+
))}
diff --git a/src/components/NavBar/NavItem.jsx b/src/components/NavBar/NavItem.jsx
index c457b8f..a942083 100644
--- a/src/components/NavBar/NavItem.jsx
+++ b/src/components/NavBar/NavItem.jsx
@@ -1,13 +1,32 @@
-import { Link } from "react-router-dom";
+import { HashLink } from "react-router-hash-link/dist/react-router-hash-link.cjs.production";
-const NavItem = ({ item, index, total }) => {
+const NavItem = ({ item, index, onClick }) => {
let borderClass = `${index === 0 ? "border-left border-right" : "border-right"}`;
+ const handleClick = (e) => {
+ if (onClick) {
+ e.preventDefault();
+ onClick();
+ } else if (item.href === "#") {
+ e.preventDefault();
+ }
+ };
+
return (
-
- {item.label}
-
+ {onClick || item.href === "#" ? (
+
+ {item.label}
+
+ ) : (
+
+ {item.label}
+
+ )}
);
};
diff --git a/src/css/Header.css b/src/css/Header.css
index aec35cb..1af0aa1 100644
--- a/src/css/Header.css
+++ b/src/css/Header.css
@@ -1,6 +1,6 @@
header {
background:
- linear-gradient(to bottom, rgba(0,0,0,0.9), rgba(0,0,0,0.5)),
+ linear-gradient(to bottom, rgba(0,0,0,1), rgba(0,0,0,1)),
url('https://www.transparenttextures.com/patterns/dark-matter.png');
border-bottom: 4px double var(--imperial-gold);
box-shadow: 0 10px 30px rgba(0,0,0,0.9);
diff --git a/src/css/LoginForm.css b/src/css/LoginForm.css
index b5dd203..96d5559 100644
--- a/src/css/LoginForm.css
+++ b/src/css/LoginForm.css
@@ -1,7 +1,7 @@
.login-card {
background: #111 !important;
- border: 1px solid var(--dirty-gold);
- color: var(--parchment);
+ border: 1px solid var(--dirty-gold) !important;
+ color: var(--parchment) !important;
padding: 40px;
clip-path: polygon(
20px 0, 100% 0,
@@ -42,7 +42,7 @@ input.form-control:focus {
font-family: 'Cinzel', serif;
text-transform: uppercase;
letter-spacing: 1px;
- color: var(--dirty-gold);
+ color: var(--dirty-gold) !important;
}
.form-floating > label::after {
@@ -51,9 +51,9 @@ input.form-control:focus {
.login-button {
font-family: 'Cinzel', serif !important;
- font-weight: 700 !important;
+ font-weight: bold !important;
+ text-transform: uppercase !important;
letter-spacing: 2px !important;
- text-transform: uppercase;
background: #000 !important;
border: 1px solid var(--imperial-gold) !important;
color: var(--imperial-gold) !important;
@@ -69,8 +69,8 @@ input.form-control:focus {
.login-button:hover {
background: var(--blood-god) !important;
- border-color: var(--plasma-glow) !important;
color: #fff !important;
- box-shadow: 0 0 20px var(--blood-god);
- text-shadow: 0 0 5px #fff;
+ border-color: var(--plasma-glow) !important;
+ box-shadow: 0 0 20px var(--blood-god) !important;
+ text-shadow: 0 0 5px #fff !important;
}
\ No newline at end of file
diff --git a/src/css/NavBar.css b/src/css/NavBar.css
index 424ab6c..5d05e88 100644
--- a/src/css/NavBar.css
+++ b/src/css/NavBar.css
@@ -34,4 +34,39 @@ li.border-right .nav-link-custom {
.nav-link-custom::before { content: '[ '; opacity: 0; transition: 0.3s; color: var(--imperial-gold); }
.nav-link-custom::after { content: ' ]'; opacity: 0; transition: 0.3s; color: var(--imperial-gold); }
-.nav-link-custom:hover::before, .nav-link-custom:hover::after { opacity: 1; }
\ No newline at end of file
+.nav-link-custom:hover::before, .nav-link-custom:hover::after { opacity: 1; }
+
+.nav-button {
+ all: unset;
+ display: block;
+ padding: 15px 30px;
+ color: #666;
+ font-family: 'Cinzel', serif;
+ font-weight: 700;
+ text-transform: uppercase;
+ transition: 0.3s;
+ position: relative;
+ cursor: pointer;
+}
+
+.border-left .nav-button {
+ border-left: 1px solid #222;
+}
+
+.border-right .nav-button {
+ border-right: 1px solid #222;
+}
+
+.nav-button:hover {
+ color: var(--parchment);
+ background-color: var(--blood-god);
+ box-shadow: inset 0 0 10px #000;
+}
+
+.nav-button::before { content: '[ '; opacity: 0; transition: 0.3s; color: var(--imperial-gold); }
+.nav-button::after { content: ' ]'; opacity: 0; transition: 0.3s; color: var(--imperial-gold); }
+
+.nav-button:hover::before,
+.nav-button:hover::after {
+ opacity: 1;
+}
\ No newline at end of file
diff --git a/src/css/PasswordInput.css b/src/css/PasswordInput.css
index b1fc02e..926d07b 100644
--- a/src/css/PasswordInput.css
+++ b/src/css/PasswordInput.css
@@ -2,6 +2,7 @@ button.show-button {
color: var(--show-btn-color);
}
+
button.show-button:hover {
color: var(--show-btn-hover);
}
diff --git a/src/css/index.css b/src/css/index.css
index c39a577..f58f93a 100644
--- a/src/css/index.css
+++ b/src/css/index.css
@@ -1,6 +1,65 @@
+/* latin-ext */
+@font-face {
+ font-family: 'Cinzel';
+ font-style: normal;
+ font-weight: 400;
+ font-display: swap;
+ src: url(https://fonts.gstatic.com/s/cinzel/v26/8vIJ7ww63mVu7gt7-GT7LEc.woff2) format('woff2');
+ unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+ font-family: 'Cinzel';
+ font-style: normal;
+ font-weight: 400;
+ font-display: swap;
+ src: url(https://fonts.gstatic.com/s/cinzel/v26/8vIJ7ww63mVu7gt79mT7.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* latin-ext */
+@font-face {
+ font-family: 'Cinzel';
+ font-style: normal;
+ font-weight: 700;
+ font-display: swap;
+ src: url(https://fonts.gstatic.com/s/cinzel/v26/8vIJ7ww63mVu7gt7-GT7LEc.woff2) format('woff2');
+ unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+ font-family: 'Cinzel';
+ font-style: normal;
+ font-weight: 700;
+ font-display: swap;
+ src: url(https://fonts.gstatic.com/s/cinzel/v26/8vIJ7ww63mVu7gt79mT7.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* latin-ext */
+@font-face {
+ font-family: 'Cinzel';
+ font-style: normal;
+ font-weight: 900;
+ font-display: swap;
+ src: url(https://fonts.gstatic.com/s/cinzel/v26/8vIJ7ww63mVu7gt7-GT7LEc.woff2) format('woff2');
+ unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+ font-family: 'Cinzel';
+ font-style: normal;
+ font-weight: 900;
+ font-display: swap;
+ src: url(https://fonts.gstatic.com/s/cinzel/v26/8vIJ7ww63mVu7gt79mT7.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* latin */
@font-face {
font-family: 'Share Tech Mono';
- src: url("https://fonts.googleapis.com/css2?family=Cinzel:wght@400;700;900&family=Share+Tech+Mono&display=swap");
+ font-style: normal;
+ font-weight: 400;
+ font-display: swap;
+ src: url(https://fonts.gstatic.com/s/sharetechmono/v16/J7aHnp1uDWRBEqV98dVQztYldFcLowEF.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
:root {
@@ -40,6 +99,13 @@ body::after {
}
/* SECCIONES Y TITULOS */
+section {
+ padding: 80px 20px !important;
+ max-width: 1200px !important;
+ margin: auto !important;
+ scroll-margin-top: 40px;
+}
+
.section-title {
font-family: 'Cinzel', serif;
font-size: 2.5rem;
@@ -57,6 +123,31 @@ body::after {
vertical-align: middle;
}
+/* SPIN */
+.spin-background {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: -1;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ pointer-events: none;
+}
+
+.spin-background img {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ opacity: 0.15;
+ transition: opacity 0.3s ease;
+}
+
/* BOTONES */
.btn-imperial {
display: inline-block;
diff --git a/src/i18n.js b/src/i18n.js
new file mode 100644
index 0000000..b3ba114
--- /dev/null
+++ b/src/i18n.js
@@ -0,0 +1,19 @@
+import i18n from "i18next";
+import { initReactI18next } from "react-i18next";
+
+import en from "@/locales/en.json";
+import es from "@/locales/es.json";
+
+i18n
+ .use(initReactI18next)
+ .init({
+ resources: {
+ en: { translation: en },
+ es: { translation: es },
+ },
+ lng: "en",
+ fallbackLng: "es",
+ interpolation: { escapeValue: false },
+ });
+
+export default i18n;
\ No newline at end of file
diff --git a/src/locales/en.json b/src/locales/en.json
new file mode 100644
index 0000000..6536060
--- /dev/null
+++ b/src/locales/en.json
@@ -0,0 +1,60 @@
+{
+ "header": {
+ "subtitle": "Markcus Garklios The Executioner Crusader"
+ },
+ "nav": {
+ "inicio": { "label": "Home", "href": "home" },
+ "muestras": { "label": "Portfolio", "href": "portfolio" },
+ "pedidos": { "label": "Comissions", "href": "comissions" },
+ "sobre": { "label": "About Markcus", "href": "about-me" },
+ "login": { "label": "Login", "href": "login" }
+ },
+ "home": {
+ "inicio_title": "+++ INITIALIZING +++",
+ "inicio_thought": "// THOUGHT OF THE DAY: HOPE IS THE FIRST STEP TOWARD DISAPPOINTMENT.",
+ "inicio_welcome": "Welcome to Markcus' personal manufactorum. Here, grey miniatures are purged of their lack of color and blessed with sacred pigments, Nuln Oil washes, and ritual dry brushing.",
+ "inicio_note": "We don't paint toys. We forge veterans of the Long War.",
+ "inicio_button": "Start Order Protocol",
+ "muestras_title": "+++ Portfolio +++",
+ "muestras": [
+ {
+ "icon": "☠",
+ "title": "Sample A-1: Astartes Pattern"
+ },
+ {
+ "icon": "⚙",
+ "title": "Sample B-2: Engine War"
+ },
+ {
+ "icon": "⚔",
+ "title": "Sample C-3: Xenos Filth"
+ }
+ ],
+ "pedidos_title": "+++ Plea to the Manufactorum +++",
+ "pedidos_text": "Fill in the details to request the attention of the Artificer. Be precise, time is an Emperor-limited resource.",
+ "pedidos_name": "Commander Designation (Name)",
+ "pedidos_email": "Vox Frequency (Email)",
+ "pedidos_requirements": "Detail mission requirements: Color scheme, Faction, Shading level...",
+ "pedidos_button": "Transmit",
+ "sobre_title": "+++ File: Markcus +++",
+ "sobre_status": {
+ "k": "[STATUS]:",
+ "v": "Operational"
+ },
+ "sobre_location": {
+ "k": "[LOCATION]:",
+ "v": "Andalusia"
+ },
+ "sobre_specialty": {
+ "k": "[SPECIALTY]:",
+ "v": "Acrilic painting, realistic details"
+ },
+ "sobre_text": "I´m Markcus, a loyal servant of the Emperor. My purpose is to expand the Emperor's domains, through wargaming and miniature modeling. Warhammer and miniature painting are my hobby and passion. That's why I put my skills as a painter at the service of all of you who want to increase your collection, even if you're a veteran or a beginner. I can paint anything: Space Marines, Imperial Guard, Necrons, Orks, etc. I can also paint miniatures that aren't from Warhammer."
+ },
+ "login": {
+ "title": "Authentication required",
+ "user_label": "Identifier",
+ "password_label": "Key",
+ "button": "Proceed"
+ }
+}
\ No newline at end of file
diff --git a/src/locales/es.json b/src/locales/es.json
new file mode 100644
index 0000000..db7bcf7
--- /dev/null
+++ b/src/locales/es.json
@@ -0,0 +1,54 @@
+{
+ "header": {
+ "subtitle": "Markcus Garklios The Executioner Crusader"
+ },
+ "nav": {
+ "inicio": { "label": "Inicio", "href": "inicio" },
+ "muestras": { "label": "Portafolio", "href": "portafolio" },
+ "pedidos": { "label": "Comisiones", "href": "comisiones" },
+ "sobre": { "label": "Sobre Markcus", "href": "sobre-mi" },
+ "login": { "label": "Login", "href": "login" }
+ },
+ "home": {
+ "inicio_title": "+++ INICIALIZANDO +++",
+ "inicio_thought": "// PENSAMIENTO DEL DÍA: LA ESPERANZA ES EL PRIMER PASO HACIA LA DECEPCIÓN.",
+ "inicio_welcome": "Bienvenido al manufactorum personal de Markcus. Aquí, las miniaturas grises son purgadas de su falta de color y bendecidas con pigmentos sagrados, lavados de Nuln Oil y pincel seco ritual.",
+ "inicio_note": "No pintamos juguetes. Forjamos veteranos de la Larga Guerra.",
+ "inicio_button": "Iniciar Protocolo de Encargo",
+
+ "muestras_title": "+++ Portafolio +++",
+ "muestras": [
+ { "icon": "☠", "title": "Muestra A-1: Astartes Pattern" },
+ { "icon": "⚙", "title": "Muestra B-2: Engine War" },
+ { "icon": "⚔", "title": "Muestra C-3: Xenos Filth" }
+ ],
+
+ "pedidos_title": "+++ Súplica al Manufactorum +++",
+ "pedidos_text": "Rellena los datos para solicitar la atención del Artífice. Sé preciso, el tiempo es un recurso limitado del Emperador.",
+ "pedidos_name": "Designación del Comandante (Nombre)",
+ "pedidos_email": "Frecuencia Vox (Email)",
+ "pedidos_requirements": "Detalla los requerimientos de la misión: Esquema de color, Facción, Nivel de degradado...",
+ "pedidos_button": "Transmitir",
+
+ "sobre_title": "+++ Archivo: Markcus +++",
+ "sobre_status": {
+ "k": "[ESTADO]:",
+ "v": "Operativo"
+ },
+ "sobre_location": {
+ "k": "[UBICACIÓN]:",
+ "v": "Andalucía"
+ },
+ "sobre_specialty": {
+ "k": "[ESPECIALIDAD]:",
+ "v": "Pintura acrílica, detalles realistas"
+ },
+ "sobre_text": "Soy Markcus, un leal servidor del Emperador. Mi propósito es expandir los dominios del Emperador, a través de wargames y modelado de miniaturas. Warhammer y la pintura de miniaturas son mi afición y pasión. Por eso pongo mis habilidades como pintor al servicio de todos vosotros que queréis ampliar vuestra colección, ya seáis veteranos o principiantes. Puedo pintar cualquier cosa: Marines Espaciales, Guardia Imperial, Necrones, Orkos, etc. También puedo pintar miniaturas que no sean de Warhammer."
+ },
+ "login": {
+ "title": "Autenticación requerida",
+ "user_label": "Identificador",
+ "password_label": "Clave",
+ "button": "Acceder"
+ }
+}
\ No newline at end of file
diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx
index bc5707b..b55b9f6 100644
--- a/src/pages/Home.jsx
+++ b/src/pages/Home.jsx
@@ -1,18 +1,93 @@
-import StartSection from "@/components/Home/StartSection";
-import SamplesSection from "@/components/Home/SamplesSection";
-import VoxSection from "@/components/Home/VoxSection";
-import AboutMeSection from "@/components/Home/AboutMeSection";
import ContentWrapper from "@/components/ContentWrapper";
import CustomContainer from "@/components/CustomContainer";
+import ScrollBackgroundSpin from "@/components/Home/ScrollBackgroundSpin";
+import TechCard from "@/components/TechCard";
+import { HashLink } from "react-router-hash-link/dist/react-router-hash-link.cjs.production";
+import { useTranslation } from "react-i18next";
const Home = () => {
+ const { t } = useTranslation();
+ const muestras = t("home.muestras", { returnObjects: true });
+
return (
+
-
-
-
-
+
+
+ {t("home.inicio_title")}
+
+
+ {t("home.inicio_thought")}
+
+
+
+ {t("home.inicio_welcome")}
+
+ {t("home.inicio_note")}
+
+
+ {t("home.inicio_button")}
+
+
+
+
+
+
+ {t("home.muestras_title")}
+
+ {muestras.map((m, i) => (
+
+
+
+ {m.icon}
+
+
+ {m.title}
+
+
+
+ ))}
+
+
+
+
+
+
+ {t("home.sobre_title")}
+
+
+
+
+ {t("home.sobre_status.k")} {t("home.sobre_status.v")}
+ {t("home.sobre_location.k")} {t("home.sobre_location.v")}
+ {t("home.sobre_specialty.k")} {t("home.sobre_specialty.v")}
+
+
+ {t("home.sobre_text")}
+
+
+
+
+
+
);