mirror of
https://github.com/Luchexx/wacrm.git
synced 2026-11-02 09:19:51 +00:00
feat(landing): open-source + Hostinger deploy section
Adds a #self-host landing section with two cards — one linking to the GitHub repo (fork / clone) and one recommending Hostinger VPS for deploying the template. Also surfaces the GitHub link from the nav (desktop icon + mobile drawer) and the footer. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5a2d11ea64
commit
dd65e532a1
@ -6,6 +6,7 @@ import { FeaturesGrid } from '@/components/landing/features-grid'
|
|||||||
import { HowItWorks } from '@/components/landing/how-it-works'
|
import { HowItWorks } from '@/components/landing/how-it-works'
|
||||||
import { FeatureSpotlight } from '@/components/landing/feature-spotlight'
|
import { FeatureSpotlight } from '@/components/landing/feature-spotlight'
|
||||||
import { FAQ } from '@/components/landing/faq'
|
import { FAQ } from '@/components/landing/faq'
|
||||||
|
import { OpenSource } from '@/components/landing/open-source'
|
||||||
import { CtaBanner } from '@/components/landing/cta-banner'
|
import { CtaBanner } from '@/components/landing/cta-banner'
|
||||||
import { Footer } from '@/components/landing/footer'
|
import { Footer } from '@/components/landing/footer'
|
||||||
import { InboxMock } from '@/components/landing/mock/inbox-mock'
|
import { InboxMock } from '@/components/landing/mock/inbox-mock'
|
||||||
@ -105,6 +106,8 @@ export default function LandingPage() {
|
|||||||
visual={<AnalyticsMock />}
|
visual={<AnalyticsMock />}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<OpenSource />
|
||||||
|
|
||||||
<FAQ />
|
<FAQ />
|
||||||
|
|
||||||
<CtaBanner />
|
<CtaBanner />
|
||||||
|
|||||||
@ -5,7 +5,7 @@ export function Footer() {
|
|||||||
const year = new Date().getFullYear()
|
const year = new Date().getFullYear()
|
||||||
return (
|
return (
|
||||||
<footer className="border-t border-slate-800 bg-slate-950">
|
<footer className="border-t border-slate-800 bg-slate-950">
|
||||||
<div className="mx-auto grid w-full max-w-7xl grid-cols-2 gap-8 px-6 py-12 sm:grid-cols-4">
|
<div className="mx-auto grid w-full max-w-7xl grid-cols-2 gap-8 px-6 py-12 sm:grid-cols-5">
|
||||||
<div className="col-span-2 sm:col-span-2">
|
<div className="col-span-2 sm:col-span-2">
|
||||||
<Link href="/" className="flex items-center gap-2" aria-label="WaCRM home">
|
<Link href="/" className="flex items-center gap-2" aria-label="WaCRM home">
|
||||||
<span className="flex h-8 w-8 items-center justify-center rounded-lg bg-emerald-500">
|
<span className="flex h-8 w-8 items-center justify-center rounded-lg bg-emerald-500">
|
||||||
@ -28,6 +28,23 @@ export function Footer() {
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<FooterColumn
|
||||||
|
title="Open source"
|
||||||
|
links={[
|
||||||
|
{
|
||||||
|
href: 'https://github.com/ArnasDon/wacrm',
|
||||||
|
label: 'GitHub repo',
|
||||||
|
external: true,
|
||||||
|
},
|
||||||
|
{ href: '#self-host', label: 'Self-host' },
|
||||||
|
{
|
||||||
|
href: 'https://www.hostinger.com/vps-hosting',
|
||||||
|
label: 'Deploy on Hostinger',
|
||||||
|
external: true,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
<FooterColumn
|
<FooterColumn
|
||||||
title="Account"
|
title="Account"
|
||||||
links={[
|
links={[
|
||||||
@ -53,7 +70,7 @@ function FooterColumn({
|
|||||||
links,
|
links,
|
||||||
}: {
|
}: {
|
||||||
title: string
|
title: string
|
||||||
links: { href: string; label: string }[]
|
links: { href: string; label: string; external?: boolean }[]
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -61,7 +78,19 @@ function FooterColumn({
|
|||||||
{title}
|
{title}
|
||||||
</h4>
|
</h4>
|
||||||
<ul className="mt-4 space-y-2.5">
|
<ul className="mt-4 space-y-2.5">
|
||||||
{links.map((l) => (
|
{links.map((l) =>
|
||||||
|
l.external ? (
|
||||||
|
<li key={l.href}>
|
||||||
|
<a
|
||||||
|
href={l.href}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="text-sm text-slate-400 transition-colors hover:text-white"
|
||||||
|
>
|
||||||
|
{l.label}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
) : (
|
||||||
<li key={l.href}>
|
<li key={l.href}>
|
||||||
<Link
|
<Link
|
||||||
href={l.href}
|
href={l.href}
|
||||||
@ -70,7 +99,8 @@ function FooterColumn({
|
|||||||
{l.label}
|
{l.label}
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
))}
|
),
|
||||||
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
18
src/components/landing/github-icon.tsx
Normal file
18
src/components/landing/github-icon.tsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import type { SVGProps } from 'react'
|
||||||
|
|
||||||
|
export function GithubIcon(props: SVGProps<SVGSVGElement>) {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="currentColor"
|
||||||
|
aria-hidden="true"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
clipRule="evenodd"
|
||||||
|
d="M12 .5C5.37.5 0 5.87 0 12.5c0 5.3 3.44 9.8 8.21 11.38.6.11.82-.26.82-.58 0-.28-.01-1.04-.02-2.04-3.34.72-4.04-1.61-4.04-1.61-.55-1.39-1.34-1.76-1.34-1.76-1.09-.74.08-.73.08-.73 1.2.08 1.84 1.24 1.84 1.24 1.07 1.84 2.81 1.31 3.5 1 .11-.78.42-1.31.76-1.61-2.67-.3-5.48-1.34-5.48-5.97 0-1.32.47-2.39 1.24-3.23-.13-.3-.54-1.53.11-3.18 0 0 1.01-.32 3.3 1.23.96-.27 1.98-.4 3-.41 1.02.01 2.04.14 3 .41 2.29-1.55 3.3-1.23 3.3-1.23.65 1.65.24 2.88.12 3.18.77.84 1.24 1.91 1.24 3.23 0 4.64-2.81 5.67-5.49 5.96.43.37.81 1.1.81 2.22 0 1.6-.01 2.89-.01 3.29 0 .32.22.7.83.58C20.57 22.29 24 17.8 24 12.5 24 5.87 18.63.5 12 .5Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -5,6 +5,7 @@ import { useEffect, useState } from 'react'
|
|||||||
import { MessageSquare, Menu, X } from 'lucide-react'
|
import { MessageSquare, Menu, X } from 'lucide-react'
|
||||||
import { createClient } from '@/lib/supabase/client'
|
import { createClient } from '@/lib/supabase/client'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
import { GithubIcon } from './github-icon'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Landing-page top nav. Client component because we need to flip the
|
* Landing-page top nav. Client component because we need to flip the
|
||||||
@ -17,9 +18,12 @@ type AuthState = 'pending' | 'signed-in' | 'signed-out'
|
|||||||
const LINKS = [
|
const LINKS = [
|
||||||
{ href: '#features', label: 'Features' },
|
{ href: '#features', label: 'Features' },
|
||||||
{ href: '#how-it-works', label: 'How it works' },
|
{ href: '#how-it-works', label: 'How it works' },
|
||||||
|
{ href: '#self-host', label: 'Self-host' },
|
||||||
{ href: '#faq', label: 'FAQ' },
|
{ href: '#faq', label: 'FAQ' },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const REPO_URL = 'https://github.com/ArnasDon/wacrm'
|
||||||
|
|
||||||
export function LandingNav() {
|
export function LandingNav() {
|
||||||
const [auth, setAuth] = useState<AuthState>('pending')
|
const [auth, setAuth] = useState<AuthState>('pending')
|
||||||
const [scrolled, setScrolled] = useState(false)
|
const [scrolled, setScrolled] = useState(false)
|
||||||
@ -75,6 +79,15 @@ export function LandingNav() {
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div className="hidden items-center gap-2 md:flex">
|
<div className="hidden items-center gap-2 md:flex">
|
||||||
|
<a
|
||||||
|
href={REPO_URL}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
aria-label="View source on GitHub"
|
||||||
|
className="flex h-9 w-9 items-center justify-center rounded-lg text-slate-300 transition-colors hover:bg-slate-800 hover:text-white"
|
||||||
|
>
|
||||||
|
<GithubIcon className="h-4 w-4" />
|
||||||
|
</a>
|
||||||
<NavCtas auth={auth} />
|
<NavCtas auth={auth} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -101,6 +114,16 @@ export function LandingNav() {
|
|||||||
{l.label}
|
{l.label}
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
|
<a
|
||||||
|
href={REPO_URL}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
onClick={() => setMobileOpen(false)}
|
||||||
|
className="flex items-center gap-2 rounded-md px-3 py-2 text-sm text-slate-300 hover:bg-slate-800 hover:text-white"
|
||||||
|
>
|
||||||
|
<GithubIcon className="h-4 w-4" />
|
||||||
|
GitHub
|
||||||
|
</a>
|
||||||
<div className="mt-2 flex flex-col gap-2 border-t border-slate-800 pt-3">
|
<div className="mt-2 flex flex-col gap-2 border-t border-slate-800 pt-3">
|
||||||
<NavCtas auth={auth} mobile />
|
<NavCtas auth={auth} mobile />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
67
src/components/landing/open-source.tsx
Normal file
67
src/components/landing/open-source.tsx
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import { ArrowRight, Server } from 'lucide-react'
|
||||||
|
import { Section, SectionHeader } from './section'
|
||||||
|
import { GithubIcon } from './github-icon'
|
||||||
|
|
||||||
|
const REPO_URL = 'https://github.com/ArnasDon/wacrm'
|
||||||
|
const HOSTINGER_URL = 'https://www.hostinger.com/vps-hosting'
|
||||||
|
|
||||||
|
export function OpenSource() {
|
||||||
|
return (
|
||||||
|
<Section id="self-host">
|
||||||
|
<SectionHeader
|
||||||
|
eyebrow="Open source"
|
||||||
|
title="Fork it, brand it, host it"
|
||||||
|
description="WaCRM is a template you can take and make your own. Grab the source on GitHub and self-host — we recommend Hostinger for a one-click Node.js VPS."
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="mx-auto grid max-w-5xl grid-cols-1 gap-5 md:grid-cols-2">
|
||||||
|
<a
|
||||||
|
href={REPO_URL}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="group flex flex-col rounded-xl border border-slate-800 bg-slate-900/40 p-6 transition-colors hover:border-slate-700 hover:bg-slate-900/70"
|
||||||
|
>
|
||||||
|
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-slate-800 text-slate-100">
|
||||||
|
<GithubIcon className="h-5 w-5" />
|
||||||
|
</div>
|
||||||
|
<h3 className="mt-4 text-base font-semibold text-white">
|
||||||
|
Source on GitHub
|
||||||
|
</h3>
|
||||||
|
<p className="mt-1.5 text-sm leading-relaxed text-slate-400">
|
||||||
|
Clone or fork the repository, tweak the code, ship your own build.
|
||||||
|
MIT-style freedom with the full CRM underneath.
|
||||||
|
</p>
|
||||||
|
<span className="mt-5 inline-flex items-center gap-1.5 text-sm font-medium text-emerald-400 transition-colors group-hover:text-emerald-300">
|
||||||
|
ArnasDon/wacrm
|
||||||
|
<ArrowRight className="h-4 w-4 transition-transform group-hover:translate-x-0.5" />
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href={HOSTINGER_URL}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="group flex flex-col rounded-xl border border-emerald-500/20 bg-slate-900/40 p-6 transition-colors hover:border-emerald-500/40 hover:bg-slate-900/70"
|
||||||
|
>
|
||||||
|
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-emerald-500/10 text-emerald-400">
|
||||||
|
<Server className="h-5 w-5" />
|
||||||
|
</div>
|
||||||
|
<h3 className="mt-4 flex flex-wrap items-center gap-2 text-base font-semibold text-white">
|
||||||
|
Deploy on Hostinger
|
||||||
|
<span className="rounded-full bg-emerald-500/10 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wider text-emerald-400">
|
||||||
|
Recommended
|
||||||
|
</span>
|
||||||
|
</h3>
|
||||||
|
<p className="mt-1.5 text-sm leading-relaxed text-slate-400">
|
||||||
|
Best fit for this template — spin up a Node.js VPS, point it at
|
||||||
|
your forked repo, and WaCRM is live in a few minutes.
|
||||||
|
</p>
|
||||||
|
<span className="mt-5 inline-flex items-center gap-1.5 text-sm font-medium text-emerald-400 transition-colors group-hover:text-emerald-300">
|
||||||
|
Get Hostinger VPS
|
||||||
|
<ArrowRight className="h-4 w-4 transition-transform group-hover:translate-x-0.5" />
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
)
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user