diff --git a/.github/workflows/azure-static-web-apps-ambitious-coast-0c7656e10.yml b/.github/workflows/azure-static-web-apps-ambitious-coast-0c7656e10.yml new file mode 100644 index 0000000..cee6c09 --- /dev/null +++ b/.github/workflows/azure-static-web-apps-ambitious-coast-0c7656e10.yml @@ -0,0 +1,53 @@ +name: Azure Static Web Apps CI/CD + +on: + push: + branches: + - staging + pull_request: + types: [opened, synchronize, reopened, closed] + branches: + - staging + +jobs: + build_and_deploy_job: + if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed') + runs-on: ubuntu-latest + name: Build and Deploy Job + + steps: + - name: Checkout repository + uses: actions/checkout@v5 + with: + submodules: true + lfs: false + + - name: Set up Node.js + uses: actions/setup-node@v5 + with: + node-version-file: .nvmrc + cache: npm + + - name: Build and Deploy + id: builddeploy + uses: Azure/static-web-apps-deploy@v1 + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AMBITIOUS_COAST_0C7656E10 }} + repo_token: ${{ secrets.GITHUB_TOKEN }} + action: "upload" + app_location: "/" + api_location: "" + output_location: "dist" + + close_pull_request_job: + if: github.event_name == 'pull_request' && github.event.action == 'closed' + runs-on: ubuntu-latest + name: Close Pull Request + + steps: + - name: Close Pull Request + id: closepullrequest + uses: Azure/static-web-apps-deploy@v1 + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AMBITIOUS_COAST_0C7656E10 }} + action: "close" \ No newline at end of file diff --git a/public/favicon.ico b/public/favicon.ico index 7f48a94..d2feacc 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/favicon.svg b/public/favicon.svg index f157bd1..5809b5c 100644 --- a/public/favicon.svg +++ b/public/favicon.svg @@ -1,9 +1,3 @@ - - - - +RealFaviconGeneratorhttps://realfavicongenerator.net \ No newline at end of file diff --git a/public/images/bmdib-logo.png b/public/images/bmdib-logo.png new file mode 100644 index 0000000..bdf7c58 Binary files /dev/null and b/public/images/bmdib-logo.png differ diff --git a/public/images/board/diana-ly.png b/public/images/board/diana-ly.png new file mode 100644 index 0000000..3abca4e Binary files /dev/null and b/public/images/board/diana-ly.png differ diff --git a/public/images/board/emily-ho.jpg b/public/images/board/emily-ho.jpg new file mode 100644 index 0000000..0cf9a90 Binary files /dev/null and b/public/images/board/emily-ho.jpg differ diff --git a/public/images/board/jack-zhao.jpg b/public/images/board/jack-zhao.jpg new file mode 100644 index 0000000..3e0e895 Binary files /dev/null and b/public/images/board/jack-zhao.jpg differ diff --git a/public/images/board/jeff-tang.jpg b/public/images/board/jeff-tang.jpg new file mode 100644 index 0000000..380c2dc Binary files /dev/null and b/public/images/board/jeff-tang.jpg differ diff --git a/public/images/board/khanh-vuong.jpg b/public/images/board/khanh-vuong.jpg new file mode 100644 index 0000000..e8508ee Binary files /dev/null and b/public/images/board/khanh-vuong.jpg differ diff --git a/public/images/board/lingkai-zuo.jpg b/public/images/board/lingkai-zuo.jpg new file mode 100644 index 0000000..2e835ef Binary files /dev/null and b/public/images/board/lingkai-zuo.jpg differ diff --git a/public/images/board/nhu-y-nguyen.jpg b/public/images/board/nhu-y-nguyen.jpg new file mode 100644 index 0000000..f48d49e Binary files /dev/null and b/public/images/board/nhu-y-nguyen.jpg differ diff --git a/public/images/board/winnie-lee.jpg b/public/images/board/winnie-lee.jpg new file mode 100644 index 0000000..dd3eb0d Binary files /dev/null and b/public/images/board/winnie-lee.jpg differ diff --git a/public/images/board/yongwang-lei.jpg b/public/images/board/yongwang-lei.jpg new file mode 100644 index 0000000..ed5114a Binary files /dev/null and b/public/images/board/yongwang-lei.jpg differ diff --git a/public/images/competitions/photo-1.jpg b/public/images/competitions/photo-1.jpg new file mode 100644 index 0000000..a39c932 Binary files /dev/null and b/public/images/competitions/photo-1.jpg differ diff --git a/public/images/competitions/photo-2.jpg b/public/images/competitions/photo-2.jpg new file mode 100644 index 0000000..3871701 Binary files /dev/null and b/public/images/competitions/photo-2.jpg differ diff --git a/public/images/competitions/photo-3.jpg b/public/images/competitions/photo-3.jpg new file mode 100644 index 0000000..bd5b018 Binary files /dev/null and b/public/images/competitions/photo-3.jpg differ diff --git a/public/images/events/kinder-popsicle-playdate-2026/2026-08-08-ice-cream-social-1.jpg b/public/images/events/kinder-popsicle-playdate-2026/2026-08-08-ice-cream-social-1.jpg new file mode 100644 index 0000000..3ebb2f9 Binary files /dev/null and b/public/images/events/kinder-popsicle-playdate-2026/2026-08-08-ice-cream-social-1.jpg differ diff --git a/public/images/events/kinder-popsicle-playdate-2026/2026-08-08-ice-cream-social-2.jpg b/public/images/events/kinder-popsicle-playdate-2026/2026-08-08-ice-cream-social-2.jpg new file mode 100644 index 0000000..03ba528 Binary files /dev/null and b/public/images/events/kinder-popsicle-playdate-2026/2026-08-08-ice-cream-social-2.jpg differ diff --git a/public/images/events/kinder-popsicle-playdate-2026/2026-08-08-ice-cream-social-3.jpg b/public/images/events/kinder-popsicle-playdate-2026/2026-08-08-ice-cream-social-3.jpg new file mode 100644 index 0000000..22c37bb Binary files /dev/null and b/public/images/events/kinder-popsicle-playdate-2026/2026-08-08-ice-cream-social-3.jpg differ diff --git a/public/images/events/mid-autumn-lantern-contest-2026/photo-1.png b/public/images/events/mid-autumn-lantern-contest-2026/photo-1.png new file mode 100644 index 0000000..8ea74eb Binary files /dev/null and b/public/images/events/mid-autumn-lantern-contest-2026/photo-1.png differ diff --git a/public/images/events/mid-autumn-lantern-contest-2026/photo-2.png b/public/images/events/mid-autumn-lantern-contest-2026/photo-2.png new file mode 100644 index 0000000..e4fa04a Binary files /dev/null and b/public/images/events/mid-autumn-lantern-contest-2026/photo-2.png differ diff --git a/public/images/events/mid-autumn-staff-treats-2026/photo-1.jpg b/public/images/events/mid-autumn-staff-treats-2026/photo-1.jpg new file mode 100644 index 0000000..2196272 Binary files /dev/null and b/public/images/events/mid-autumn-staff-treats-2026/photo-1.jpg differ diff --git a/public/images/events/welcome-back-picnic-2026/photo-1.jpg b/public/images/events/welcome-back-picnic-2026/photo-1.jpg new file mode 100644 index 0000000..f5f372e Binary files /dev/null and b/public/images/events/welcome-back-picnic-2026/photo-1.jpg differ diff --git a/public/images/events/welcome-back-picnic-2026/photo-2.jpg b/public/images/events/welcome-back-picnic-2026/photo-2.jpg new file mode 100644 index 0000000..c259928 Binary files /dev/null and b/public/images/events/welcome-back-picnic-2026/photo-2.jpg differ diff --git a/public/images/events/welcome-back-picnic-2026/photo-3.jpg b/public/images/events/welcome-back-picnic-2026/photo-3.jpg new file mode 100644 index 0000000..18f687d Binary files /dev/null and b/public/images/events/welcome-back-picnic-2026/photo-3.jpg differ diff --git a/public/images/events/welcome-back-picnic-2026/photo-4.jpg b/public/images/events/welcome-back-picnic-2026/photo-4.jpg new file mode 100644 index 0000000..12fbea3 Binary files /dev/null and b/public/images/events/welcome-back-picnic-2026/photo-4.jpg differ diff --git a/src/components/BoardMemberCard.astro b/src/components/BoardMemberCard.astro index 6e25834..9abb1cf 100644 --- a/src/components/BoardMemberCard.astro +++ b/src/components/BoardMemberCard.astro @@ -2,27 +2,27 @@ interface Props { name: string; role: string; - image?: string | null; - bio: string; + image?: string; } -const { name, role, image, bio } = Astro.props; +const { name, role, image } = Astro.props; ---
-
- {image ? ( - {`Headshot - ) : ( - + ) + }

{name}

{role}

-

{bio}

+ +
+ +
\ No newline at end of file diff --git a/src/components/CompetitionCard.astro b/src/components/CompetitionCard.astro index 690a4c4..241c87a 100644 --- a/src/components/CompetitionCard.astro +++ b/src/components/CompetitionCard.astro @@ -1,22 +1,102 @@ --- +import { formatDate, formatTime } from "../utils/dateTime"; + +interface Image { + src: string; + alt: string; +} + interface Props { title: string; date: string; - description: string; + time: string; location?: string; + images?: Image[]; } -const { title, date, description, location } = Astro.props; +const { title, date, time, location, images = [] } = Astro.props; + +const formattedDate = formatDate(date); +const formattedTime = formatTime(time); + +const carouselId = `competition-carousel-${date}-${title}` + .toLowerCase() + .replace(/[^a-z0-9]+/g, "-") + .replace(/^-|-$/g, ""); ---
+ { + images.length === 1 && ( + {images[0].alt} + ) + } + + { + images.length > 1 && ( + + ) + }
-

{date}

+

+ +

{title}

{location &&

{location}

} -

{description}

+
+ +
\ No newline at end of file diff --git a/src/components/EventCard.astro b/src/components/EventCard.astro index 7a92c1b..43bed9c 100644 --- a/src/components/EventCard.astro +++ b/src/components/EventCard.astro @@ -1,22 +1,102 @@ --- +import { formatDate, formatTime } from "../utils/dateTime"; + +interface Image { + src: string; + alt: string; +} + interface Props { title: string; date: string; - description: string; + time?: string; location?: string; + images?: Image[]; } -const { title, date, description, location } = Astro.props; +const { title, date, time, location, images = [] } = Astro.props; + +const formattedDate = formatDate(date); +const formattedTime = time ? formatTime(time) : null; + +const carouselId = `event-carousel-${date}-${title}` + .toLowerCase() + .replace(/[^a-z0-9]+/g, "-") + .replace(/^-|-$/g, ""); ---
+ { + images.length === 1 && ( + {images[0].alt} + ) + } + + { + images.length > 1 && ( + + ) + }
-

{date}

+

+ +

{title}

{location &&

{location}

} -

{description}

+
+ +
\ No newline at end of file diff --git a/src/components/Footer.astro b/src/components/Footer.astro index 685de26..2028b8b 100644 --- a/src/components/Footer.astro +++ b/src/components/Footer.astro @@ -12,24 +12,13 @@
diff --git a/src/components/Header.astro b/src/components/Header.astro index 02e5e2a..369a276 100644 --- a/src/components/Header.astro +++ b/src/components/Header.astro @@ -7,7 +7,6 @@ const navItems = [ { label: "General Meetings", href: "/meetings" }, { label: "Fundraising", href: "/fundraising" }, { label: "Resources", href: "/resources" }, - { label: "Contact", href: "/contact" }, ]; // Helper function to remove trailing slashes for strict matching @@ -18,7 +17,13 @@ const currentPath = normalizePath(Astro.url.pathname); \ No newline at end of file + + + \ No newline at end of file diff --git a/src/components/MeetingCard.astro b/src/components/MeetingCard.astro index 5c25906..6c10c50 100644 --- a/src/components/MeetingCard.astro +++ b/src/components/MeetingCard.astro @@ -1,28 +1,46 @@ --- +import { formatDate, formatTime } from "../utils/dateTime"; + interface Props { title: string; date: string; + time: string; location?: string; agenda?: string; slides?: string; minutes?: string; } -const { title, date, location, agenda, slides, minutes } = Astro.props; +const { title, date, time, location, agenda, slides, minutes, } = Astro.props; + +const formattedDate = formatDate(date); +const formattedTime = formatTime(time); ---
-

{date}

+

+ +

{title}

{location &&

{location}

} -
- {agenda && Agenda} - {slides && Slides} - {minutes && Minutes} +
+
+ + { + (agenda || slides || minutes) && ( +
+ {agenda && Agenda} + {slides && Slides} + {minutes && Minutes} +
+ ) + }
\ No newline at end of file diff --git a/src/components/PageHeader.astro b/src/components/PageHeader.astro new file mode 100644 index 0000000..f1be3a9 --- /dev/null +++ b/src/components/PageHeader.astro @@ -0,0 +1,23 @@ +--- +interface Props { + eyebrow: string; + title: string; + description?: string; +} + +const { eyebrow, title, description } = Astro.props; +--- + + \ No newline at end of file diff --git a/src/content.config.ts b/src/content.config.ts new file mode 100644 index 0000000..bbe7707 --- /dev/null +++ b/src/content.config.ts @@ -0,0 +1,76 @@ +import { defineCollection, z } from "astro:content"; +import { glob } from "astro/loaders"; + +const events = defineCollection({ + loader: glob({ + pattern: "**/*.md", + base: "./src/data/events", + }), + schema: z.object({ + title: z.string(), + date: z.string(), + time: z.string().optional(), + location: z.string().optional(), + images: z.array( + z.object({ + src: z.string(), + alt: z.string(), + }) + ).optional(), + }), +}); + +const competitions = defineCollection({ + loader: glob({ + pattern: "**/*.md", + base: "./src/data/competitions", + }), + schema: z.object({ + title: z.string(), + date: z.string(), + time: z.string(), + location: z.string().optional(), + images: z.array( + z.object({ + src: z.string(), + alt: z.string(), + }) + ).optional(), + }), +}); + +const meetings = defineCollection({ + loader: glob({ + pattern: "**/*.md", + base: "./src/data/meetings", + }), + schema: z.object({ + title: z.string(), + date: z.string(), + time: z.string(), + location: z.string().optional(), + agenda: z.string().optional(), + slides: z.string().optional(), + minutes: z.string().optional(), + }), +}); + +const board = defineCollection({ + loader: glob({ + pattern: "**/*.md", + base: "./src/data/board", + }), + schema: z.object({ + name: z.string(), + role: z.string(), + image: z.string().optional(), + order: z.number(), + }), +}); + +export const collections = { + events, + competitions, + meetings, + board, +}; \ No newline at end of file diff --git a/src/data/board/diana-ly.md b/src/data/board/diana-ly.md new file mode 100644 index 0000000..b624e93 --- /dev/null +++ b/src/data/board/diana-ly.md @@ -0,0 +1,8 @@ +--- +name: "Diana Ly" +role: "Treasurer" +image: "/images/board/diana-ly.png" +order: 5 +--- + +A mom of two amazing boys in the Mandarin Dual Immersion program. By day, I work at one of the coolest space agencies around, and whenever I can, I’m off exploring the world, discovering new cultures, and finding my next favorite bite. As Treasurer on the board, I’m passionate about giving back, connecting families, and helping create a strong, welcoming community where everyone feels they belong. Building community, supporting our kids, and making a difference—one connection at a time. \ No newline at end of file diff --git a/src/data/board/emily-ho.md b/src/data/board/emily-ho.md new file mode 100644 index 0000000..6927bf1 --- /dev/null +++ b/src/data/board/emily-ho.md @@ -0,0 +1,8 @@ +--- +name: "Emily Ho" +role: "Volunteer Coordinator" +image: "/images/board/emily-ho.jpg" +order: 6 +--- + +I am a mother of 3 children and have been part of the mandarin immersion program since its inception! My oldest is now a junior in PHHS and the younger ones are in 6th and 8th grade at Sierramont. I love our school community and the dedicated staff who go above and beyond to make the extra programming for the mandarin learning possible, and would like to encourage all parents to get involved and help make our program shine! Outside of work and volunteering, I love to watch my children play basketball, softball and go fishing! \ No newline at end of file diff --git a/src/data/board/jack-zhao.md b/src/data/board/jack-zhao.md new file mode 100644 index 0000000..778ba55 --- /dev/null +++ b/src/data/board/jack-zhao.md @@ -0,0 +1,12 @@ +--- +name: "Jack Zhao" +role: "VP of Events" +image: "/images/board/jack-zhao.jpg" +order: 4 +--- + +I am a proud father of two children who have both been part of the Mandarin Immersion (MI) program. My son graduated from elementary school, and my daughter is now in 5th grade. Both have participated in annual Lion Dancing for school and district awards celebrations, giving them the opportunity to share our culture with the community. + +I serve as the Vice President of Events, helping organize Mid-Autumn Festival, Lunar New Year, and the Lunar New Year Teacher’s Luncheon. I enjoy sharing Asian culture with students, teachers, and staff through activities, traditions, performances, and food. + +I often joke that I am the school’s “Jack of All Trades”—from hanging decorations high above the school and dressing as Cai Shen (God of Wealth) to cooking special dishes for the teachers’ luncheon. I am happy to help wherever I am needed. \ No newline at end of file diff --git a/src/data/board/jeff-tang.md b/src/data/board/jeff-tang.md new file mode 100644 index 0000000..a7bc9bc --- /dev/null +++ b/src/data/board/jeff-tang.md @@ -0,0 +1,8 @@ +--- +name: "Jeff Tang" +role: "President" +image: "/images/board/jeff-tang.jpg" +order: 1 +--- + +My journey with this community began in 2015 as one of the founding members who advocated and laid the groundwork to bring a Mandarin Dual Immersion program to Berryessa. Since the program officially launched in 2018, it has been an absolute joy to watch it grow into the vibrant educational community it is today. As a parent with two children currently in the program, my dedication to its success is both professional and personal. Beyond the MDI Boosters, I serve actively across various local education, civic, and youth organizations, focusing on equal rights of education, youth leadership and community advocacy. \ No newline at end of file diff --git a/src/data/board/khanh-vuong.md b/src/data/board/khanh-vuong.md new file mode 100644 index 0000000..6434b38 --- /dev/null +++ b/src/data/board/khanh-vuong.md @@ -0,0 +1,10 @@ +--- +name: "Khanh Vuong" +role: "Co-Secretary" +image: "/images/board/khanh-vuong.jpg" +order: 7 +--- + +Hi everyone! I’m a mom of two wonderful kids in a Mandarin immersion program. Outside of being a busy mom, I love to travel and, most importantly, try new foods and discover new places. + +By day, I’m a Realtor, and I’m excited to also serve our organization as Co-Secretary. I’m looking forward to getting to know everyone and working together to make our organization even stronger! \ No newline at end of file diff --git a/src/data/board/lingkai-zuo.md b/src/data/board/lingkai-zuo.md new file mode 100644 index 0000000..08aeadd --- /dev/null +++ b/src/data/board/lingkai-zuo.md @@ -0,0 +1,8 @@ +--- +name: "Lingkai Zuo" +role: "VP of Academic Programs" +image: "/images/board/lingkai-zuo.jpg" +order: 3 +--- + +I am a proud father of two daughters in the Mandarin Dual Language Immersion (MI) program, which our family has been part of since day one. I love our schools and community, and in my free time, I enjoy travel, home DIY projects, and learning new skills alongside my kids. Lately, my youngest daughter and I have been learning to speed-skate together—and I might even get my coaching certification soon! 🙂 \ No newline at end of file diff --git a/src/data/board/nhu-y-nguyen.md b/src/data/board/nhu-y-nguyen.md new file mode 100644 index 0000000..f063861 --- /dev/null +++ b/src/data/board/nhu-y-nguyen.md @@ -0,0 +1,8 @@ +--- +name: "Nhu-y Nguyen" +role: "Co-Secretary" +image: "/images/board/nhu-y-nguyen.jpg" +order: 8 +--- + +Mom of two who’s been living that Dual Immersion life since day one. When I’m not embarrassing my teens by attempting to speak fluent Gen Alpha, you can find me under the orange lights before dawn, diving deep into most things tech, or finagling schedules to prioritize family experiences and personal wellness. Thrilled to be on Board and keep this amazing community thriving. \ No newline at end of file diff --git a/src/data/board/winnie-lee.md b/src/data/board/winnie-lee.md new file mode 100644 index 0000000..77c34bf --- /dev/null +++ b/src/data/board/winnie-lee.md @@ -0,0 +1,8 @@ +--- +name: "Winnie Lee" +role: "Webmaster" +image: "/images/board/winnie-lee.jpg" +order: 9 +--- + +I'm a bit of a stereotypical geek! I love bringing structure and order to things, and I can happily spend hours building things with code. Outside of work, I enjoy baking and gardening with my little one. As a parent in the Mandarin Immersion Program, I'm passionate about supporting Mandarin language and cultural education for children and families in our community. I'm thrilled to bring both my technical experience and my heart for this mission to Mandarin Boosters. \ No newline at end of file diff --git a/src/data/board/yongwang-lei.md b/src/data/board/yongwang-lei.md new file mode 100644 index 0000000..8ef5402 --- /dev/null +++ b/src/data/board/yongwang-lei.md @@ -0,0 +1,8 @@ +--- +name: "Yongwang Lei" +role: "Co-VP of Fundraising" +image: "/images/board/yongwang-lei.jpg" +order: 2 +--- + +I am a proud father of a son and a daughter in the Mandarin Dual Language Immersion (MI) program, which our family has enthusiastically supported since day one. As Co-VP of Fundraising, I am excited to help raise vital resources to enrich our kids' learning experiences and empower our dedicated teachers. Outside of work, I love traveling, hiking, and immersing myself in nature. \ No newline at end of file diff --git a/src/data/competitions/competition-past-1.md b/src/data/competitions/competition-past-1.md new file mode 100644 index 0000000..641ab62 --- /dev/null +++ b/src/data/competitions/competition-past-1.md @@ -0,0 +1,8 @@ +--- +title: "BMDIB Competition" +date: "2025-11-21" +time: "09:00" +location: "Location TBD" +--- + +Placeholder description for an upcoming BMDIB competition. \ No newline at end of file diff --git a/src/data/competitions/competition-past-2.md b/src/data/competitions/competition-past-2.md new file mode 100644 index 0000000..fe047ab --- /dev/null +++ b/src/data/competitions/competition-past-2.md @@ -0,0 +1,8 @@ +--- +title: "BMDIB Competition" +date: "2026-01-21" +time: "09:00" +location: "Location TBD" +--- + +Placeholder description for an upcoming BMDIB competition. \ No newline at end of file diff --git a/src/data/competitions/competition-upcoming-1.md b/src/data/competitions/competition-upcoming-1.md new file mode 100644 index 0000000..c9da304 --- /dev/null +++ b/src/data/competitions/competition-upcoming-1.md @@ -0,0 +1,8 @@ +--- +title: "BMDIB Competition" +date: "2026-10-21" +time: "09:00" +location: "Location TBD" +--- + +Placeholder description for an upcoming BMDIB competition. \ No newline at end of file diff --git a/src/data/competitions/competition-upcoming-2.md b/src/data/competitions/competition-upcoming-2.md new file mode 100644 index 0000000..0d346e0 --- /dev/null +++ b/src/data/competitions/competition-upcoming-2.md @@ -0,0 +1,8 @@ +--- +title: "BMDIB Competition" +date: "2026-11-21" +time: "09:00" +location: "Location TBD" +--- + +Placeholder description for an upcoming BMDIB competition. \ No newline at end of file diff --git a/src/data/events/cultural-event-upcoming.md b/src/data/events/cultural-event-upcoming.md new file mode 100644 index 0000000..1fb1a71 --- /dev/null +++ b/src/data/events/cultural-event-upcoming.md @@ -0,0 +1,8 @@ +--- +title: "Mandarin Cultural Event" +date: "2026-12-05" +time: "17:00" +location: "Location TBD" +--- + +Placeholder description for an upcoming Mandarin cultural event. \ No newline at end of file diff --git a/src/data/events/kinder-popsicle-playdate-2026.md b/src/data/events/kinder-popsicle-playdate-2026.md new file mode 100644 index 0000000..0a7ff23 --- /dev/null +++ b/src/data/events/kinder-popsicle-playdate-2026.md @@ -0,0 +1,22 @@ +--- +title: "Kinder Popsicle Playdate" +date: "2026-08-08" +location: "Ruskin Elementary School" +images: + - src: "/images/events/kinder-popsicle-playdate-2026/2026-08-08-ice-cream-social-1.jpg" + alt: "Alt1" + - src: "/images/events/kinder-popsicle-playdate-2026/2026-08-08-ice-cream-social-2.jpg" + alt: "Alt2" + - src: "/images/events/kinder-popsicle-playdate-2026/2026-08-08-ice-cream-social-3.jpg" + alt: "Alt3" +--- + +A big welcome to another wonderful generation of kindergarteners! 🎉 + +It was so much fun seeing our newest students and families come together for a day of popsicles, smiles, and new friendships. + +As our little ones begin this exciting journey, we wish them a fantastic year filled with learning, growing, making friends, and creating wonderful memories. + +A special thank you to Mandarin Immersion Boosters and the PTA for hosting this event and helping bring our school community together. + +Here's to a great school year ahead! Welcome, kindergarteners! \ No newline at end of file diff --git a/src/data/events/mid-autumn-lantern-contest-2026.md b/src/data/events/mid-autumn-lantern-contest-2026.md new file mode 100644 index 0000000..0b0ad57 --- /dev/null +++ b/src/data/events/mid-autumn-lantern-contest-2026.md @@ -0,0 +1,18 @@ +--- +title: "Mid-Autumn Lantern Decorating Contest" +date: "2026-10-06" +location: "Ruskin Elementary School & Sierramont Middle School" +images: + - src: "/images/events/mid-autumn-lantern-contest-2026/photo-1.png" + alt: "Alt1" + - src: "/images/events/mid-autumn-lantern-contest-2026/photo-2.png" + alt: "Alt2" +--- + +Our lantern decorating contest was a huge success! + +More than 200 lanterns were submitted by students from Ruskin and Sierramont, filling the Ruskin multipurpose room with colorful lanterns throughout October. + +Congratulations to the winners in each age group, who received a $10 Tastea gift card! + +Thank you to all the students and families who participated and helped make this celebration so special. \ No newline at end of file diff --git a/src/data/events/mid-autumn-staff-treats-2026.md b/src/data/events/mid-autumn-staff-treats-2026.md new file mode 100644 index 0000000..53ef897 --- /dev/null +++ b/src/data/events/mid-autumn-staff-treats-2026.md @@ -0,0 +1,14 @@ +--- +title: "Mid-Autumn Staff Treats" +date: "2026-09-27" +location: "Ruskin Elementary School" +images: + - src: "/images/events/mid-autumn-staff-treats-2026/photo-1.jpg" + alt: "Alt1" +--- + +Our wonderful volunteers prepared delicious dim sum treats—including dumplings, buns, and mooncakes—for Ruskin staff in celebration of the Mid-Autumn Festival. + +It was a wonderful way to show our appreciation for the teachers and staff before Fall Break. + +Thank you to everyone who helped prepare and share these special treats! \ No newline at end of file diff --git a/src/data/events/welcome-back-picnic-2026.md b/src/data/events/welcome-back-picnic-2026.md new file mode 100644 index 0000000..950c365 --- /dev/null +++ b/src/data/events/welcome-back-picnic-2026.md @@ -0,0 +1,20 @@ +--- +title: "Welcome Back Picnic" +date: "2026-08-28" +location: "Ruskin Elementary School" +images: + - src: "/images/events/welcome-back-picnic-2026/photo-1.jpg" + alt: "Alt1" + - src: "/images/events/welcome-back-picnic-2026/photo-2.jpg" + alt: "Alt2" + - src: "/images/events/welcome-back-picnic-2026/photo-3.jpg" + alt: "Alt3" + - src: "/images/events/welcome-back-picnic-2026/photo-4.jpg" + alt: "Alt3" +--- + +It was great to see familiar faces at our first family night event at Ruskin this year! + +BMDIB hosted a booth with information about our organization and flyers promoting our giving campaign, while sharing treats and snacks. + +Thank you to everyone who stopped by to say hello! \ No newline at end of file diff --git a/src/data/meetings/meeting-past-1.md b/src/data/meetings/meeting-past-1.md new file mode 100644 index 0000000..68323ce --- /dev/null +++ b/src/data/meetings/meeting-past-1.md @@ -0,0 +1,9 @@ +--- +title: "BMDIB General Meeting" +date: "2026-03-12" +time: "19:00" +location: "Location TBD" +minutes: "/documents/placeholder-minutes.pdf" +--- + +Placeholder information for a past BMDIB General Meeting. \ No newline at end of file diff --git a/src/data/meetings/meeting-past-2.md b/src/data/meetings/meeting-past-2.md new file mode 100644 index 0000000..d1d416c --- /dev/null +++ b/src/data/meetings/meeting-past-2.md @@ -0,0 +1,11 @@ +--- +title: "BMDIB General Meeting" +date: "2026-05-14" +time: "19:00" +location: "Location TBD" +agenda: "/documents/placeholder-agenda.pdf" +slides: "/documents/placeholder-slides.pdf" +minutes: "/documents/placeholder-minutes.pdf" +--- + +Placeholder information for a past BMDIB General Meeting. \ No newline at end of file diff --git a/src/data/meetings/meeting-upcoming-1.md b/src/data/meetings/meeting-upcoming-1.md new file mode 100644 index 0000000..e8ed4a9 --- /dev/null +++ b/src/data/meetings/meeting-upcoming-1.md @@ -0,0 +1,9 @@ +--- +title: "BMDIB General Meeting" +date: "2026-11-12" +time: "19:00" +location: "Location TBD" +agenda: "/documents/placeholder-agenda.pdf" +--- + +Placeholder information for an upcoming BMDIB General Meeting. \ No newline at end of file diff --git a/src/data/meetings/meeting-upcoming-2.md b/src/data/meetings/meeting-upcoming-2.md new file mode 100644 index 0000000..482199f --- /dev/null +++ b/src/data/meetings/meeting-upcoming-2.md @@ -0,0 +1,8 @@ +--- +title: "BMDIB General Meeting" +date: "2026-12-10" +time: "19:00" +location: "Location TBD" +--- + +Placeholder information for an upcoming BMDIB General Meeting. \ No newline at end of file diff --git a/src/pages/board.astro b/src/pages/board.astro index 30bfa15..809a855 100644 --- a/src/pages/board.astro +++ b/src/pages/board.astro @@ -1,93 +1,47 @@ --- +import { getCollection, render } from "astro:content"; + import BaseLayout from "../layouts/BaseLayout.astro"; import BoardMemberCard from "../components/BoardMemberCard.astro"; +import PageHeader from "../components/PageHeader.astro"; + +const boardMembers = await getCollection("board"); + +const sortedBoardMembers = boardMembers.sort( + (a, b) => a.data.order - b.data.order +); -const boardMembers = [ - { - name: "Board Member Name", - role: "Board Role", - image: null, - bio: "Placeholder self-introduction. Final content will be provided by the board.", - }, - { - name: "Board Member Name", - role: "Board Role", - image: null, - bio: "Placeholder self-introduction. Final content will be provided by the board.", - }, - { - name: "Board Member Name", - role: "Board Role", - image: null, - bio: "Placeholder self-introduction. Final content will be provided by the board.", - }, - { - name: "Board Member Name", - role: "Board Role", - image: null, - bio: "Placeholder self-introduction. Final content will be provided by the board.", - }, - { - name: "Board Member Name", - role: "Board Role", - image: null, - bio: "Placeholder self-introduction. Final content will be provided by the board.", - }, - { - name: "Board Member Name", - role: "Board Role", - image: null, - bio: "Placeholder self-introduction. Final content will be provided by the board.", - }, - { - name: "Board Member Name", - role: "Board Role", - image: null, - bio: "Placeholder self-introduction. Final content will be provided by the board.", - }, - { - name: "Board Member Name", - role: "Board Role", - image: null, - bio: "Placeholder self-introduction. Final content will be provided by the board.", - }, - { - name: "Board Member Name", - role: "Board Role", - image: null, - bio: "Placeholder self-introduction. Final content will be provided by the board.", - }, -]; +const renderedBoardMembers = await Promise.all( + sortedBoardMembers.map(async (member) => ({ + member, + Content: (await render(member)).Content, + })) +); --- -
-
-
-
-

The Board

- -

Meet the Board

- -

- Placeholder introduction to the BMDIB board. Final content will be - provided by the organization. -

-
-
-
-
+
{ - boardMembers.map((member) => ( + renderedBoardMembers.map(({ member, Content }) => (
- + + +
)) } diff --git a/src/pages/competitions.astro b/src/pages/competitions.astro index e88f665..bfc54ea 100644 --- a/src/pages/competitions.astro +++ b/src/pages/competitions.astro @@ -1,100 +1,119 @@ --- +import { getCollection, render } from "astro:content"; +import { getPacificToday } from "../utils/dateTime"; + import BaseLayout from "../layouts/BaseLayout.astro"; import CompetitionCard from "../components/CompetitionCard.astro"; +import PageHeader from "../components/PageHeader.astro"; + +const competitions = await getCollection("competitions"); + +const today = getPacificToday(); + +const upcomingCompetitions = competitions + .filter((competition) => competition.data.date >= today) + .sort((a, b) => { + const dateComparison = a.data.date.localeCompare(b.data.date); + + if (dateComparison !== 0) { + return dateComparison; + } + + return a.data.time.localeCompare(b.data.time); + }); + +const pastCompetitions = competitions + .filter((competition) => competition.data.date < today) + .sort((a, b) => { + const dateComparison = b.data.date.localeCompare(a.data.date); + + if (dateComparison !== 0) { + return dateComparison; + } + + return b.data.time.localeCompare(a.data.time); + }); + +const renderedUpcomingCompetitions = await Promise.all( + upcomingCompetitions.map(async (competition) => ({ + competition, + Content: (await render(competition)).Content, + })) +); -const upcomingCompetitions = [ - { - title: "Mandarin Competition", - date: "Date TBD", - location: "Location TBD", - description: - "Placeholder description for an upcoming Mandarin competition.", - }, - { - title: "Chinese Language Competition", - date: "Date TBD", - location: "Location TBD", - description: - "Placeholder description for an upcoming Chinese language competition.", - }, -]; - -const pastCompetitions = [ - { - title: "Mandarin Competition", - date: "Past Date", - location: "Location TBD", - description: - "Placeholder description for a past Mandarin competition.", - }, - { - title: "Chinese Language Competition", - date: "Past Date", - location: "Location TBD", - description: - "Placeholder description for a past Chinese language competition.", - }, -]; +const renderedPastCompetitions = await Promise.all( + pastCompetitions.map(async (competition) => ({ + competition, + Content: (await render(competition)).Content, + })) +); --- -
-
-
-
-

Competitions

+ -

Competitions

+
+
+
+

BMDIB Competition Program

-

- Placeholder introduction to BMDIB competitions. Final content will - be provided by the organization. -

-
-
-
-
+

+ A message from our VP of Academic Programs: +

-
-
-
-
-

Current & Upcoming Competitions

-
-
- -
- { - upcomingCompetitions.map((competition) => ( -
- -
- )) - } -
-
-
+

+ BMDIB works closely with the district to promote our dual + language immersion programs by organizing and supporting key + events throughout the school year. One of our proudest + traditions is hosting the district-wide internal competition, + which features Pinyin typing, speech, calligraphy, and writing + for students from both Ruskin Elementary and Sierramont Middle + School. Winners from our internal competition will go on to + represent the Berryessa Union School District (BUSD) at the + statewide competition hosted by the Association of Northern + California Chinese Schools (ANCCS). +

-
-
-
-
-

Past Competitions

+ -
- -
- { - pastCompetitions.map((competition) => ( -
- -
- )) - } -
+
\ No newline at end of file diff --git a/src/pages/events.astro b/src/pages/events.astro index 2d2c834..d0854dc 100644 --- a/src/pages/events.astro +++ b/src/pages/events.astro @@ -1,62 +1,71 @@ --- +import { getCollection, render } from "astro:content"; +import { getPacificToday } from "../utils/dateTime"; + import BaseLayout from "../layouts/BaseLayout.astro"; import EventCard from "../components/EventCard.astro"; +import PageHeader from "../components/PageHeader.astro"; + +// Loads all the Markdown event entries +const events = await getCollection("events"); + +// Determine today's calendar date in BMDIB's local Pacific timezone. +// Using YYYY-MM-DD allows reliable string comparison with event dates. +const today = getPacificToday(); + +// Current and upcoming events are sorted from earliest to latest. +// If multiple events occur on the same date, sort them by time. +const upcomingEvents = events + .filter((event) => event.data.date >= today) + .sort((a, b) => { + const dateComparison = a.data.date.localeCompare(b.data.date); + + if (dateComparison !== 0) { + return dateComparison; + } + + return (a.data.time ?? "").localeCompare(b.data.time ?? ""); + }); + +// Past events are sorted from most recent to oldest. +// If multiple events occurred on the same date, show the later one first. +const pastEvents = events + .filter((event) => event.data.date < today) + .sort((a, b) => { + const dateComparison = b.data.date.localeCompare(a.data.date); + + if (dateComparison !== 0) { + return dateComparison; + } + + return b.data.time.localeCompare(a.data.time); + }); -const upcomingEvents = [ - { - title: "BMDIB Community Event", - date: "Date TBD", - location: "Location TBD", - description: - "Placeholder description for an upcoming BMDIB community event.", - }, - { - title: "Mandarin Cultural Event", - date: "Date TBD", - location: "Location TBD", - description: - "Placeholder description for an upcoming Mandarin cultural event.", - }, -]; - -const pastEvents = [ - { - title: "BMDIB Community Event", - date: "Past Date", - location: "Location TBD", - description: - "Placeholder description for a past BMDIB community event.", - }, - { - title: "Mandarin Cultural Event", - date: "Past Date", - location: "Location TBD", - description: - "Placeholder description for a past Mandarin cultural event.", - }, -]; +// Render the Markdown body for each event before generating the page markup. +const renderedUpcomingEvents = await Promise.all( + upcomingEvents.map(async (event) => ({ + event, + Content: (await render(event)).Content, + })) +); + +const renderedPastEvents = await Promise.all( + pastEvents.map(async (event) => ({ + event, + Content: (await render(event)).Content, + })) +); --- -
-
-
-
-

Events

- -

Events

- -

- Placeholder introduction to BMDIB events. Final content will be - provided by the organization. -

-
-
-
-
+
@@ -68,9 +77,16 @@ const pastEvents = [
{ - upcomingEvents.map((event) => ( + renderedUpcomingEvents.map(({ event, Content }) => (
- + + +
)) } @@ -88,9 +104,17 @@ const pastEvents = [
{ - pastEvents.map((event) => ( -
- + renderedPastEvents.map(({ event, Content }) => ( +
+ + +
)) } diff --git a/src/pages/fundraising.astro b/src/pages/fundraising.astro index eb43a6e..6fb21e1 100644 --- a/src/pages/fundraising.astro +++ b/src/pages/fundraising.astro @@ -1,27 +1,17 @@ --- import BaseLayout from "../layouts/BaseLayout.astro"; +import PageHeader from "../components/PageHeader.astro"; --- -
-
-
-
-

Fundraising

- -

Support Mandarin Boosters

- -

- Placeholder introduction to BMDIB fundraising. Final content will - be provided by the organization. -

-
-
-
-
+
diff --git a/src/pages/index.astro b/src/pages/index.astro index 9bf5fee..ac7409a 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -1,10 +1,11 @@ + --- import BaseLayout from "../layouts/BaseLayout.astro"; ---
@@ -18,8 +19,9 @@ import BaseLayout from "../layouts/BaseLayout.astro";

- Placeholder introduction for BMDIB. Final homepage messaging will - be provided by the organization. + Championing bilingual, bicultural, and biliterate + excellence through academic support, cultural + enrichment, and community involvement.

@@ -46,13 +48,27 @@ import BaseLayout from "../layouts/BaseLayout.astro";

Supporting our Mandarin immersion community

- Placeholder mission content. The organization's official mission - statement will be added when provided by the board. + Our mission is to champion Berryessa Union School + District's K–8 Mandarin Dual Language Immersion + Program by partnering with district leaders to + ensure long-term policy support, providing + fundraising and classroom resources, and promoting + strong parent engagement. +

+ +

+ We foster cultural exchange, connect elementary + and middle school programs, and collaborate with + other Mandarin immersion programs statewide and + nationally.

- Additional placeholder content can be used here to establish the - final layout and spacing. + Through academic support, cultural enrichment, + and community involvement, we strive to empower + students to achieve bilingual, bicultural, and + biliterate excellence, preparing them to thrive + as global citizens.

@@ -71,13 +87,24 @@ import BaseLayout from "../layouts/BaseLayout.astro";

- Placeholder history content. This section will introduce the - history of Mandarin Boosters and explain how the organization - developed over time. + Berryessa's Mandarin Dual Immersion Program + started in 2018 with two kindergarten classes + and one first-grade class. The program came + together through the advocacy of a group of + parents committed to creating a supportive + Mandarin learning environment for their children. + With the support of the school district, the + program came to live at Cherrywood Elementary School + in 2018 and has since expanded through 8th + grade.

- The final history narrative will be provided by the organization. + Previously operating as Cherrywood Home & + School Club, Berryessa Mandarin Dual Immersion + Boosters was formed following school + consolidation, when the Mandarin Dual Immersion + Program moved to Ruskin Elementary School.

@@ -94,9 +121,11 @@ import BaseLayout from "../layouts/BaseLayout.astro";

Be part of our community

- Placeholder content for a short call to action. This section can - guide visitors toward fundraising, events, resources, or other ways - to participate. + Join us in supporting Mandarin immersion + education through cultural activities, + community events, and fundraising initiatives. + Together, we can create meaningful learning + experiences for our students.

@@ -106,4 +135,4 @@ import BaseLayout from "../layouts/BaseLayout.astro";
-
\ No newline at end of file + diff --git a/src/pages/meetings.astro b/src/pages/meetings.astro index 56f1074..04a2fae 100644 --- a/src/pages/meetings.astro +++ b/src/pages/meetings.astro @@ -1,76 +1,87 @@ --- +import { getCollection, render } from "astro:content"; +import { getPacificToday } from "../utils/dateTime"; + import BaseLayout from "../layouts/BaseLayout.astro"; import MeetingCard from "../components/MeetingCard.astro"; +import PageHeader from "../components/PageHeader.astro"; + +const meetings = await getCollection("meetings"); + +const today = getPacificToday(); + +const upcomingMeetings = meetings + .filter((meeting) => meeting.data.date >= today) + .sort((a, b) => { + const dateComparison = a.data.date.localeCompare(b.data.date); + + if (dateComparison !== 0) { + return dateComparison; + } + + return a.data.time.localeCompare(b.data.time); + }); + +const pastMeetings = meetings + .filter((meeting) => meeting.data.date < today) + .sort((a, b) => { + const dateComparison = b.data.date.localeCompare(a.data.date); + + if (dateComparison !== 0) { + return dateComparison; + } + + return b.data.time.localeCompare(a.data.time); + }); -const upcomingMeetings = [ - { - title: "BMDIB General Meeting", - date: "Date TBD", - location: "Location TBD", - agenda: "#", - }, - { - title: "BMDIB General Meeting", - date: "Date TBD", - location: "Location TBD", - agenda: "#", - }, -]; - -const pastMeetings = [ - { - title: "BMDIB General Meeting", - date: "Past Date", - location: "Location TBD", - agenda: "#", - slides: "#", - minutes: "#", - }, - { - title: "BMDIB General Meeting", - date: "Past Date", - location: "Location TBD", - agenda: "#", - slides: "#", - minutes: "#", - }, -]; +const renderedUpcomingMeetings = await Promise.all( + upcomingMeetings.map(async (meeting) => ({ + meeting, + Content: (await render(meeting)).Content, + })) +); + +const renderedPastMeetings = await Promise.all( + pastMeetings.map(async (meeting) => ({ + meeting, + Content: (await render(meeting)).Content, + })) +); --- -
-
-
-
-

General Meetings

- -

General Meetings

- -

- Placeholder introduction to BMDIB general meetings. Final content - will be provided by the organization. -

-
-
-
-
+
-

Upcoming Meetings

+

Current & Upcoming Meetings

{ - upcomingMeetings.map((meeting) => ( + renderedUpcomingMeetings.map(({ meeting, Content }) => (
- + + +
)) } @@ -88,9 +99,19 @@ const pastMeetings = [
{ - pastMeetings.map((meeting) => ( + renderedPastMeetings.map(({ meeting, Content }) => (
- + + +
)) } diff --git a/src/pages/resources.astro b/src/pages/resources.astro index 84f2057..19bf71f 100644 --- a/src/pages/resources.astro +++ b/src/pages/resources.astro @@ -1,5 +1,6 @@ --- import BaseLayout from "../layouts/BaseLayout.astro"; +import PageHeader from "../components/PageHeader.astro"; const resourceCategories = [ { @@ -77,22 +78,11 @@ const resourceCategories = [ title="Resources | Mandarin Boosters" description="Resources for BMDIB families, students, educators, and the community." > -
-
-
-
-

Resources

- -

Resources

- -

- Placeholder introduction to resources for BMDIB families, - students, educators, and the broader community. -

-
-
-
-
+
diff --git a/src/styles/global.css b/src/styles/global.css index 613a7bd..640c1a8 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -204,6 +204,26 @@ h6 { } } +/* + * PageHeader + */ + +.page-header { + padding: 4rem 0 3rem; + background-color: var(--color-background); +} + +.page-header h1 { + margin-bottom: 1rem; + color: var(--color-primary-dark); +} + +.page-header .lead { + max-width: 42rem; + margin-right: auto; + margin-left: auto; +} + /* * Homepage */ @@ -270,22 +290,6 @@ h6 { * Board page */ -.board-intro { - padding: 4rem 0 3rem; - background-color: var(--color-background); -} - -.board-intro h1 { - margin-bottom: 1rem; - color: var(--color-primary-dark); -} - -.board-intro .lead { - max-width: 42rem; - margin-right: auto; - margin-left: auto; -} - .board-members { padding: 3rem 0 5rem; background-color: var(--color-surface); @@ -345,22 +349,6 @@ h6 { * Events page */ -.events-intro { - padding: 4rem 0 3rem; - background-color: var(--color-background); -} - -.events-intro h1 { - margin-bottom: 1rem; - color: var(--color-primary-dark); -} - -.events-intro .lead { - max-width: 42rem; - margin-right: auto; - margin-left: auto; -} - .events-upcoming, .events-past { padding: 3rem 0 5rem; @@ -418,103 +406,66 @@ h6 { color: var(--color-text-muted); } -/* - * Competitions page - */ - -.competitions-intro { - padding: 4rem 0 3rem; - background-color: var(--color-background); -} - -.competitions-intro h1 { - margin-bottom: 1rem; - color: var(--color-primary-dark); -} - -.competitions-intro .lead { - max-width: 42rem; - margin-right: auto; - margin-left: auto; -} - -.competitions-upcoming, -.competitions-past { - padding: 3rem 0 5rem; +.event-card { + overflow: hidden; } -.competitions-upcoming { - background-color: var(--color-surface); +.event-card-image { + width: 100%; + aspect-ratio: 16 / 9; + object-fit: cover; + display: block; } -.competitions-past { - background-color: var(--color-background); +.event-card .carousel { + aspect-ratio: 16 / 9; + overflow: hidden; } -.competitions-upcoming h2, -.competitions-past h2 { - margin-bottom: 2rem; - color: var(--color-primary-dark); +.event-card .carousel-inner, +.event-card .carousel-item { + width: 100%; + height: 100%; } -.competition-card { +.event-card .carousel-item img { + width: 100%; height: 100%; - background-color: var(--color-surface); - border: 1px solid rgba(41, 41, 41, 0.1); - border-radius: 0.5rem; - box-shadow: 0 0.125rem 0.5rem rgba(41, 41, 41, 0.06); + object-fit: cover; } -.competition-card-content { - padding: 1.5rem; +/* + * Competitions page + */ + +.competition-article { + max-width: 800px; } -.competition-card-date { - margin-bottom: 0.5rem; - color: var(--color-primary); - font-size: 0.875rem; - font-weight: 700; - letter-spacing: 0.04em; - text-transform: uppercase; +.competition-article p { + line-height: 1.8; } -.competition-card-content h2 { - margin-bottom: 0.5rem; - font-size: 1.25rem; - color: var(--color-primary-dark); +.competition-gallery figure { + margin-bottom: 2.5rem; } -.competition-card-location { - margin-bottom: 1rem; - color: var(--color-secondary); - font-weight: 600; +.competition-photo { + display: block; + width: 100%; + height: auto; } -.competition-card-content > p:last-child { - margin-bottom: 0; - color: var(--color-text-muted); +.competition-gallery figcaption { + font-size: 0.9rem; + line-height: 1.5; + text-align: center; } /* * General Meetings page */ -.meetings-intro { - padding: 4rem 0 3rem; - background-color: var(--color-background); -} - -.meetings-intro h1 { - margin-bottom: 1rem; - color: var(--color-primary-dark); -} - -.meetings-intro .lead { - max-width: 42rem; - margin-right: auto; - margin-left: auto; -} - .meetings-upcoming, .meetings-past { padding: 3rem 0 5rem; @@ -592,22 +543,6 @@ h6 { * Fundraising page */ -.fundraising-intro { - padding: 4rem 0 3rem; - background-color: var(--color-background); -} - -.fundraising-intro h1 { - margin-bottom: 1rem; - color: var(--color-primary-dark); -} - -.fundraising-intro .lead { - max-width: 42rem; - margin-right: auto; - margin-left: auto; -} - .fundraising-why, .fundraising-campaign { padding: 4rem 0; @@ -642,22 +577,6 @@ h6 { * Resources page */ -.resources-intro { - padding: 4rem 0 3rem; - background-color: var(--color-background); -} - -.resources-intro h1 { - margin-bottom: 1rem; - color: var(--color-primary-dark); -} - -.resources-intro .lead { - max-width: 42rem; - margin-right: auto; - margin-left: auto; -} - .resources-content { padding: 4rem 0 5rem; background-color: var(--color-surface); diff --git a/src/utils/dateTime.ts b/src/utils/dateTime.ts new file mode 100644 index 0000000..0e1bbcd --- /dev/null +++ b/src/utils/dateTime.ts @@ -0,0 +1,36 @@ +// The event date and time are stored as local Pacific calendar values. +// UTC is used here only as a neutral formatting mechanism so that the +// build machine's timezone does not change the displayed values. + +// Example, if there are date: "2026-11-14" and time: "17:00" +// in Markdown, it converts 2026/11/14 00:00 UTC time to this specific +// weekday, year, month, day format. + +export function formatDate(date: string): string { + const [year, month, day] = date.split("-").map(Number); + + return new Intl.DateTimeFormat("en-US", { + weekday: "short", + year: "numeric", + month: "long", + day: "numeric", + timeZone: "UTC", + }).format(new Date(Date.UTC(year, month - 1, day))); +} + +export function formatTime(time: string): string { + const [hour, minute] = time.split(":").map(Number); + + return new Intl.DateTimeFormat("en-US", { + hour: "numeric", + minute: "2-digit", + hour12: true, + timeZone: "UTC", + }).format(new Date(Date.UTC(2000, 0, 1, hour, minute))); +} + +export function getPacificToday(): string { + return new Date().toLocaleDateString("en-CA", { + timeZone: "America/Los_Angeles", + }); +} \ No newline at end of file diff --git a/staticwebapp.config.json b/staticwebapp.config.json new file mode 100644 index 0000000..09d4d03 --- /dev/null +++ b/staticwebapp.config.json @@ -0,0 +1,25 @@ +{ + "auth": { + "identityProviders": { + "azureActiveDirectory": { + "registration": { + "openIdIssuer": "https://login.microsoftonline.com/a2972296-16d7-4a73-a37a-95aef3123bff/v2.0", + "clientIdSettingName": "AZURE_CLIENT_ID", + "clientSecretSettingName": "AZURE_CLIENT_SECRET" + } + } + } + }, + "routes": [ + { + "route": "/*", + "allowedRoles": ["authenticated"] + } + ], + "responseOverrides": { + "401": { + "statusCode": 302, + "redirect": "/.auth/login/aad" + } + } +} \ No newline at end of file