Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/layouts/HomeLayout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ interface Props {
image?: string;
noindex?: boolean;
canonicalUrl?: string;
// Extra JSON-LD properties to merge into the sitewide NonprofitOrganization
// node (e.g. a page-specific contactPoint or potentialAction). Pages must
// not emit their own NonprofitOrganization script sharing the same @id —
// separate <script> tags aren't reliably merged by structured-data parsers.
organizationSchemaExtra?: Record<string, unknown>;
}

const {
Expand All @@ -21,6 +26,7 @@ const {
image = "https://techforpalestine.org/t4p-social-logo.png",
noindex = false,
canonicalUrl: canonicalUrlOverride,
organizationSchemaExtra,
} = Astro.props;

const membershipLive = getEnv("MEMBERSHIP_LIVE", Astro.locals) === "true";
Expand All @@ -41,6 +47,7 @@ const organizationSchema = {
"@context": "https://schema.org",
"@type": "NonprofitOrganization",
"@id": "https://techforpalestine.org/#organization",
...organizationSchemaExtra,
name: "Tech for Palestine",
url: "https://techforpalestine.org",
logo: "https://techforpalestine.org/t4p-social-logo.png",
Expand Down
4 changes: 4 additions & 0 deletions src/pages/about-new.astro
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ const founderSchema = {
src="/images/new-homepage/why/paul.webp"
alt="Paul Biggar, founder of Tech for Palestine"
class="w-full rounded-[20px] border border-butter object-cover"
width="1254"
height="1254"
loading="lazy"
decoding="async"
/>
Expand Down Expand Up @@ -301,6 +303,8 @@ const founderSchema = {
src="/gaza-children-playing-ocean.jpg"
alt="Palestinian children playing joyfully in ocean waves at sunset on Gaza's Mediterranean coastline"
class="aspect-[5/2] w-full rounded-lg object-cover"
width="900"
height="603"
loading="lazy"
decoding="async"
/>
Expand Down
26 changes: 11 additions & 15 deletions src/pages/contact-new.astro
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,14 @@ const membershipLive = getEnv("MEMBERSHIP_LIVE", Astro.locals) === "true";
title="Contact Us | Tech for Palestine"
description="Get in touch with Tech for Palestine — general questions, media inquiries, or request an endorsement for your campaign."
noindex={true}
organizationSchemaExtra={{
contactPoint: {
"@type": "ContactPoint",
contactType: "customer support",
email: "contact@techforpalestine.org",
},
}}
>
<Fragment slot="head">
<script
type="application/ld+json"
set:html={JSON.stringify({
"@context": "https://schema.org",
"@type": "NonprofitOrganization",
"@id": "https://techforpalestine.org/#organization",
contactPoint: {
"@type": "ContactPoint",
contactType: "customer support",
email: "contact@techforpalestine.org",
},
})}
/>
</Fragment>
<HomeNavbar membershipLive={membershipLive} alwaysVisible />
<main class="pt-20">
<section class="bg-sand px-6 py-14 min-[810px]:px-10 min-[810px]:py-20">
Expand All @@ -48,6 +40,7 @@ const membershipLive = getEnv("MEMBERSHIP_LIVE", Astro.locals) === "true";
<div class="page-animate rounded-xl border border-butter bg-cream p-8">
<div class="mb-4 inline-flex h-12 w-12 items-center justify-center rounded-lg bg-sand">
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
Expand Down Expand Up @@ -79,6 +72,7 @@ const membershipLive = getEnv("MEMBERSHIP_LIVE", Astro.locals) === "true";
<div class="page-animate rounded-xl border border-butter bg-cream p-8">
<div class="mb-4 inline-flex h-12 w-12 items-center justify-center rounded-lg bg-sand">
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
Expand Down Expand Up @@ -110,6 +104,7 @@ const membershipLive = getEnv("MEMBERSHIP_LIVE", Astro.locals) === "true";
<div class="page-animate rounded-xl border border-butter bg-cream p-8">
<div class="mb-4 inline-flex h-12 w-12 items-center justify-center rounded-lg bg-sand">
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
Expand Down Expand Up @@ -140,6 +135,7 @@ const membershipLive = getEnv("MEMBERSHIP_LIVE", Astro.locals) === "true";
<div class="page-animate rounded-xl border border-butter bg-cream p-8">
<div class="mb-4 inline-flex h-12 w-12 items-center justify-center rounded-lg bg-sand">
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
Expand Down
25 changes: 9 additions & 16 deletions src/pages/donate-2-new.astro
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,16 @@ const membershipLive = getEnv("MEMBERSHIP_LIVE", Astro.locals) === "true";
description="Alternate donation form for Tech for Palestine. Use this page if the primary donate form doesn't load in your browser."
noindex={true}
canonicalUrl="https://techforpalestine.org/donate"
organizationSchemaExtra={{
potentialAction: {
"@type": "DonateAction",
name: "Donate to Tech for Palestine",
description:
"Your donation helps us hire professionals, strengthen existing projects, and launch new initiatives for a free Palestine.",
target: "https://techforpalestine.org/donate-2-new",
},
}}
>
<Fragment slot="head">
<script
type="application/ld+json"
set:html={JSON.stringify({
"@context": "https://schema.org",
"@type": "NonprofitOrganization",
"@id": "https://techforpalestine.org/#organization",
potentialAction: {
"@type": "DonateAction",
name: "Donate to Tech for Palestine",
description:
"Your donation helps us hire professionals, strengthen existing projects, and launch new initiatives for a free Palestine.",
},
})}
/>
</Fragment>
<HomeNavbar membershipLive={membershipLive} alwaysVisible />

<main class="pt-20">
Expand Down
45 changes: 25 additions & 20 deletions src/pages/donate-new.astro
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,26 @@ import HomeNavbar from "../components/home/HomeNavbar.astro";
const membershipLive = getEnv("MEMBERSHIP_LIVE", Astro.locals) === "true";
const country = Astro.request.headers.get("cf-ipcountry") || "UNKNOWN";
const isUK = country === "GB";
// Server-rendered fallback variant (no A/B randomization) so the donation
// form is present in the initial HTML for non-JS clients and crawlers —
// the client-side A/B test below still overrides this for real visitors.
const defaultFormId = isUK ? "form-validaid-link" : "form-qgiv-link";
---

<HomeLayout
title="Donate | Tech for Palestine"
description="Support Tech for Palestine. Your donation helps us strengthen existing projects and launch new initiatives for a free Palestine."
title="Donate to Tech for Palestine | Support Our Work"
description="Support Tech for Palestine, a 501(c)(3) nonprofit. Your donation helps us strengthen existing projects and launch new initiatives for a free Palestine."
noindex={true}
organizationSchemaExtra={{
potentialAction: {
"@type": "DonateAction",
name: "Donate to Tech for Palestine",
description:
"Your donation helps us strengthen existing projects and launch new initiatives for a free Palestine.",
target: "https://techforpalestine.org/donate-new",
},
}}
>
<Fragment slot="head">
<script
type="application/ld+json"
set:html={JSON.stringify({
"@context": "https://schema.org",
"@type": "NonprofitOrganization",
"@id": "https://techforpalestine.org/#organization",
potentialAction: {
"@type": "DonateAction",
name: "Donate to Tech for Palestine",
description:
"Your donation helps us strengthen existing projects and launch new initiatives for a free Palestine.",
},
})}
/>
</Fragment>
<HomeNavbar membershipLive={membershipLive} alwaysVisible />

<main class="pt-20">
Expand Down Expand Up @@ -75,7 +72,7 @@ const isUK = country === "GB";
</div>

<!-- Variant B Non-UK: Qgiv + link to ValidAid -->
<div id="form-qgiv-link" hidden>
<div id="form-qgiv-link" hidden={defaultFormId !== "form-qgiv-link"}>
<p class="ts-body-small mb-4 text-ink-secondary">
If you are in the UK, <a
href="?variant=validaid"
Expand All @@ -94,7 +91,7 @@ const isUK = country === "GB";
</div>

<!-- Variant B UK: ValidAid + link to Qgiv -->
<div id="form-validaid-link" hidden>
<div id="form-validaid-link" hidden={defaultFormId !== "form-validaid-link"}>
<p class="ts-body-small mb-4 text-ink-secondary">
Not in the UK? <a
href="?variant=qgiv"
Expand Down Expand Up @@ -309,6 +306,14 @@ const isUK = country === "GB";
}
}

// One variant is server-rendered visible (non-JS fallback) regardless of
// which variant this client ends up assigned to, so hide all three before
// revealing the chosen one to avoid showing two forms at once.
["form-qgiv-only", "form-qgiv-link", "form-validaid-link"].forEach((id) => {
const el = document.getElementById(id);
if (el) el.style.display = "none";
});

const targetForm = document.getElementById(formToShow);
if (targetForm) {
targetForm.style.display = "block";
Expand Down
2 changes: 2 additions & 0 deletions src/pages/e4p-new.astro
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,8 @@ const peopleSchema = [...testimonials, ...founders].map((person) => ({
src={f.image}
alt={f.name}
class="founder-avatar mb-4 h-20 w-20 rounded-full object-cover min-[810px]:h-24 min-[810px]:w-24"
width="96"
height="96"
loading="lazy"
decoding="async"
/>
Expand Down
17 changes: 13 additions & 4 deletions src/pages/get-involved-new.astro
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ const membershipLive = getEnv("MEMBERSHIP_LIVE", Astro.locals) === "true";
const webPageSchema = {
"@context": "https://schema.org",
"@type": "WebPage",
name: "Get Involved | Tech for Palestine",
"@id": "https://techforpalestine.org/get-involved-new",
url: "https://techforpalestine.org/get-involved-new",
name: "Get Involved with Tech for Palestine | Volunteer & More",
description:
"Join our mission-driven community building tools and projects for Palestinian liberation. Volunteer, mentor, build, and more.",
"Join our mission-driven community building tools and projects for Palestinian liberation. Volunteer, mentor, contribute your skills, or help lead a project.",
isPartOf: {
"@type": "NonprofitOrganization",
"@id": "https://techforpalestine.org/#organization",
Expand All @@ -21,8 +23,8 @@ const webPageSchema = {
---

<HomeLayout
title="Get Involved | Tech for Palestine"
description="Join our mission-driven community building tools and projects for Palestinian liberation. Volunteer, mentor, build, and more."
title="Get Involved with Tech for Palestine | Volunteer & More"
description="Join our mission-driven community building tools and projects for Palestinian liberation. Volunteer, mentor, contribute your skills, or help lead a project."
noindex={true}
>
<Fragment slot="head">
Expand Down Expand Up @@ -57,6 +59,7 @@ const webPageSchema = {
<div class="gi-animate rounded-xl border border-butter bg-cream p-8">
<div class="mb-6 flex h-16 w-16 items-center justify-center rounded-full bg-butter">
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
Expand Down Expand Up @@ -89,6 +92,7 @@ const webPageSchema = {
<div class="gi-animate rounded-xl border border-butter bg-cream p-8">
<div class="mb-6 flex h-16 w-16 items-center justify-center rounded-full bg-butter">
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
Expand Down Expand Up @@ -126,6 +130,7 @@ const webPageSchema = {
<div class="gi-animate rounded-xl border border-butter bg-cream p-8">
<div class="mb-6 flex h-16 w-16 items-center justify-center rounded-full bg-butter">
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
Expand Down Expand Up @@ -165,6 +170,7 @@ const webPageSchema = {
<div class="gi-animate rounded-xl border border-butter bg-cream p-8">
<div class="mb-6 flex h-16 w-16 items-center justify-center rounded-full bg-butter">
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
Expand All @@ -190,6 +196,7 @@ const webPageSchema = {
<div class="gi-animate rounded-xl border border-butter bg-cream p-8">
<div class="mb-6 flex h-16 w-16 items-center justify-center rounded-full bg-butter">
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
Expand Down Expand Up @@ -217,6 +224,7 @@ const webPageSchema = {
<div class="gi-animate rounded-xl border border-butter bg-cream p-8">
<div class="mb-6 flex h-16 w-16 items-center justify-center rounded-full bg-butter">
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
Expand All @@ -242,6 +250,7 @@ const webPageSchema = {
<div class="gi-animate rounded-xl border border-butter bg-cream p-8">
<div class="mb-6 flex h-16 w-16 items-center justify-center rounded-full bg-butter">
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
Expand Down
12 changes: 11 additions & 1 deletion src/pages/ideas-new.astro
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,20 @@ try {

const mapIdea = (idea: any) => {
const plainText = idea.description.map((s: any) => s.plain_text).join("");
// Truncate at the last word boundary within the limit rather than a hard
// character cut, so structured-data descriptions read as clean sentence
// fragments instead of stopping mid-word.
let excerpt = plainText;
if (plainText.length > 150) {
const truncated = plainText.slice(0, 150);
const lastSpace = truncated.lastIndexOf(" ");
excerpt = (lastSpace > 0 ? truncated.slice(0, lastSpace) : truncated) + "...";
}
return {
id: idea.id,
data: { title: idea.name, tags: [] },
richTextDescription: idea.description,
excerpt: plainText.substring(0, 150) + (plainText.length > 150 ? "..." : ""),
excerpt,
};
};

Expand Down Expand Up @@ -91,6 +100,7 @@ const ideasListSchema = allIdeas.length > 0 && {
</section>

<section class="bg-page pt-10 min-[810px]:pt-12">
<h2 class="sr-only">Browse ideas</h2>
<IdeasWithTabsNew
newIdeas={newIdeas}
existingIdeas={existingIdeas}
Expand Down
2 changes: 2 additions & 0 deletions src/pages/incubator-new.astro
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ const membershipLive = getEnv("MEMBERSHIP_LIVE", Astro.locals) === "true";
src="/happy-kids.jpg"
alt="Palestinian children smiling together"
class="aspect-[5/2] w-full rounded-lg object-cover"
width="2048"
height="1365"
loading="lazy"
decoding="async"
/>
Expand Down
14 changes: 13 additions & 1 deletion src/pages/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,27 @@
import Layout from "../layouts/Layout.astro";
import SignUpForm from "../structures/SignUpForm.astro";
import "../styles/base.css";

// Search/AI crawlers must never be enrolled in the client-side A/B redirect:
// home-new is noindex, and a crawler that randomly lands there (via
// location.replace) makes Google's indexing signal for "/" — the site's most
// important URL — non-deterministic across crawls. Bots always get the
// stable, indexable content on this page.
const userAgent = Astro.request.headers.get("user-agent") || "";
const isBot =
/bot|crawl|spider|slurp|facebookexternalhit|GPTBot|ChatGPT|CCBot|Claude-Web|ClaudeBot|PerplexityBot|anthropic|Applebot|ia_archiver/i.test(
userAgent
);
---

<Layout
title="Tech For Palestine"
description="A coalition of thousands of founders, engineers, product marketers, investors and other professionals working in support of Palestinian liberation. The T4P Incubator helps pro-Palestine advocates build, grow, and scale their work towards a Free Palestine."
image="https://techforpalestine.org/happy-kids.jpg"
>
<script is:inline slot="head">
<script is:inline slot="head" define:vars={{ isBot }}>
(function () {
if (isBot) return;
try {
var key = "ab-homepage-variant";
var v = localStorage.getItem(key);
Expand Down
6 changes: 6 additions & 0 deletions src/pages/legal-new.astro
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@ const pageDescription =
const webPageSchema = {
"@context": "https://schema.org",
"@type": "WebPage",
"@id": "https://techforpalestine.org/legal-new",
url: "https://techforpalestine.org/legal-new",
name: pageTitle,
description: pageDescription,
dateModified: "2025-08-05",
publisher: {
"@type": "NonprofitOrganization",
"@id": "https://techforpalestine.org/#organization",
},
};
---

Expand Down
Loading
Loading