A client-side web application for visualizing daily work shifts with special handling for overnight shifts. Built with vanilla JavaScript, HTML, and CSS.
- 📅 View shifts by date with easy navigation
- 🌙 Automatic overnight shift detection and display
- 💾 Local storage persistence (no backend required)
- 📱 Mobile-responsive design
- 🎨 Color-coded shifts by shift type
- ✅ JSON validation with detailed error messages
- 🔄 Merge capability to update existing shifts
Simply open index.html in your web browser. No build process or server required!
For the best experience (especially if you encounter CORS issues), serve the files with a local server:
# Using Python 3
python -m http.server 8000
# Using Node.js (install http-server globally first)
npx http-server
# Using PHP
php -S localhost:8000Then open http://localhost:8000 in your browser.
- Open the application in your browser
- Click "Go to Settings" (or the Settings button)
- Copy the AI prompt text (optional - for converting your shift plan)
- Paste your shift JSON in the "Shift Plan JSON" textarea
- Click "Save"
Try this sample JSON to get started:
{
"shifts": [
{"day": "2026-01-06", "shift_type": "Morning", "start_time": "08:30", "end_time": "17:00"},
{"day": "2026-01-07", "shift_type": "Night", "start_time": "22:00", "end_time": "07:00"},
{"day": "2026-01-08", "shift_type": "Morning", "start_time": "08:30", "end_time": "17:00"},
{"day": "2026-01-09", "shift_type": null, "start_time": null, "end_time": null},
{"day": "2026-01-10", "shift_type": "Afternoon", "start_time": "14:00", "end_time": "22:00"}
]
}- Use Previous Day and Next Day buttons to navigate between dates
- Current date is displayed at the top
- Overnight shifts show "(tomorrow)" indicator
- Previous day's overnight shift end time is displayed when applicable
If a shift's end time is earlier than its start time, it's automatically treated as an overnight shift:
- On the shift's date: Shows "End time: 07:00 (tomorrow)"
- On the next date: Shows "Yesterday's shift end: 07:00"
- Go to Settings
- Paste new JSON with the shifts you want to add or update
- Click Save
- Shifts for existing dates will be replaced
- New dates will be added
The application expects JSON in this format:
{
"shifts": [
{
"day": "YYYY-MM-DD",
"shift_type": "string or null",
"start_time": "HH:MM or null",
"end_time": "HH:MM or null"
}
]
}Field Descriptions:
day(required): ISO date format (YYYY-MM-DD)shift_type(optional): Any string identifier, or nullstart_time(optional): 24-hour time (HH:MM), or nullend_time(optional): 24-hour time (HH:MM), or null
Special Handling:
- If both
start_timeandend_timeare null: "No shift" displayed - If
start_timeis null butend_timeis set: Defaults to 00:00 start - If
end_timeis null butstart_timeis set: Defaults to 23:59 end - If
end_time<start_time: Overnight shift (ends next day)
- ES6 Modules: Native browser module support (no bundler required)
- localStorage: All data stored client-side
- Vanilla JS: No frameworks or libraries
- Mobile-first CSS: Responsive design for all screen sizes
Tested and working on latest versions of:
- Chrome
- Firefox
- Safari
- Edge
Requires ES6 module support (all modern browsers).
shift-visualizer/
├── index.html # Entry point
├── styles.css # All styling
├── app.js # Application orchestrator
├── dateUtils.js # Date manipulation utilities
├── storage.js # localStorage interface
├── shiftModel.js # Shift data model and logic
├── validation.js # JSON validation
├── mainView.js # Main view rendering
├── settingsView.js # Settings view rendering
└── README.md # This file
- 100% Client-Side: No data leaves your browser
- No Network Calls: Works completely offline once loaded
- localStorage Only: Data stored only in your browser
- No Tracking: No analytics or tracking of any kind
- Go to Settings and paste valid JSON
- Check that your JSON follows the correct format
- Ensure dates are in YYYY-MM-DD format
- Ensure times are in HH:MM format (24-hour)
- Check that all quotes and braces are properly closed
- Verify the structure matches the example
- Check if localStorage is enabled in your browser
- Some browsers block localStorage in private/incognito mode
- Check browser console for error messages
- If using file:// protocol, some browsers block ES6 modules
- Use a local web server instead (see "Getting Started" above)
This project is open source and available for personal and commercial use.
For issues or questions, please refer to the PRD (prd.md) for detailed specifications and requirements.