Skip to content

Commit 13be535

Browse files
Merge branch 'main' into feat/stop-route-labels-256
2 parents f62aa7b + f7f170d commit 13be535

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1690
-123
lines changed

.claude/agents/simplify.md

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
---
2+
name: simplify
3+
description: Use to simplify JavaScript/TypeScript/Svelte code before code review. Invoke with "simplify my branch", "simplify these changes", or "use simplify on these changes". Analyzes git diff against main, iterates file-by-file, proposes refactors interactively.
4+
tools: Read, Grep, Glob, Bash, Write, Task
5+
---
6+
7+
You are an opinionated code simplifier for JavaScript, TypeScript, and SvelteKit projects. Your job is to make code cleaner, more readable, and more maintainable before code review.
8+
9+
## Workflow
10+
11+
1. **Get the diff**: Run `git diff main...HEAD --name-only` to find changed files
12+
2. **Filter**: Only process `.js`, `.ts`, `.svelte` files
13+
3. **Iterate file-by-file**: For each file:
14+
- Show the filename
15+
- Read the file and the diff for that file (`git diff main...HEAD -- <file>`)
16+
- Analyze against simplification principles
17+
- Present numbered proposals + observations
18+
- Wait for user input before proceeding
19+
20+
## Before proposing changes
21+
22+
**Always consult Svelte/SvelteKit conventions first.** Use the Svelte MCP tools:
23+
24+
- `list-sections` to find relevant documentation sections
25+
- `get-documentation` to fetch current best practices
26+
- `svelte-autofixer` to detect anti-patterns in Svelte files
27+
28+
This ensures your suggestions align with Svelte 5 and SvelteKit conventions, not outdated patterns.
29+
30+
## Interaction format
31+
32+
Present proposals like this:
33+
34+
```
35+
## src/routes/dashboard/+page.svelte
36+
37+
### Proposals
38+
1. [Lines 23-41] Flatten nested if/else into early returns
39+
2. [Lines 67-89] Extract repeated fetch error handling into `$lib/utils/fetch.ts`
40+
3. [Lines 102-108] Rename `d` to `dashboardData` for clarity
41+
42+
### Observations
43+
- This component is 180 lines. Consider extracting the chart configuration (lines 100-150) into a separate component.
44+
- The reactive statement on line 45 recalculates on every state change. Consider using $derived with more specific dependencies.
45+
46+
[1] [2] [3] [all] [skip] [discuss N]
47+
```
48+
49+
Wait for user response:
50+
51+
- `1`, `2`, `3`, etc. → Apply that specific proposal, show the change, confirm
52+
- `all` → Apply all proposals in sequence
53+
- `skip` → Move to next file
54+
- `discuss 2` → Explain proposal 2 in detail, show before/after, wait for approval
55+
56+
After applying changes or skipping, move to the next file. Continue until all files are processed.
57+
58+
## Simplification principles (opinionated)
59+
60+
### Control flow
61+
62+
- **Early returns over nested conditionals.** Flip conditions and return/continue early.
63+
- **No nested ternaries.** One level max. Otherwise use if/else or extract to a function.
64+
- **Guard clauses first.** Handle edge cases and errors at the top of functions.
65+
- **Prefer `switch` with early returns** over long if/else chains when matching discrete values.
66+
67+
### Functions
68+
69+
- **Max 30 lines per function.** If longer, it probably does too much—extract.
70+
- **Single responsibility.** A function should do one thing. "And" in a description = split it.
71+
- **Max 3 parameters.** More than 3? Use an options object.
72+
- **No boolean parameters** that change behavior. Use two functions or an options object.
73+
- **Name functions for what they return**, not what they do internally. `getUserRole()` not `checkUserAndGetRole()`.
74+
75+
### Naming
76+
77+
- **Variables: nouns.** `user`, `dashboardData`, `isLoading`
78+
- **Functions: verbs.** `fetchUser`, `calculateTotal`, `handleSubmit`
79+
- **Booleans: `is`, `has`, `should`, `can`.** `isActive`, `hasPermission`
80+
- **No abbreviations** unless universally understood (`id`, `url`, `api`). `btn``button`, `msg``message`
81+
- **No single-letter variables** except in very short lambdas or loop indices.
82+
83+
### Svelte/SvelteKit specific
84+
85+
- **Use `$state` and `$derived`** (Svelte 5 runes), not legacy `let` + `$:` reactive statements.
86+
- **Prefer `onclick` over `on:click`** (Svelte 5 syntax).
87+
- **Colocate related logic** in the same file unless it's reused elsewhere.
88+
- **Use `+page.server.ts` for data loading**, not client-side fetches in `onMount`.
89+
- **Use `$lib` aliases** for imports from lib folder.
90+
- **Form actions over API routes** for mutations when possible.
91+
- **Keep components under 150 lines.** Extract sub-components or move logic to `.svelte.ts` files.
92+
93+
### Extraction patterns
94+
95+
- **Repeated code (2+ times)**: Extract to a function or component.
96+
- **Complex conditionals**: Extract to a well-named boolean or function.
97+
- **Magic numbers/strings**: Extract to named constants.
98+
- **Fetch/error handling patterns**: Extract to `$lib/utils/`.
99+
- **Shared component logic**: Extract to `$lib/components/` or colocate in same folder.
100+
101+
### Removal
102+
103+
- **Dead code**: Unused imports, unreachable branches, commented-out code.
104+
- **Unnecessary abstractions**: If a wrapper adds no value, inline it.
105+
- **Redundant type annotations**: Let TypeScript infer when obvious.
106+
107+
## Summary
108+
109+
After all files are processed, provide a summary:
110+
111+
```
112+
## Summary
113+
114+
### Applied
115+
- src/routes/dashboard/+page.svelte: 3 refactors (early returns, fetch helper, naming)
116+
- src/lib/components/DataTable.svelte: 1 refactor (extracted sort logic)
117+
118+
### Skipped
119+
- src/routes/api/health/+server.ts: No changes needed
120+
121+
### Observations to consider later
122+
- Dashboard component could be split into smaller pieces
123+
- Consider adding error boundary around chart section
124+
```
125+
126+
## Important
127+
128+
- **Don't change behavior.** These are refactors, not rewrites. Tests should still pass.
129+
- **Preserve comments** that explain "why", but remove obvious "what" comments.
130+
- **One thing at a time.** Apply proposals individually so user can review each change.
131+
- **Be specific.** Show line numbers, show before/after snippets.
132+
- **Respect user decisions.** If they skip something, don't bring it up again.

.claude/settings.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"WebFetch(domain:github.com)",
5+
"Bash(cat:*)",
6+
"Bash(gh issue edit:*)",
7+
"Bash(grep:*)",
8+
"Bash(npm run prepush:*)",
9+
"Bash(find:*)",
10+
"Bash(sort:*)",
11+
"Bash(npm run build:*)",
12+
"Bash(npm run test:*)"
13+
]
14+
}
15+
}

.env.example

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,38 @@ PRIVATE_OBACO_SHOW_TEST_ALERTS=false
1010
PUBLIC_NAV_BAR_LINKS={"Home": "/","About": "/about","Contact": "/contact","Fares & Tolls": "/fares-and-tolls"}
1111
PUBLIC_OBA_GOOGLE_MAPS_API_KEY=""
1212
PUBLIC_OBA_LOGO_URL="https://onebusaway.org/wp-content/uploads/oba_logo-1.png"
13+
FAVICON_URL=""
1314
PUBLIC_OBA_MAP_PROVIDER="osm"
1415

1516
PUBLIC_OBA_REGION_CENTER_LAT=47.60728155903877
1617
PUBLIC_OBA_REGION_CENTER_LNG=-122.3339240843084
1718
PUBLIC_OBA_REGION_NAME="Puget Sound"
1819

20+
# Set to "false" to hide the region name text in the navigation bar
21+
SHOW_REGION_NAME_IN_NAV_BAR=true
22+
1923
PUBLIC_OBA_SERVER_URL="https://api.pugetsound.onebusaway.org/"
2024

2125
PUBLIC_OTP_SERVER_URL=""
2226

23-
# 1 TUE, 2 WED, 3 THU, 4 FRI, 5 SAT, 6 SUN, 0 MON
27+
# 1 TUE, 2 WED, 3 THU, 4 FRI, 5 SAT, 6 SUN, 0 MON
2428
PUBLIC_CALENDAR_FIRST_DAY_OF_WEEK=6
2529

30+
# Nav bar background, primary buttons
31+
COLOR_BRAND_PRIMARY="#78aa36"
32+
33+
# Text on brand-primary surfaces
34+
COLOR_BRAND_PRIMARY_FOREGROUND="#ffffff"
35+
36+
# Links, selected states, focus rings
37+
COLOR_BRAND_ACCENT="#486621"
38+
39+
# Panel backgrounds
40+
COLOR_SURFACE="#ffffff"
41+
42+
# Panel text
43+
COLOR_SURFACE_FOREGROUND="#000000"
44+
2645
# Analytics
2746
PUBLIC_ANALYTICS_DOMAIN=""
2847
PUBLIC_ANALYTICS_ENABLED=true

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ vite.config.js.timestamp-*
2121
vite.config.ts.timestamp-*
2222

2323
coverage/
24-
.claude
24+
.claude/settings.local.json

.mcp.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"mcpServers": {
3+
"svelte": {
4+
"type": "stdio",
5+
"command": "npx",
6+
"args": ["-y", "@sveltejs/mcp"],
7+
"env": {}
8+
}
9+
}
10+
}

README.md

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,51 @@ npm run dev
1717

1818
See `.env.example` for an example of the required keys and values.
1919

20-
### Visuals
20+
### Analytics
2121

22-
- `PUBLIC_OBA_REGION_NAME` - string: (required) displayed in the header.
23-
- `PUBLIC_OBA_LOGO_URL` - string: (required) The URL of your transit agency's logo.
24-
- `PUBLIC_NAV_BAR_LINKS` - JSON string: (required) A dictionary of the links displayed across the navigation bar.
25-
- `PUBLIC_APP_PRIMARY_COLOR` - string: (required) The hex color code for the application's primary brand color. Must be wrapped in quotes (e.g., "#214666").
26-
- `PUBLIC_APP_SECONDARY_COLOR` - string: (required) The hex color code for the application's secondary brand color. Must be wrapped in quotes (e.g., "#486621").
2722
- `PUBLIC_ANALYTICS_DOMAIN` - string: (optional).
2823
- `PUBLIC_ANALYTICS_ENABLED` - boolean: (optional).
2924
- `PUBLIC_ANALYTICS_API_HOST` - string: (optional).
3025

26+
### Text and Images
27+
28+
- `PUBLIC_OBA_REGION_NAME` - string: (required) displayed in the header.
29+
- `PUBLIC_OBA_LOGO_URL` - string: (required) The URL of your transit agency's logo.
30+
- `SHOW_REGION_NAME_IN_NAV_BAR` - boolean: (optional) Set to "false" to hide the region name text in the navigation bar. Defaults to true.
31+
- `FAVICON_URL` - string: (optional) URL to a custom favicon. Falls back to the default favicon if not specified.
32+
- `PUBLIC_NAV_BAR_LINKS` - JSON string: (required) A dictionary of the links displayed across the navigation bar.
33+
34+
### Colors
35+
36+
Customize the application's color scheme via environment variables:
37+
38+
- `COLOR_BRAND_PRIMARY` - string: (optional) Primary brand color for nav bar and buttons. Default: "#78aa36".
39+
- `COLOR_BRAND_PRIMARY_FOREGROUND` - string: (optional) Text color on brand-colored surfaces. Default: "#ffffff".
40+
- `COLOR_BRAND_ACCENT` - string: (optional) Accent color for links, selected states, focus rings. Default: "#486621".
41+
- `COLOR_SURFACE` - string: (optional) Background color for panels and surfaces. Default: "#ffffff".
42+
- `COLOR_SURFACE_FOREGROUND` - string: (optional) Text color on surfaces. Default: "#000000".
43+
44+
> **Note:** Color variables (`COLOR_*`) are processed at build time by Tailwind CSS. After changing any color values, you must rebuild the application (`npm run build`) for changes to take effect.
45+
46+
#### Generated Primary Palette
47+
48+
A full 10-shade color palette is automatically generated from `COLOR_BRAND_ACCENT` for use with Flowbite components:
49+
50+
| Shade | Description |
51+
| ------------- | -------------------------------------------- |
52+
| `primary-50` | Very light (95% white) |
53+
| `primary-100` | Light (90% white) |
54+
| `primary-200` | Light (75% white) |
55+
| `primary-300` | Light-medium (60% white) |
56+
| `primary-400` | Slightly lighter than base (30% white) |
57+
| `primary-500` | **Base color** (equals `COLOR_BRAND_ACCENT`) |
58+
| `primary-600` | Slightly darker (15% black) |
59+
| `primary-700` | Medium-dark (30% black) |
60+
| `primary-800` | Dark (45% black) |
61+
| `primary-900` | Very dark (60% black) |
62+
63+
Use these in Tailwind classes: `bg-primary-500`, `text-primary-700`, `border-primary-300`, etc.
64+
3165
## Calendar Configuration
3266

3367
- `PUBLIC_CALENDAR_FIRST_DAY_OF_WEEK` - number: (optional) Sets the first day of the week for calendar components. Use 0 for Monday, 1 for Tuesday, 2 for Wednesday, 3 for Thursday, 4 for Friday, 5 for Saturday, 6 for Sunday. Defaults to 0 (Monday).
@@ -56,6 +90,30 @@ See `.env.example` for an example of the required keys and values.
5690

5791
- `PUBLIC_OTP_SERVER_URL` - string: (optional) Your OpenTripPlanner 1.x-compatible trip planner server URL.
5892

93+
## URL Parameters
94+
95+
You can link directly to a specific location on the map using URL query parameters:
96+
97+
| Parameter | Description | Example |
98+
| --------- | ----------------------------------- | ----------- |
99+
| `lat` | Latitude of the initial map center | `47.6062` |
100+
| `lng` | Longitude of the initial map center | `-122.3321` |
101+
102+
**Example URL:**
103+
104+
```
105+
https://your-wayfinder-instance.com/?lat=47.6062&lng=-122.3321
106+
```
107+
108+
**Validation rules:**
109+
110+
- Both `lat` and `lng` must be provided together
111+
- Latitude must be between -90 and 90
112+
- Longitude must be between -180 and 180
113+
- Coordinates must be within 200km of the configured region center (`PUBLIC_OBA_REGION_CENTER_LAT`/`PUBLIC_OBA_REGION_CENTER_LNG`)
114+
115+
When valid coordinates are provided, the map will center on that location and place a location marker there. The URL parameters are automatically cleaned from the browser address bar after being applied.
116+
59117
## Building
60118

61119
To create a production version of your app:

eslint.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ export default [
1616
...globals.node,
1717
L: 'readonly',
1818
google: 'readonly',
19-
$state: 'readonly'
19+
$state: 'readonly',
20+
__SHOW_REGION_NAME_IN_NAV_BAR__: 'readonly'
2021
}
2122
}
2223
},

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app.css

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@
44

55
@layer components {
66
.h1 {
7-
@apply mb-4 text-2xl font-semibold text-gray-900 dark:text-gray-300;
7+
@apply mb-4 text-2xl font-semibold text-surface-foreground dark:text-surface-foreground-dark;
88
}
99

1010
.h2 {
11-
@apply mb-4 text-xl font-semibold text-gray-900 dark:text-gray-300;
11+
@apply mb-4 text-xl font-semibold text-surface-foreground dark:text-surface-foreground-dark;
1212
}
1313

1414
.h3 {
15-
@apply mb-2 text-lg font-semibold dark:text-white;
15+
@apply mb-2 text-lg font-semibold dark:text-surface-foreground-dark;
1616
}
1717

1818
.modal-pane {
19-
@apply rounded-lg border-gray-500 bg-white/90 px-4 shadow-lg dark:bg-black dark:text-white dark:shadow-lg dark:shadow-gray-200/10;
19+
@apply rounded-lg border-gray-500 bg-surface/90 px-4 shadow-lg dark:bg-surface-dark dark:text-surface-foreground-dark dark:shadow-lg dark:shadow-gray-200/10;
2020
}
2121

2222
.tab-container {
@@ -28,15 +28,15 @@
2828
}
2929

3030
.tab-container__item--active {
31-
@apply border-b-2 border-brand-secondary text-brand-secondary;
31+
@apply border-b-2 border-brand-accent text-brand-accent;
3232
}
3333

3434
.button {
35-
@apply rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50;
35+
@apply rounded-md bg-surface px-3 py-2 text-sm font-semibold text-surface-foreground shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50;
3636
}
3737

3838
.button--primary {
39-
@apply rounded-md bg-brand-secondary px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-brand focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand-secondary;
39+
@apply rounded-md bg-brand-accent px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-brand focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand-accent;
4040
}
4141

4242
.rtl {

src/app.html

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
<head>
44
<meta charset="utf-8" />
55
<link rel="apple-touch-icon" sizes="180x180" href="%sveltekit.assets%/apple-touch-icon.png" />
6-
<link rel="icon" type="image/png" sizes="32x32" href="%sveltekit.assets%/favicon-32x32.png" />
7-
<link rel="icon" type="image/png" sizes="16x16" href="%sveltekit.assets%/favicon-16x16.png" />
86
<link rel="manifest" href="%sveltekit.assets%/site.webmanifest" />
97
<meta name="viewport" content="width=device-width, initial-scale=1" />
108
%sveltekit.head%

0 commit comments

Comments
 (0)