diff --git a/public/llms.txt b/public/llms.txt new file mode 100644 index 0000000..7ca0381 --- /dev/null +++ b/public/llms.txt @@ -0,0 +1,32 @@ +# Tech for Palestine + +> Tech for Palestine is a 501(c)(3) nonprofit (EIN 99-3441367) that incubates and scales tech and advocacy projects for Palestinian liberation. It is a coalition of thousands of founders, engineers, product marketers, investors, and other professionals in the tech industry supporting Palestinian liberation. + +Tech for Palestine's mission is to harness technology and human innovation for a free and truly sovereign Palestine. It operates primarily as an incubator: it provides mentorship, tech volunteers, marketing support, and community connections to help early-stage Palestinian-advocacy projects start, grow, and scale. Tech for Palestine is not itself a single product — it is the organization behind an independent portfolio of tools (news coverage, boycott and accountability tools, protest-finding tools, datasets, and more) built and run by the movement. + +## Key pages + +- [About](https://techforpalestine.org/about): Mission, founder, and organizational background. +- [Donate](https://techforpalestine.org/donate): Support Tech for Palestine's work; donations are generally tax-deductible in the US. +- [Incubator](https://techforpalestine.org/incubator): How the T4P Incubator supports early-stage advocacy projects with mentorship, volunteers, and funding. +- [Projects](https://techforpalestine.org/projects): Directory of active Incubator projects. +- [Ideas](https://techforpalestine.org/ideas): Project ideas available for advocates to pick up and lead. +- [Membership](https://techforpalestine.org/membership): Paid membership program — suggested dues, fee waivers, and benefits. +- [Volunteer](https://techforpalestine.org/volunteer): How to volunteer skills and time to Incubator projects. +- [Mentorship](https://techforpalestine.org/mentorship): How to become a mentor for Incubator projects. +- [Get Involved](https://techforpalestine.org/get-involved): Overview of every way to contribute — volunteering, mentoring, membership, and building. +- [Events](https://techforpalestine.org/events): Community webinars, workshops, and in-person gatherings. +- [FAQ](https://techforpalestine.org/faq): Answers to common questions about T4P's mission and programs. +- [Team](https://techforpalestine.org/team): Board and staff leadership. +- [Media](https://techforpalestine.org/media): Press coverage, interviews, and brand/press-kit assets. +- [Tools](https://techforpalestine.org/tools): Directory of Palestinian-advocacy tools built by the movement. +- [Entrepreneurs for Palestine](https://techforpalestine.org/e4p): A global community of founders and CEOs pledging to steer hiring, sourcing, and fundraising in support of Palestinian liberation. +- [Legal & Financial Notice](https://techforpalestine.org/legal): 501(c)(3) status, EIN, and financial transparency. + +## Organization facts + +- Legal name: Tech for Palestine +- Entity type: 501(c)(3) nonprofit +- EIN: 99-3441367 +- Registered address: 548 Market St #266950, San Francisco, CA 94104-5401, US +- Website: https://techforpalestine.org diff --git a/public/robots.txt b/public/robots.txt index e6cbad9..984128d 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -1,4 +1,28 @@ User-agent: * Allow: / +# Explicit allow rules for major AI crawlers/answer engines (redundant with +# the wildcard above, but keeps intent explicit if narrower rules are ever +# added for other bots). +User-agent: GPTBot +Allow: / + +User-agent: ChatGPT-User +Allow: / + +User-agent: OAI-SearchBot +Allow: / + +User-agent: ClaudeBot +Allow: / + +User-agent: Claude-User +Allow: / + +User-agent: PerplexityBot +Allow: / + +User-agent: Google-Extended +Allow: / + Sitemap: https://techforpalestine.org/sitemap-index.xml diff --git a/src/components/events/EventsNew.tsx b/src/components/events/EventsNew.tsx index 1ca5342..d469431 100644 --- a/src/components/events/EventsNew.tsx +++ b/src/components/events/EventsNew.tsx @@ -163,12 +163,12 @@ function HeroEvent({ event }: HeroEventProps) { {/* Content side */}
{/* Date block */} -
-

{day}

-

+

-
+ + {/* Title */}

{event.title}

@@ -232,12 +232,12 @@ function LineupTile({ event }: LineupTileProps) { {/* Content */}
{/* Date */} -
-

{day}

-

+

-
+ + {/* Title */}

{event.title}

@@ -311,7 +311,9 @@ function PastEventCard({ event }: { event: EventItem }) {

{event.title}

- {full} + {event.time && {event.time}} {event.location && ( {event.location} diff --git a/src/components/home/FooterSection.astro b/src/components/home/FooterSection.astro index da1fe49..7d6df79 100644 --- a/src/components/home/FooterSection.astro +++ b/src/components/home/FooterSection.astro @@ -81,6 +81,7 @@ const socials: { name: string; url: string; icon: string }[] = [ alt="Tech for Palestine" width="352" height="112" + loading="lazy" class="h-14 w-auto" /> @@ -106,6 +107,7 @@ const socials: { name: string; url: string; icon: string }[] = [ {s.name} ) : ( diff --git a/src/components/membership/MembershipDues.tsx b/src/components/membership/MembershipDues.tsx index 3a05120..cb98242 100644 --- a/src/components/membership/MembershipDues.tsx +++ b/src/components/membership/MembershipDues.tsx @@ -29,30 +29,41 @@ function QgivEmbed() { } export default function MembershipDues() { - const [showCalculator] = useState(() => { + // Default to the no-calculator variant so this renders identically during + // SSR (no window/localStorage access) before the A/B assignment runs below. + const [showCalculator, setShowCalculator] = useState(false); + + useEffect(() => { const urlParams = new URLSearchParams(window.location.search); const urlParam = urlParams.get("calculator"); - if (urlParam === "yes") return true; - if (urlParam === "no") return false; - const stored = localStorage.getItem("membership_ab_variant"); - if (stored === "Calculator") return true; - if (stored === "No Calculator") return false; + let assigned: boolean; + if (urlParam === "yes") { + assigned = true; + } else if (urlParam === "no") { + assigned = false; + } else { + const stored = localStorage.getItem("membership_ab_variant"); + if (stored === "Calculator") { + assigned = true; + } else if (stored === "No Calculator") { + assigned = false; + } else { + assigned = Math.random() < 0.5; + localStorage.setItem("membership_ab_variant", assigned ? "Calculator" : "No Calculator"); + } + } - const assigned = Math.random() < 0.5; - localStorage.setItem("membership_ab_variant", assigned ? "Calculator" : "No Calculator"); - return assigned; - }); + setShowCalculator(assigned); - useEffect(() => { if (typeof window.plausible !== "undefined") { window.plausible("Membership Page", { props: { - membership_variant: showCalculator ? "Calculator" : "No Calculator", + membership_variant: assigned ? "Calculator" : "No Calculator", }, }); } - }, [showCalculator]); + }, []); return (
diff --git a/src/layouts/HomeLayout.astro b/src/layouts/HomeLayout.astro index 4e0e233..bfff53c 100644 --- a/src/layouts/HomeLayout.astro +++ b/src/layouts/HomeLayout.astro @@ -12,6 +12,7 @@ interface Props { description?: string; image?: string; noindex?: boolean; + canonicalUrl?: string; } const { @@ -19,18 +20,27 @@ const { description = "T4P is an incubator for Palestine advocacy projects.", image = "https://techforpalestine.org/t4p-social-logo.png", noindex = false, + canonicalUrl: canonicalUrlOverride, } = Astro.props; const membershipLive = getEnv("MEMBERSHIP_LIVE", Astro.locals) === "true"; -const canonicalUrl = new URL( - Astro.url.pathname, - Astro.site || "https://techforpalestine.org" -).toString(); +// Site-wide internal links never use a trailing slash, so the canonical tag +// shouldn't either — otherwise /page and /page/ resolve to the same content +// with two different self-referential canonicals. +const normalizedPathname = + Astro.url.pathname.length > 1 && Astro.url.pathname.endsWith("/") + ? Astro.url.pathname.slice(0, -1) + : Astro.url.pathname; + +const canonicalUrl = + canonicalUrlOverride || + new URL(normalizedPathname, Astro.site || "https://techforpalestine.org").toString(); const organizationSchema = { "@context": "https://schema.org", "@type": "NonprofitOrganization", + "@id": "https://techforpalestine.org/#organization", name: "Tech for Palestine", url: "https://techforpalestine.org", logo: "https://techforpalestine.org/t4p-social-logo.png", diff --git a/src/pages/about-new.astro b/src/pages/about-new.astro index 5240883..e348fbe 100644 --- a/src/pages/about-new.astro +++ b/src/pages/about-new.astro @@ -12,9 +12,10 @@ const founderSchema = { "@type": "Person", name: "Paul Biggar", jobTitle: "Founder", + image: "https://techforpalestine.org/paul-biggar.webp", worksFor: { "@type": "NonprofitOrganization", - name: "Tech for Palestine", + "@id": "https://techforpalestine.org/#organization", }, sameAs: ["https://blog.paulbiggar.com/", "https://circleci.com", "https://darklang.com"], }; @@ -45,7 +46,10 @@ const founderSchema = { >

- Technology should disrupt the status quo — not serve it. + Tech for Palestine is a 501(c)(3) nonprofit that incubates and scales tech and + advocacy projects for Palestinian liberation. Technology should disrupt the status quo — not serve it.

For decades, the narrative about Palestine has been shaped by selective historical diff --git a/src/pages/contact-new.astro b/src/pages/contact-new.astro index c94d7dd..7364487 100644 --- a/src/pages/contact-new.astro +++ b/src/pages/contact-new.astro @@ -15,9 +15,13 @@ const membershipLive = getEnv("MEMBERSHIP_LIVE", Astro.locals) === "true"; type="application/ld+json" set:html={JSON.stringify({ "@context": "https://schema.org", - "@type": "ContactPoint", - contactType: "customer support", - email: "contact@techforpalestine.org", + "@type": "NonprofitOrganization", + "@id": "https://techforpalestine.org/#organization", + contactPoint: { + "@type": "ContactPoint", + contactType: "customer support", + email: "contact@techforpalestine.org", + }, })} /> @@ -30,11 +34,17 @@ const membershipLive = getEnv("MEMBERSHIP_LIVE", Astro.locals) === "true";

Contact Us

Have a question, media inquiry, or want to request an endorsement? We'd love to hear - from you. + from you. Tech for Palestine is a volunteer-powered 501(c)(3) nonprofit, so most inboxes + below are staffed part-time — we aim to respond to general and media inquiries within + 5-7 business days, and endorsement requests follow the same timeline. If your question + is about how to get involved, donate, or join the Incubator, check our FAQ first — it covers the most common questions we receive.

-
+ diff --git a/src/pages/donate-2-new.astro b/src/pages/donate-2-new.astro index a36d026..b933cc2 100644 --- a/src/pages/donate-2-new.astro +++ b/src/pages/donate-2-new.astro @@ -9,9 +9,10 @@ const membershipLive = getEnv("MEMBERSHIP_LIVE", Astro.locals) === "true"; ---