@@ -63,13 +63,13 @@ export function DownloadCTA() {
- Descargar para Windows
+ Descargar última versión para Windows
Preguntas frecuentes
- Respuestas rápidas sobre el funcionamiento, la licencia y la instalación de FreeTPV. + Respuestas prácticas sobre instalación, impresión, usuarios y funcionamiento local.
+
+
+
+
Todo lo que necesitas para tu negocio
-
+
FreeTPV incluye las herramientas esenciales para gestionar
tu bar, restaurante o cafetería de forma profesional.
-
+
{features.map((feature, index) => (
-
-
+
+
- {feature.title}
+ {feature.title}
{feature.description}
))}
diff --git a/landing/components/footer.tsx b/landing/components/footer.tsx
index e3de2ac..815b3f0 100644
--- a/landing/components/footer.tsx
+++ b/landing/components/footer.tsx
@@ -9,9 +9,9 @@ function GithubIcon({ className }: { className?: string }) {
export function Footer() {
return (
diff --git a/landing/components/header.tsx b/landing/components/header.tsx
index d7e7802..22e3fdb 100644
--- a/landing/components/header.tsx
+++ b/landing/components/header.tsx
@@ -1,96 +1,111 @@
"use client";
-import Link from "next/link";
import { Menu, X } from "lucide-react";
import { useState } from "react";
+import { ThemeToggle } from "@/components/theme-toggle";
+
function GithubIcon({ className }: { className?: string }) {
return (
);
}
+const navItems = [
+ { href: "#caracteristicas", label: "Características" },
+ { href: "#capturas", label: "Capturas" },
+ { href: "#faq", label: "FAQ" },
+ { href: "#descargar", label: "Descargar" },
+];
+
export function Header() {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
+ function scrollToTop() {
+ setMobileMenuOpen(false);
+ window.scrollTo({ top: 0, behavior: "smooth" });
+
+ if (window.location.hash) {
+ window.history.replaceState(null, "", window.location.pathname);
+ }
+ }
+
return (
-
-
-
-
+
+
+
+
-
{mobileMenuOpen && (
-
+
- setMobileMenuOpen(false)}
- >
- Características
-
- setMobileMenuOpen(false)}
- >
- Capturas
-
- setMobileMenuOpen(false)}
- >
- Descargar
-
+ {navItems.map((item) => (
+ setMobileMenuOpen(false)}
+ >
+ {item.label}
+
+ ))}
setMobileMenuOpen(false)}
>
-
+
GitHub
diff --git a/landing/components/hero.tsx b/landing/components/hero.tsx
index 4fdc515..c60d283 100644
--- a/landing/components/hero.tsx
+++ b/landing/components/hero.tsx
@@ -13,7 +13,7 @@ function GithubIcon({ className }: { className?: string }) {
export function Hero() {
return (
-
+
- Descargar para Windows
+ Descargar última versión para Windows
- MIT · Windows 10/11 · Java 25
+ MIT · Windows 10/11 · Java 25 incluido en el instalador
diff --git a/landing/components/screenshots.tsx b/landing/components/screenshots.tsx
index 6fdd28e..25881e7 100644
--- a/landing/components/screenshots.tsx
+++ b/landing/components/screenshots.tsx
@@ -33,25 +33,25 @@ const screenshots = [
export function Screenshots() {
return (
-
-
-
-
+
+
+
+
Un vistazo a FreeTPV
-
+
Las capturas mostrarán las partes principales de la aplicación,
desde la venta diaria hasta la configuración del negocio.
-
+
{screenshots.map((screenshot) => (
-
-
-
-
+
+
+
+
Captura pendiente
@@ -61,7 +61,7 @@ export function Screenshots() {
- {screenshot.title}
+ {screenshot.title}
{screenshot.description}
))}
diff --git a/landing/components/theme-toggle.tsx b/landing/components/theme-toggle.tsx
new file mode 100644
index 0000000..dee741b
--- /dev/null
+++ b/landing/components/theme-toggle.tsx
@@ -0,0 +1,76 @@
+"use client";
+
+import { Moon, Sun } from "lucide-react";
+import { useEffect, useState } from "react";
+
+const STORAGE_KEY = "freetpv-theme";
+
+type Theme = "latte" | "mocha";
+
+function getSystemTheme(): Theme {
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "mocha" : "latte";
+}
+
+function getSavedTheme(): Theme | null {
+ const savedTheme = window.localStorage.getItem(STORAGE_KEY);
+
+ if (savedTheme === "latte" || savedTheme === "mocha") {
+ return savedTheme;
+ }
+
+ return null;
+}
+
+function applyTheme(theme: Theme) {
+ document.documentElement.dataset.theme = theme;
+}
+
+export function ThemeToggle() {
+ const [theme, setTheme] = useState("latte");
+ const isDark = theme === "mocha";
+
+ useEffect(() => {
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
+ const savedTheme = getSavedTheme();
+ const initialTheme = savedTheme ?? getSystemTheme();
+
+ setTheme(initialTheme);
+ applyTheme(initialTheme);
+
+ function handleSystemThemeChange() {
+ if (getSavedTheme() !== null) {
+ return;
+ }
+
+ const nextTheme = mediaQuery.matches ? "mocha" : "latte";
+ setTheme(nextTheme);
+ applyTheme(nextTheme);
+ }
+
+ mediaQuery.addEventListener("change", handleSystemThemeChange);
+
+ return () => {
+ mediaQuery.removeEventListener("change", handleSystemThemeChange);
+ };
+ }, []);
+
+ function toggleTheme() {
+ const nextTheme = isDark ? "latte" : "mocha";
+
+ setTheme(nextTheme);
+ applyTheme(nextTheme);
+ window.localStorage.setItem(STORAGE_KEY, nextTheme);
+ }
+
+ return (
+
+ );
+}
diff --git a/landing/components/trust-signals.tsx b/landing/components/trust-signals.tsx
new file mode 100644
index 0000000..bd24716
--- /dev/null
+++ b/landing/components/trust-signals.tsx
@@ -0,0 +1,33 @@
+const signals = [
+ {
+ title: "Gratis y sin cuotas",
+ description: "Sin pagos mensuales ni funciones bloqueadas.",
+ },
+ {
+ title: "Funciona en local",
+ description: "Tus datos se guardan en el equipo del negocio.",
+ },
+ {
+ title: "Código abierto MIT",
+ description: "Proyecto público en GitHub, revisable y adaptable.",
+ },
+];
+
+export function TrustSignals() {
+ return (
+
+
+
+ {signals.map((signal) => (
+ -
+
{signal.title}
+
+ {signal.description}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/landing/public/googlec799a0bae7f48338.html b/landing/public/googlec799a0bae7f48338.html
new file mode 100644
index 0000000..ac53893
--- /dev/null
+++ b/landing/public/googlec799a0bae7f48338.html
@@ -0,0 +1 @@
+google-site-verification: googlec799a0bae7f48338.html
\ No newline at end of file
Todo lo que necesitas para tu negocio
-+
FreeTPV incluye las herramientas esenciales para gestionar tu bar, restaurante o cafetería de forma profesional.
{feature.title}
+{feature.title}
{feature.description}
- MIT · Windows 10/11 · Java 25 + MIT · Windows 10/11 · Java 25 incluido en el instalador
+
+
+
+
Un vistazo a FreeTPV
-
+
Las capturas mostrarán las partes principales de la aplicación,
desde la venta diaria hasta la configuración del negocio.
-
+
{screenshots.map((screenshot) => (
-
-
-
-
+
+
+
+
Captura pendiente
@@ -61,7 +61,7 @@ export function Screenshots() {
- {screenshot.title}
+ {screenshot.title}
{screenshot.description}
))}
diff --git a/landing/components/theme-toggle.tsx b/landing/components/theme-toggle.tsx
new file mode 100644
index 0000000..dee741b
--- /dev/null
+++ b/landing/components/theme-toggle.tsx
@@ -0,0 +1,76 @@
+"use client";
+
+import { Moon, Sun } from "lucide-react";
+import { useEffect, useState } from "react";
+
+const STORAGE_KEY = "freetpv-theme";
+
+type Theme = "latte" | "mocha";
+
+function getSystemTheme(): Theme {
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "mocha" : "latte";
+}
+
+function getSavedTheme(): Theme | null {
+ const savedTheme = window.localStorage.getItem(STORAGE_KEY);
+
+ if (savedTheme === "latte" || savedTheme === "mocha") {
+ return savedTheme;
+ }
+
+ return null;
+}
+
+function applyTheme(theme: Theme) {
+ document.documentElement.dataset.theme = theme;
+}
+
+export function ThemeToggle() {
+ const [theme, setTheme] = useState("latte");
+ const isDark = theme === "mocha";
+
+ useEffect(() => {
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
+ const savedTheme = getSavedTheme();
+ const initialTheme = savedTheme ?? getSystemTheme();
+
+ setTheme(initialTheme);
+ applyTheme(initialTheme);
+
+ function handleSystemThemeChange() {
+ if (getSavedTheme() !== null) {
+ return;
+ }
+
+ const nextTheme = mediaQuery.matches ? "mocha" : "latte";
+ setTheme(nextTheme);
+ applyTheme(nextTheme);
+ }
+
+ mediaQuery.addEventListener("change", handleSystemThemeChange);
+
+ return () => {
+ mediaQuery.removeEventListener("change", handleSystemThemeChange);
+ };
+ }, []);
+
+ function toggleTheme() {
+ const nextTheme = isDark ? "latte" : "mocha";
+
+ setTheme(nextTheme);
+ applyTheme(nextTheme);
+ window.localStorage.setItem(STORAGE_KEY, nextTheme);
+ }
+
+ return (
+
+ );
+}
diff --git a/landing/components/trust-signals.tsx b/landing/components/trust-signals.tsx
new file mode 100644
index 0000000..bd24716
--- /dev/null
+++ b/landing/components/trust-signals.tsx
@@ -0,0 +1,33 @@
+const signals = [
+ {
+ title: "Gratis y sin cuotas",
+ description: "Sin pagos mensuales ni funciones bloqueadas.",
+ },
+ {
+ title: "Funciona en local",
+ description: "Tus datos se guardan en el equipo del negocio.",
+ },
+ {
+ title: "Código abierto MIT",
+ description: "Proyecto público en GitHub, revisable y adaptable.",
+ },
+];
+
+export function TrustSignals() {
+ return (
+
+
+
+ {signals.map((signal) => (
+ -
+
{signal.title}
+
+ {signal.description}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/landing/public/googlec799a0bae7f48338.html b/landing/public/googlec799a0bae7f48338.html
new file mode 100644
index 0000000..ac53893
--- /dev/null
+++ b/landing/public/googlec799a0bae7f48338.html
@@ -0,0 +1 @@
+google-site-verification: googlec799a0bae7f48338.html
\ No newline at end of file
Un vistazo a FreeTPV
-+
Las capturas mostrarán las partes principales de la aplicación, desde la venta diaria hasta la configuración del negocio.
Captura pendiente @@ -61,7 +61,7 @@ export function Screenshots() {
{screenshot.title}
+{screenshot.title}
{screenshot.description}
-
+ {signals.map((signal) => (
+
-
+
{signal.title}
++ {signal.description} +
+
+ ))}
+