Compare commits

...

21 commits

Author SHA1 Message Date
9d9771de6e
Merge branch 'home-page' 2026-05-17 09:45:06 +03:00
a621510226
add get involved and footer 2026-05-16 22:09:18 +03:00
b54522ddfc
test get involved and footer render 2026-05-16 22:07:42 +03:00
d24e0940c1
add start your journey ctas 2026-05-16 22:06:56 +03:00
3aa8c51e5f
test start your journey ctas render 2026-05-16 22:02:45 +03:00
4f997fdf45
add projects grid 2026-05-16 22:02:01 +03:00
39bd4cc5f5
test projects grid renders 2026-05-16 22:00:37 +03:00
c4c1ccf316
add sponsor strip 2026-05-16 22:00:11 +03:00
f490535457
test sponsor strip renders 2026-05-16 21:59:05 +03:00
46b05e6724
add testimonials carousel 2026-05-16 21:58:33 +03:00
8fe6dbc5c2
test testimonials carousel renders 2026-05-16 21:56:49 +03:00
f50ea8707c
add unique voice section 2026-05-16 21:56:14 +03:00
243aed4f12
test unique voice section renders 2026-05-16 21:54:03 +03:00
57fe1ac49e
add core teachings grid 2026-05-16 21:53:37 +03:00
2be6840d10
test core teachings grid renders 2026-05-16 21:52:18 +03:00
7ac05c90ea
add discover path section 2026-05-16 21:51:26 +03:00
8c74eb707e
test discover path section renders 2026-05-16 21:50:33 +03:00
4d8e0902ba
add homepage hero and route 2026-05-16 21:49:32 +03:00
ca20b7ae43
test homepage hero renders 2026-05-16 21:47:14 +03:00
821ff72b00
wire cypress for frontend 2026-05-16 21:47:08 +03:00
4cfe2bd4a5
ignore reference directory 2026-05-16 21:40:03 +03:00
12 changed files with 4092 additions and 11 deletions

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
/.direnv/ /.direnv/
/.reference/
/backend/.phpunit.cache/ /backend/.phpunit.cache/

View file

@ -0,0 +1,16 @@
import { defineConfig } from 'cypress'
import createBundler from '@bahmutov/cypress-esbuild-preprocessor'
export default defineConfig({
e2e: {
baseUrl: 'http://localhost:5173',
specPattern: 'cypress/e2e/**/*.cy.ts',
supportFile: 'cypress/support/e2e.ts',
fixturesFolder: false,
video: false,
screenshotOnRunFailure: false,
setupNodeEvents(onEvent) {
onEvent('file:preprocessor', createBundler())
},
},
})

View file

@ -0,0 +1,222 @@
describe('homepage hero', () => {
beforeEach(() => {
cy.visit('/')
})
it('renders the header navigation', () => {
cy.get('header').within(() => {
cy.contains('Torah Media').should('be.visible')
cy.contains('About').should('be.visible')
cy.contains('Contact').should('be.visible')
cy.contains('Donate').should('be.visible')
})
})
it('renders the hero headline with italic emphasis', () => {
cy.get('[data-cy="hero"]').within(() => {
cy.contains('upgrade our lives').should('be.visible')
cy.contains('em', 'healthy').should('be.visible')
cy.contains('em', 'integrated').should('be.visible')
cy.contains('em', 'balanced').should('be.visible')
cy.contains('Torah existence').should('be.visible')
cy.contains('Rabbi Yehoshua Gerzi').should('be.visible')
})
})
it('renders the rabbi portrait image', () => {
cy.get('[data-cy="hero-portrait"]')
.should('be.visible')
.and('have.attr', 'alt')
.and('match', /Rabbi Yehoshua Gerzi/i)
})
})
describe('homepage discover path section', () => {
beforeEach(() => {
cy.visit('/')
})
it('renders the heading and body copy', () => {
cy.get('[data-cy="discover-path"]').within(() => {
cy.contains('h2', 'Discover a Path to a Holistically Engaged Life')
.should('be.visible')
cy.contains('Rabbi Yehoshua Gerzi has dedicated his life')
.should('be.visible')
cy.contains('Healthy, Integrated and Balanced Torah Living')
.should('be.visible')
cy.contains('Ramat Beit Shemesh').should('be.visible')
cy.contains('Pilzno Institute of Higher Learning').should('be.visible')
})
})
})
describe('homepage core teachings grid', () => {
beforeEach(() => {
cy.visit('/')
})
it('renders the heading and six teaching tiles', () => {
cy.get('[data-cy="core-teachings"]').within(() => {
cy.contains('h2', 'Baderech HaAvodah').should('be.visible')
cy.contains('Core Teachings').should('be.visible')
cy.contains('1) Introduction').should('be.visible')
cy.contains('2) Foundations').should('be.visible')
cy.contains('3) Divine Plan').should('be.visible')
cy.contains('4) Architecture of the Soul').should('be.visible')
cy.contains('5) Arba Yesodot').should('be.visible')
cy.contains('6) Fluid Integration').should('be.visible')
})
})
})
describe('homepage unique voice section', () => {
beforeEach(() => {
cy.visit('/')
})
it('renders heading body and cta button', () => {
cy.get('[data-cy="unique-voice"]').within(() => {
cy.contains('h2', 'A Unique Voice for the Generation')
.should('be.visible')
cy.contains('wholly unique and much needed perspective')
.should('be.visible')
cy.contains('practically engaged positivity').should('be.visible')
cy.contains('button', /Learn about Rabbi Gerzi.s Approach/)
.should('be.visible')
})
})
})
describe('homepage testimonials carousel', () => {
beforeEach(() => {
cy.visit('/')
})
it('renders the heading and the active testimonial', () => {
cy.get('[data-cy="testimonials"]').within(() => {
cy.contains('h2', 'What People Are Saying').should('be.visible')
cy.get('[data-cy="testimonial-active"]').within(() => {
cy.contains('Nathaniel M').should('be.visible')
cy.contains('best Jewish day schools').should('be.visible')
})
})
})
it('advances to the next testimonial when next is clicked', () => {
cy.get('[data-cy="testimonials"]').within(() => {
cy.get('[data-cy="testimonial-active"]')
.should('contain.text', 'Nathaniel M')
cy.get('[data-cy="testimonial-next"]').click()
cy.get('[data-cy="testimonial-active"]')
.should('not.contain.text', 'Nathaniel M')
})
})
it('goes back to the previous testimonial when prev is clicked', () => {
cy.get('[data-cy="testimonials"]').within(() => {
cy.get('[data-cy="testimonial-next"]').click()
cy.get('[data-cy="testimonial-prev"]').click()
cy.get('[data-cy="testimonial-active"]')
.should('contain.text', 'Nathaniel M')
})
})
})
describe('homepage sponsor strip', () => {
beforeEach(() => {
cy.visit('/')
})
it('renders the heading and all seven partner logos', () => {
cy.get('[data-cy="sponsors"]').within(() => {
cy.contains('h2', 'Organizations Rabbi Gerzi has Worked With')
.should('be.visible')
cy.get('[data-cy="sponsor-logo"]').should('have.length', 7)
const expectedAlts = [
'SHARE',
'U of Israel',
'Mayberg Foundation',
'JLE UK',
'Yeshivat Reishit',
'Aish HaTorah',
'Yeshivat Lev HaTorah',
]
expectedAlts.forEach((altText) => {
cy.get(`[data-cy="sponsor-logo"][alt="${altText}"]`)
.should('be.visible')
})
})
})
})
describe('homepage projects grid', () => {
beforeEach(() => {
cy.visit('/')
})
it('renders the heading and four project cards', () => {
cy.get('[data-cy="projects"]').within(() => {
cy.contains('h2', 'Projects').should('be.visible')
cy.get('[data-cy="project-card"]').should('have.length', 4)
cy.contains('h3', 'Chaburot').should('be.visible')
cy.contains('group learning sessions').should('be.visible')
cy.contains('h3', 'Pilzno Work Inspired').should('be.visible')
cy.contains('healthy relationship to work').should('be.visible')
cy.contains('h3', 'Shul').should('be.visible')
cy.contains('Pilzno Beis Dovid').should('be.visible')
cy.contains('h3', 'New Building').should('be.visible')
cy.contains('Beit Shemesh municipality').should('be.visible')
})
})
})
describe('homepage start your journey ctas', () => {
beforeEach(() => {
cy.visit('/')
})
it('renders both journey CTAs with their headings and bodies', () => {
cy.get('[data-cy="journey"]').within(() => {
cy.contains('h2', 'Start Your Journey').should('be.visible')
cy.get('[data-cy="journey-media"]').within(() => {
cy.contains('Access').should('be.visible')
cy.contains('Torah Media').should('be.visible')
cy.contains('wealth of video, audio and written content')
.should('be.visible')
})
cy.get('[data-cy="journey-baderech"]').within(() => {
cy.contains('Explore').should('be.visible')
cy.contains('Baderech HaAvodah').should('be.visible')
cy.contains('transformative principles').should('be.visible')
})
})
})
})
describe('homepage get involved and footer', () => {
beforeEach(() => {
cy.visit('/')
})
it('renders the newsletter signup form', () => {
cy.get('[data-cy="get-involved"]').within(() => {
cy.contains('h2', 'Get Involved').should('be.visible')
cy.contains(
'Subscribe for updates as we release new content',
).should('be.visible')
cy.get('input[name="fullName"]').should('be.visible')
cy.get('input[name="email"]').should('be.visible')
cy.contains('button', 'Submit').should('be.visible')
})
})
it('renders the footer with links and copyright', () => {
cy.get('[data-cy="footer"]').within(() => {
cy.contains('Torah Media').should('be.visible')
cy.contains('About').should('be.visible')
cy.contains('Donate').should('be.visible')
cy.contains('Contact').should('be.visible')
cy.contains(/Rabbi Gerzi 2025/).should('be.visible')
})
})
})

View file

@ -0,0 +1,3 @@
// Loaded automatically before every spec file in cypress/e2e/.
// Intentionally minimal - add shared commands here when needed.
export {}

View file

@ -1,10 +1,20 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang=""> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<link rel="icon" href="/favicon.ico"> <link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title> <meta
name="description"
content="The official site of Rabbi Yehoshua Gerzi"
>
<title>Rabbi Gerzi</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link
href="https://fonts.googleapis.com/css2?family=Merriweather:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,700&family=Inter:wght@400;500;600;700&display=swap"
rel="stylesheet"
>
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

File diff suppressed because it is too large Load diff

View file

@ -12,7 +12,9 @@
"lint": "run-s lint:*", "lint": "run-s lint:*",
"lint:oxlint": "oxlint . --fix", "lint:oxlint": "oxlint . --fix",
"lint:eslint": "eslint . --fix --cache", "lint:eslint": "eslint . --fix --cache",
"format": "oxfmt src/" "format": "oxfmt src/",
"test:e2e": "cypress run",
"test:e2e:open": "cypress open"
}, },
"dependencies": { "dependencies": {
"pinia": "^3.0.4", "pinia": "^3.0.4",
@ -20,12 +22,15 @@
"vue-router": "^5.0.4" "vue-router": "^5.0.4"
}, },
"devDependencies": { "devDependencies": {
"@bahmutov/cypress-esbuild-preprocessor": "^2.2.8",
"@tsconfig/node24": "^24.0.4", "@tsconfig/node24": "^24.0.4",
"@types/node": "^24.12.2", "@types/node": "^24.12.2",
"@vitejs/plugin-vue": "^6.0.6", "@vitejs/plugin-vue": "^6.0.6",
"@vitejs/plugin-vue-jsx": "^5.1.5", "@vitejs/plugin-vue-jsx": "^5.1.5",
"@vue/eslint-config-typescript": "^14.7.0", "@vue/eslint-config-typescript": "^14.7.0",
"@vue/tsconfig": "^0.9.1", "@vue/tsconfig": "^0.9.1",
"cypress": "^14.5.4",
"esbuild": "^0.28.0",
"eslint": "^10.2.1", "eslint": "^10.2.1",
"eslint-config-prettier": "^10.1.8", "eslint-config-prettier": "^10.1.8",
"eslint-plugin-oxlint": "~1.60.0", "eslint-plugin-oxlint": "~1.60.0",

View file

@ -1,11 +1,7 @@
<script setup lang="ts"></script> <script setup lang="ts"></script>
<template> <template>
<h1>You did it!</h1> <RouterView />
<p>
Visit <a href="https://vuejs.org/" target="_blank" rel="noopener">vuejs.org</a> to read the
documentation
</p>
</template> </template>
<style scoped></style> <style scoped></style>

View file

@ -0,0 +1,37 @@
:root {
--color-cream: #f4efe1;
--color-slate: #2b3f4e;
--color-slate-dark: #213240;
--color-olive: #5e6b4c;
--color-text: #1f1f1f;
--color-text-muted: #5a5a5a;
--color-white: #ffffff;
--color-border: #e6e1d2;
--font-serif: 'Merriweather', Georgia, serif;
--font-sans: 'Inter', system-ui, -apple-system, sans-serif;
}
* {
box-sizing: border-box;
}
html,
body {
margin: 0;
padding: 0;
font-family: var(--font-sans);
color: var(--color-text);
background: var(--color-white);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a {
color: inherit;
text-decoration: none;
}
button {
font-family: inherit;
cursor: pointer;
}

View file

@ -3,6 +3,7 @@ import { createPinia } from 'pinia'
import App from './App.vue' import App from './App.vue'
import router from './router' import router from './router'
import './assets/global.css'
const app = createApp(App) const app = createApp(App)

View file

@ -1,8 +1,15 @@
import { createRouter, createWebHistory } from 'vue-router' import { createRouter, createWebHistory } from 'vue-router'
import HomePage from '@/views/HomePage.vue'
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(import.meta.env.BASE_URL),
routes: [], routes: [
{
path: '/',
name: 'home',
component: HomePage,
},
],
}) })
export default router export default router

File diff suppressed because it is too large Load diff