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
33 changes: 33 additions & 0 deletions .github/DISCUSSION_TEMPLATE/request-a-city.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
title: "[city request] "
labels: ["community"]
body:
- type: markdown
attributes:
value: |
Want StudyMap to cover your city? Tell us which one and why, we use these
requests to prioritize where the dataset grows next.
- type: input
id: city
attributes:
label: Which city?
description: Name the city (and state/country if it could be ambiguous).
validations:
required: true
- type: textarea
id: why
attributes:
label: Why this city?
description: What makes it student-relevant, e.g. exam centres, colleges, coaching hubs.
validations:
required: true
- type: dropdown
id: help
attributes:
label: Willing to help with data?
description: Adding places is a PR, see CONTRIBUTING.md.
options:
- "Yes, I can contribute places"
- "Maybe, depends on scope"
- "No, just requesting"
validations:
required: true
15 changes: 9 additions & 6 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ Pure TypeScript modules. No JSX, no React imports. Each file has a single respon
| File | What it does |
|------|-------------|
| `types.ts` | `Place`, `PlaceType`, `City` types; label maps |
| `places.ts` | Imports all 8 JSON files; exports `getPlaces()` and `filterPlaces()` |
| `places.ts` | Reads places from `studymap.config.ts`; exports `getPlaces()` and `filterPlaces()` |
| `geo.ts` | Haversine distance, `placesByDistance()`, `formatDistance()` |
| `map.ts` | `PLACE_TYPE_COLORS` (color-blind-safe palette); `directionsUrl()` |
| `share.ts` | URL state encode/decode for shareable filtered map links |
Expand All @@ -151,10 +151,10 @@ Pure TypeScript modules. No JSX, no React imports. Each file has a single respon
## Data flow

```
data/places/*.json
studymap.config.ts imports data/places/*.json, exports the merged Place[]
src/lib/places.ts getPlaces() merges all 8 files into one Place[]
src/lib/places.ts getPlaces() reads the config's Place[]
│ filterPlaces() narrows by type and/or city
src/components/map/places-map.tsx
Expand All @@ -176,7 +176,7 @@ src/components/pins/pin-popup.tsx
buildShareUrl(state) ← src/lib/share.ts
```

**No network requests at runtime.** The JSON is bundled at build time via static `import` statements in `places.ts`. The Leaflet tile layer (OpenStreetMap) is the only external request when the map is open.
**No network requests at runtime.** The JSON is bundled at build time via static `import` statements in `studymap.config.ts`. The Leaflet tile layer is the only external request when the map is open.

---

Expand All @@ -189,10 +189,13 @@ The single aggregation point for place data. Every component that needs places c
```ts
getPlaces(): Place[]
filterPlaces(places, { types?, cities? }): Place[]
MMR_CENTER // [lat, lng] for the initial map view
MMR_DEFAULT_ZOOM
getCities(places, preferredOrder?): City[]
```

Region and dataset settings (initial map center, default zoom, coordinate bounds, the
city display order, and which `data/places/*.json` files get loaded) live in
`studymap.config.ts` at the repo root, the one file a fork edits to retarget StudyMap.

### `src/lib/geo.ts`

All distance math lives here. Used by `places-map.tsx` to find the five nearest places when the user enables geolocation.
Expand Down
5 changes: 5 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@ Use [Conventional Commits](https://www.conventionalcommits.org/): `<type>: <shor

Optional scope in parens: `feat(calendar): add today label`. One logical change per commit.

## Get recognized

First merged PR? Add your GitHub handle to [CONTRIBUTORS.md](CONTRIBUTORS.md), in the
same PR or a quick follow-up.

## House rules

- No em dashes in any copy
Expand Down
16 changes: 16 additions & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Contributors

Everyone who has helped build StudyMap, whether through code, data, or docs.

- [@AnayDhawan](https://github.com/AnayDhawan)
- [@yakew7](https://github.com/yakew7)
- [@shauryagangrade](https://github.com/shauryagangrade)
- [@shauryagangrade-blip](https://github.com/shauryagangrade-blip)
- [@Circout-sudo](https://github.com/Circout-sudo)
- [@thunderrblitzyt-eng](https://github.com/thunderrblitzyt-eng)

## Adding yourself

Opened your first merged PR? Add your GitHub handle to the list above, alphabetical
order doesn't matter, append it. Do this in the same PR as your contribution, or a
quick follow-up if you forgot.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,24 @@ data/
- **shadcn/ui + Tailwind v4** (UI components)
- **next-themes** (dark/light mode)

## Running your own fork

Want StudyMap for a different city? Click "Use this template" above, then follow
[SELF-HOSTING.md](SELF-HOSTING.md): set your region and dataset in one config file, optionally
wire up your own Supabase project for sign-in, and deploy.

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md).

## Good first issues

New here? Start with an issue tagged [`good first issue`](https://github.com/StudentSuite/StudyMap/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) or browse everything tagged [`help wanted`](https://github.com/StudentSuite/StudyMap/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22). Adding a place from your own neighbourhood ([#18](https://github.com/StudentSuite/StudyMap/issues/18)) needs no coding at all.

## Contributors

See [CONTRIBUTORS.md](CONTRIBUTORS.md).

## License

MIT. See [LICENSE](LICENSE).
114 changes: 114 additions & 0 deletions SELF-HOSTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# Self-hosting StudyMap

Run StudyMap for your own city. Everything below works from a fork, no coding required beyond
editing one config file and your place data.

## What you get out of the box

- The interactive map, filters, search, and calendar for whatever `data/places/*.json` you provide.
- Two optional, signed-in-only features (saved places, personal calendar events) if you set up your
own Supabase project. Skip that section entirely and the app still works, just without those.

## 1. Get the code

Click "Use this template" at the top of [StudentSuite/StudyMap](https://github.com/StudentSuite/StudyMap)
to create your own copy, then clone it:

```bash
git clone https://github.com/<your-account>/<your-fork>.git
cd <your-fork>
npm install
```

## 2. Set your region and dataset

Everything region- and data-specific lives in one file: `studymap.config.ts` at the repo root.

```bash
cp studymap.config.example.ts studymap.config.ts
```

Edit it:

- `center`: `[lat, lng]` for the initial map view
- `defaultZoom`: initial zoom level (11-13 works well for a metro area)
- `bounds`: rough coordinate box around your region, used for data validation and map fitting
- `cities`: display order for the city filter (any city present in your data but missing here
still shows, just sorted alphabetically after)
- `places`: swap the sample imports for your own `data/places/*.json` files

The dataset itself follows the schema in [`data/CONTRIBUTING.md`](data/CONTRIBUTING.md): one JSON
file per place type, one object per place, with `id`, `name`, `type`, `city`, `lat`, `lng`,
`gmaps_link`, and `added_by`. `data/places.sample/` has two minimal example entries if you want to
start from a clean skeleton instead of the Mumbai dataset that ships with the template.

Validate as you go:

```bash
npm run validate
```

## 3. Environment variables

```bash
cp .env.example .env.local
```

- `NEXT_PUBLIC_MAPTILER_KEY` is required for the map basemap. Free tier, no credit card, at
[cloud.maptiler.com](https://cloud.maptiler.com/account/keys/).
- The Supabase variables are optional. Leave them blank and the map, filters, and calendar all
work; you just won't get sign-in or the two private features below. See step 5 to fill them in.

## 4. Run it

```bash
npm run dev
```

Open [http://localhost:3000/map](http://localhost:3000/map) and confirm your places show up in
the right spot.

## 5. Optional: sign-in, saved places, and personal calendar events

These three features (`src/app/login`, saved custom places, personal calendar events) need a
Supabase project:

1. Create a free project at [supabase.com](https://supabase.com).
2. Copy its URL and anon key into `.env.local` (`NEXT_PUBLIC_SUPABASE_URL`, `NEXT_PUBLIC_SUPABASE_ANON_KEY`).
3. In the Supabase SQL editor, run every file in `supabase/migrations/`, in filename order. Each
one creates its tables with row-level security already scoped to `auth.uid()`, so users can
only ever read or write their own rows.
4. Enable whichever auth providers you want (email, Google, etc.) under Authentication > Providers.

Skip this whole section if you only want the public map and calendar.

## 6. Deploy

Deploy like any standard Next.js app, for example on Vercel:

```bash
npx vercel
```

or import the repo at [vercel.com/new](https://vercel.com/new) and set the same environment
variables from step 3 in the project settings.

**Static export (`output: "export"`) is not supported.** Sign-in needs a live server: the OAuth
callback route exchanges a code for a session server-side, and middleware refreshes that session
on every request. Both are incompatible with a static build. Deploy to a normal server/edge
runtime instead, that's the default for Vercel and most other Next.js hosts.

## Keeping your fork current

StudyMap doesn't push updates to forks automatically. To pull in upstream fixes, add the original
repo as a remote and merge from it:

```bash
git remote add upstream https://github.com/StudentSuite/StudyMap.git
git fetch upstream
git merge upstream/main
```

Your `studymap.config.ts`, `.env.local`, and `data/places/*.json` are yours, upstream changes to
shared code (map, calendar, components) merge in without touching them, unless you've also edited
those files.
13 changes: 13 additions & 0 deletions data/places.sample/book_shop.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[
{
"id": "example-book_shop-01",
"name": "Example Street Book Shop",
"type": "book_shop",
"city": "example_city",
"lat": -0.01,
"lng": 0.01,
"address": "Replace with a real address",
"gmaps_link": "https://maps.google.com/?q=-0.01,0.01",
"added_by": "your-github-handle"
}
]
24 changes: 24 additions & 0 deletions data/places.sample/library.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[
{
"id": "example-library-01",
"name": "Example City Central Library",
"type": "library",
"city": "example_city",
"lat": 0,
"lng": 0,
"address": "Replace with a real address",
"gmaps_link": "https://maps.google.com/?q=0,0",
"added_by": "your-github-handle"
},
{
"id": "example-library-02",
"name": "Example University Library",
"type": "library",
"city": "example_city",
"lat": 0.01,
"lng": 0.01,
"address": "Replace with a real address",
"gmaps_link": "https://maps.google.com/?q=0.01,0.01",
"added_by": "your-github-handle"
}
]
43 changes: 43 additions & 0 deletions docs/OFFLINE_CACHING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Offline caching and stale content

StudyMap is a Progressive Web App (PWA). It registers a service worker
(`public/sw.js`) so the map still opens on exam day with a weak or absent
signal. This also means the app can keep serving cached content after a
deploy ships, which can look like "the fix never happened" when really your
browser or installed PWA is still holding the previous version.

## What gets cached

The service worker keeps two caches, both versioned by `VERSION` in
`public/sw.js`:

- **App cache** (`app-<version>`): the app shell (`/`, `/offline`,
`/manifest.webmanifest`), plus build output under `/_next/static` and
`/icons`. Static build assets are cache-first since they're
content-hashed and never change under the same URL. Page navigations try
the network first and fall back to the cache when offline.
- **Tile cache** (`tiles-<version>`): map tiles from `api.maptiler.com`,
cache-first, capped at 300 tiles so it doesn't grow unbounded.

On every deploy, `VERSION` changes, which causes the new service worker to
delete all caches that don't match the new version on activation. In most
cases a normal reload picks up the new version automatically. Staleness
happens when the browser hasn't fetched the new `sw.js` yet, usually because
the old service worker is still controlling the page or the browser served
`sw.js` itself from an HTTP cache.

## Forcing a fresh load

If the map or UI looks out of date after a known deploy, try these in order:

1. **Hard refresh**: reload while bypassing the cache (Cmd+Shift+R on
Mac, Ctrl+Shift+R on Windows/Linux, or Ctrl+F5).
2. **Clear site data**: in browser dev tools, Application (Chrome/Edge) or
Storage (Firefox) tab, clear Service Workers, Cache Storage, and Storage
for the site, then reload.
3. **Uninstall and reinstall the PWA**: if StudyMap was installed as an app,
remove it from your device and reinstall from the site to pick up a
fresh service worker.

If none of these help, the deploy itself likely hasn't shipped yet, so
check the deployment status before assuming it's a caching issue.
Loading
Loading