From 4e5c13f60a501c480d15f087cea3a5fdc19cc9c8 Mon Sep 17 00:00:00 2001 From: "DESKTOP-RTLN3BA\\$punk" Date: Wed, 17 Jun 2026 21:29:14 -0700 Subject: [PATCH] feat: readded google signins and add global announcement feature - Updated .env.example to include new environment variables for Google authentication and global announcement settings. - Integrated Google sign-in functionality in SignInButton and HeroSection components, allowing users to log in with their Google accounts. - Added GlobalAnnouncement component to display maintenance notices or announcements on the homepage layout. - Enhanced styling for Google sign-in buttons to improve user experience. --- surfsense_web/.env.example | 55 ++++++++++++-- surfsense_web/app/(home)/layout.tsx | 2 + .../components/auth/sign-in-button.tsx | 74 ++++++++++++++++++- .../homepage/global-announcement.tsx | 27 +++++++ .../components/homepage/hero-section.tsx | 55 ++++++++++++++ surfsense_web/lib/env-config.ts | 9 +++ 6 files changed, 214 insertions(+), 8 deletions(-) create mode 100644 surfsense_web/components/homepage/global-announcement.tsx diff --git a/surfsense_web/.env.example b/surfsense_web/.env.example index 746957257..11646c948 100644 --- a/surfsense_web/.env.example +++ b/surfsense_web/.env.example @@ -1,29 +1,74 @@ +# ───────────────────────────────────────────────────────────────────────────── +# Backend connectivity +# ───────────────────────────────────────────────────────────────────────────── + # Optional packaged-client override. Leave unset in Docker so browser requests -# use same-origin relative URLs behind Caddy. +# use same-origin relative URLs behind Caddy. Set it for packaged clients +# (e.g. Electron) or local dev that talks to a separate backend origin. # NEXT_PUBLIC_FASTAPI_BACKEND_URL=http://localhost:8000 -# Server-only. Internal backend URL used by Next.js server code. +# Server-only. Internal backend URL used by Next.js server code (RSC / route +# handlers). Cannot be a relative URL. SURFSENSE_BACKEND_INTERNAL_URL=http://backend:8000 +# ───────────────────────────────────────────────────────────────────────────── +# Runtime configuration (read at runtime by the server, no rebuild needed) +# ───────────────────────────────────────────────────────────────────────────── + +# Authentication method: LOCAL (email/password) or GOOGLE (OAuth). AUTH_TYPE=LOCAL +# Document parsing backend: DOCLING, LLAMACLOUD, etc. ETL_SERVICE=DOCLING +# Deployment mode: self-hosted or cloud. DEPLOYMENT_MODE=self-hosted -# Contact Form Vars (optional) +# ───────────────────────────────────────────────────────────────────────────── +# Build-time fallbacks for packaged clients (e.g. Electron) without a runtime +# config provider. Optional; Docker reads the plain runtime vars above first. +# ───────────────────────────────────────────────────────────────────────────── +# NEXT_PUBLIC_AUTH_TYPE=GOOGLE +# NEXT_PUBLIC_ETL_SERVICE=DOCLING +# NEXT_PUBLIC_DEPLOYMENT_MODE=self-hosted +# Overrides the app version shown in the UI (defaults to package.json version). +# NEXT_PUBLIC_APP_VERSION= + +# ───────────────────────────────────────────────────────────────────────────── +# Database (Contact Form, optional) +# ───────────────────────────────────────────────────────────────────────────── DATABASE_URL=postgresql://postgres:[YOUR-PASSWORD]@db.sdsf.supabase.co:5432/postgres -# PostHog analytics (optional, leave empty to disable) +# ───────────────────────────────────────────────────────────────────────────── +# PostHog analytics (optional, leave key empty to disable) +# ───────────────────────────────────────────────────────────────────────────── NEXT_PUBLIC_POSTHOG_KEY= +NEXT_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com +# ───────────────────────────────────────────────────────────────────────────── +# Zero cache (real-time sync). Leave unset in Docker to use the same-origin +# "/zero" endpoint behind Caddy. Set it for local dev or packaged clients. +# ───────────────────────────────────────────────────────────────────────────── +# NEXT_PUBLIC_ZERO_CACHE_URL=http://localhost:4848 + +# ───────────────────────────────────────────────────────────────────────────── # Cloudflare Turnstile CAPTCHA for anonymous chat abuse prevention # Get your site key from https://dash.cloudflare.com/ -> Turnstile +# ───────────────────────────────────────────────────────────────────────────── NEXT_PUBLIC_TURNSTILE_SITE_KEY= +# ───────────────────────────────────────────────────────────────────────────── # Google AdSense (optional, only enables ads on the /free hub page). # Publisher ID from your AdSense dashboard, e.g. ca-pub-XXXXXXXXXXXXXXXX. # Leave empty to disable ad rendering entirely. +# ───────────────────────────────────────────────────────────────────────────── NEXT_PUBLIC_GOOGLE_ADSENSE_CLIENT_ID= # Ad unit slot IDs from AdSense dashboard -> Ads -> By ad unit. # Leave empty to hide individual slots while keeping the script loaded. NEXT_PUBLIC_GOOGLE_ADSENSE_SLOT_FREE_HUB_IN_CONTENT= -NEXT_PUBLIC_GOOGLE_ADSENSE_SLOT_FREE_HUB_BEFORE_FAQ= \ No newline at end of file +NEXT_PUBLIC_GOOGLE_ADSENSE_SLOT_FREE_HUB_BEFORE_FAQ= + +# ───────────────────────────────────────────────────────────────────────────── +# Global announcement banner (e.g. planned downtime / maintenance notice). +# Set ENABLED to "true" to show the banner, and put the notice text in MESSAGE. +# ───────────────────────────────────────────────────────────────────────────── +NEXT_PUBLIC_GLOBAL_ANNOUNCEMENT_ENABLED=false +NEXT_PUBLIC_GLOBAL_ANNOUNCEMENT_MESSAGE= diff --git a/surfsense_web/app/(home)/layout.tsx b/surfsense_web/app/(home)/layout.tsx index 57dd9919e..c749b10f3 100644 --- a/surfsense_web/app/(home)/layout.tsx +++ b/surfsense_web/app/(home)/layout.tsx @@ -2,6 +2,7 @@ import { usePathname } from "next/navigation"; import { FooterNew } from "@/components/homepage/footer-new"; +import { GlobalAnnouncement } from "@/components/homepage/global-announcement"; import { Navbar } from "@/components/homepage/navbar"; export default function HomePageLayout({ children }: { children: React.ReactNode }) { @@ -15,6 +16,7 @@ export default function HomePageLayout({ children }: { children: React.ReactNode return (
+ {children} {!isAuthPage && } diff --git a/surfsense_web/components/auth/sign-in-button.tsx b/surfsense_web/components/auth/sign-in-button.tsx index b53988c5f..581e37603 100644 --- a/surfsense_web/components/auth/sign-in-button.tsx +++ b/surfsense_web/components/auth/sign-in-button.tsx @@ -1,6 +1,40 @@ "use client"; import Link from "next/link"; +import { useState } from "react"; +import { Button } from "@/components/ui/button"; +import { BUILD_TIME_AUTH_TYPE, buildBackendUrl } from "@/lib/env-config"; +import { trackLoginAttempt } from "@/lib/posthog/events"; +import { cn } from "@/lib/utils"; + +// Official Google "G" logo with brand colors +const GoogleLogo = ({ className }: { className?: string }) => ( + + Google logo + + + + + +); interface SignInButtonProps { /** @@ -12,17 +46,51 @@ interface SignInButtonProps { } export const SignInButton = ({ variant = "desktop" }: SignInButtonProps) => { + const isGoogleAuth = BUILD_TIME_AUTH_TYPE === "GOOGLE"; + const [isRedirecting, setIsRedirecting] = useState(false); + + const handleGoogleLogin = () => { + if (isRedirecting) return; + setIsRedirecting(true); + trackLoginAttempt("google"); + window.location.href = buildBackendUrl("/auth/google/authorize-redirect"); + }; + const getClassName = () => { if (variant === "desktop") { - return "hidden rounded-full bg-black px-8 py-2 text-sm font-bold text-white shadow-[0px_-2px_0px_0px_rgba(255,255,255,0.4)_inset] md:block dark:bg-white dark:text-black"; + return isGoogleAuth + ? "hidden rounded-full border border-white bg-white px-5 py-2 text-sm font-medium text-[#1f1f1f] shadow-sm hover:bg-zinc-100 hover:text-[#1f1f1f] md:flex dark:border-white" + : "hidden rounded-full bg-black px-8 py-2 text-sm font-bold text-white shadow-[0px_-2px_0px_0px_rgba(255,255,255,0.4)_inset] md:block dark:bg-white dark:text-black"; } if (variant === "compact") { - return "rounded-full bg-black px-6 py-1.5 text-sm font-bold text-white shadow-[0px_-2px_0px_0px_rgba(255,255,255,0.4)_inset] dark:bg-white dark:text-black"; + return isGoogleAuth + ? "rounded-full border border-white bg-white px-4 py-1.5 text-sm font-medium text-[#1f1f1f] shadow-sm hover:bg-zinc-100 hover:text-[#1f1f1f] dark:border-white" + : "rounded-full bg-black px-6 py-1.5 text-sm font-bold text-white shadow-[0px_-2px_0px_0px_rgba(255,255,255,0.4)_inset] dark:bg-white dark:text-black"; } // mobile - return "w-full rounded-lg bg-black px-8 py-2 font-medium text-white shadow-[0px_-2px_0px_0px_rgba(255,255,255,0.4)_inset] dark:bg-white dark:text-black text-center touch-manipulation"; + return isGoogleAuth + ? "w-full rounded-lg border border-white bg-white px-8 py-2.5 font-medium text-[#1f1f1f] shadow-sm hover:bg-zinc-100 hover:text-[#1f1f1f] dark:border-white touch-manipulation" + : "w-full rounded-lg bg-black px-8 py-2 font-medium text-white shadow-[0px_-2px_0px_0px_rgba(255,255,255,0.4)_inset] dark:bg-white dark:text-black text-center touch-manipulation"; }; + if (isGoogleAuth) { + return ( + + ); + } + return ( Sign In diff --git a/surfsense_web/components/homepage/global-announcement.tsx b/surfsense_web/components/homepage/global-announcement.tsx new file mode 100644 index 000000000..212be42c7 --- /dev/null +++ b/surfsense_web/components/homepage/global-announcement.tsx @@ -0,0 +1,27 @@ +import { IconInfoCircle } from "@tabler/icons-react"; +import { GLOBAL_ANNOUNCEMENT_ENABLED, GLOBAL_ANNOUNCEMENT_MESSAGE } from "@/lib/env-config"; + +/** + * Small, site-wide banner for planned downtime / maintenance notices. + * + * Controlled entirely through build-time env vars so it can be toggled from + * Vercel without a code change: + * - NEXT_PUBLIC_GLOBAL_ANNOUNCEMENT_ENABLED ("true" to show) + * - NEXT_PUBLIC_GLOBAL_ANNOUNCEMENT_MESSAGE (the copy to display) + */ +export function GlobalAnnouncement() { + const message = GLOBAL_ANNOUNCEMENT_MESSAGE.trim(); + + if (!GLOBAL_ANNOUNCEMENT_ENABLED || !message) { + return null; + } + + return ( +
+
+ + {message} +
+
+ ); +} diff --git a/surfsense_web/components/homepage/hero-section.tsx b/surfsense_web/components/homepage/hero-section.tsx index 9c9139b83..0f3bfe1aa 100644 --- a/surfsense_web/components/homepage/hero-section.tsx +++ b/surfsense_web/components/homepage/hero-section.tsx @@ -37,8 +37,38 @@ import { getAssetLabel, usePrimaryDownload, } from "@/lib/desktop-download-utils"; +import { BUILD_TIME_AUTH_TYPE, buildBackendUrl } from "@/lib/env-config"; +import { trackLoginAttempt } from "@/lib/posthog/events"; import { cn } from "@/lib/utils"; +const GoogleLogo = ({ className }: { className?: string }) => ( + + Google logo + + + + + +); + type HeroUseCase = { id: string; title: string; @@ -284,6 +314,31 @@ export function HeroSection() { } function GetStartedButton() { + const isGoogleAuth = BUILD_TIME_AUTH_TYPE === "GOOGLE"; + const [isRedirecting, setIsRedirecting] = useState(false); + + const handleGoogleLogin = () => { + if (isRedirecting) return; + setIsRedirecting(true); + trackLoginAttempt("google"); + window.location.href = buildBackendUrl("/auth/google/authorize-redirect"); + }; + + if (isGoogleAuth) { + return ( + + ); + } + return (