Skip to content

Building a Campus Arts Programming Site for October

•
•5 min read

I walk through building an arts programming site for a university campus, covering responsive design, event calendar integration, and how I used a reliable cost estimator to keep the budget on track.

Cover image for "Building a Campus Arts Programming Site for October"

When the October arts lineup hit the Emory campus, I realized the existing flyers and PDFs weren’t cutting it for students scrolling on their phones. I set out to build an arts programming site that would showcase each performance, let visitors filter by date or venue, and stay within a realistic budget. In this post I’ll share the stack I chose, the UI tricks that made the calendar feel native, and the budgeting hacks that kept the project from ballooning.

Why this matters: A well‑engineered campus events portal reduces manual updates, improves discoverability, and gives the arts department data they can actually act on.

#Picking a lightweight tech stack for an arts programming site

I wanted something that could spin up quickly, stay cheap on hosting, and still feel modern. After prototyping a few options, I landed on:

  1. Vite + React – instant dev server, ES module support, and easy HMR.
  2. Tailwind CSS – utility‑first styling keeps the CSS bundle under 30 KB.
  3. Cloudflare Workers – serverless functions for fetching event data from the university’s Google Sheet API, with a free tier that covers our traffic.

This combination gave me a full‑stack experience without managing a traditional server, which is perfect for a semester‑long project.

Tip: If you want to skip the serverless setup, I’ve been using Estimate Website Cost to model the hosting bill before I even write a line of code.

#Designing a responsive event calendar UI

A calendar is the heart of any arts programming site. I focused on three principles:

  • Mobile‑first layout – the grid collapses to a single column on screens < 640 px.
  • Accessible interactions – keyboard navigation and ARIA labels for screen readers.
  • Lazy loading – only the current month’s events are rendered initially.

Below is a stripped‑down React component that renders a month view using Tailwind’s grid utilities:

import { useState, useEffect } from "react";

interface Event {
  title: string;
  date: string; // ISO string
  location: string;
}

export default function Calendar() {
  const [events, setEvents] = useState<Event[]>([]);
  const [month, setMonth] = useState(new Date());

  useEffect(() => {
    fetch(`/api/events?month=${month.getMonth() + 1}`)
      .then((r) => r.json())
      .then(setEvents);
  }, [month]);

  const days = Array.from({ length: 30 }, (_, i) => i + 1);
  return (
    <div className="grid grid-cols-7 gap-2">
      {days.map((day) => (
        <div
          key={day}
          className="p-2 border rounded hover:bg-gray-100"
          role="gridcell"
          aria-label={`Day ${day}`}
        >
          <span className="text-sm font-medium">{day}</span>
          {events
            .filter((e) => new Date(e.date).getDate() === day)
            .map((e) => (
              <p key={e.title} className="text-xs mt-1">
                {e.title}
              </p>
            ))}
        </div>
      ))}
    </div>
  );
}

On line 12 you can see the fetch call that pulls events for the currently displayed month. The component re‑renders automatically when the user clicks the “next month” button (not shown here).

#Handling time zones and daylight saving

When I first deployed, events from the university’s schedule appeared an hour early during DST. The fix was to always store dates in UTC on the backend and convert them client‑side with Intl.DateTimeFormat. A quick utility function kept the UI consistent across browsers.

#Implementing serverless data fetching for campus events

The arts department maintains a public Google Sheet with columns for title, date, time, and venue. I used Cloudflare Workers to expose a thin JSON API:

addEventListener("fetch", (event) => {
  event.respondWith(handleRequest(event.request));
});

async function handleRequest(request) {
  const url = new URL(request.url);
  const month = url.searchParams.get("month");
  const sheetId = "1aBcD..."; // shortened for brevity
  const api = `https://sheets.googleapis.com/v4/spreadsheets/${sheetId}/values/Events!A:D?key=${API_KEY}`;
  const resp = await fetch(api);
  const data = await resp.json();

  const filtered = data.values
    .slice(1) // skip header
    .filter(([_, date]) => new Date(date).getMonth() + 1 == month)
    .map(([title, date, time, venue]) => ({
      title,
      date: `${date}T${time}:00Z`,
      location: venue,
    }));

  return new Response(JSON.stringify(filtered), {
    headers: { "Content-Type": "application/json" },
  });
}

Note: Remember to restrict the API key to the sheet’s domain; otherwise you expose a credential that could be abused.

The worker runs in under 50 ms per request, keeping the user experience snappy even on a campus Wi‑Fi network.

#Estimating and controlling website costs

Even with a free tier, I wanted to be sure the site wouldn’t surprise the department with hidden fees. I broke the budget into three buckets:

  • Hosting – Cloudflare Workers (free up to 100 k requests/day) and KV storage for static assets.
  • Domain & SSL – a standard .edu subdomain, $15/year.
  • Third‑party services – Google Sheets API (free for read‑only) and optional analytics.

Using the estimator, I entered these line items and got a transparent total of $22 per semester, well under the department’s $100 cap. The tool also highlighted that if traffic doubled, the Workers tier would still be free, confirming the scalability.

Warning: Don’t forget to account for future features like user‑submitted events; that could push you into the paid request tier.

#Deploy, test, and iterate

  1. Run a local build – npm run build and verify the dist/ folder is under 500 KB.
  2. Deploy with Wrangler – wrangler publish pushes the worker and static assets in one step.
  3. Smoke test on multiple devices – use Chrome DevTools’ device toolbar and a screen‑reader extension to catch accessibility gaps.
  4. Gather feedback – embed a tiny Google Form for attendees to rate the UI; iterate based on real usage.

Tip: The budget estimator I mentioned earlier can be re‑run after each major feature addition to keep the financial picture up‑to‑date without manual spreadsheets.

#Closing thoughts

Building an arts programming site for a university campus taught me that good tooling—both technical and financial—keeps a project lean and focused. By choosing a serverless stack, crafting an accessible calendar UI, and regularly checking the cost model with a reliable estimator, the October arts lineup launched on time and on budget. If you’re tackling a similar campus‑wide event portal, give the approach above a try and let the numbers guide your decisions as much as the code does. Happy coding!

Related posts

  • Link to article
    4 min read

    Wheeling Gaunt Day Programming Set: Cost‑Effective Site Build

    Learn how to build a Wheeling Gaunt Day programming set website while keeping the budget in check. Follow practical steps for cost estimation and efficient dev.

  • Link to article
    6 min read

    Building a Web Portal for Iowa’s Big Read Grants – Guide

    I share how I built a lightweight web portal for Iowa’s Big Read grants, from requirements to budgeting, and why accurate cost estimates matter for grant‑focused sites.