add README
This commit is contained in:
227
README.md
227
README.md
@@ -1,43 +1,206 @@
|
||||
# Svelte + Vite
|
||||
# Map Journal
|
||||
|
||||
This template should help get you started developing with Svelte in Vite.
|
||||
**Author:** _[Your Name]_
|
||||
**Student ID:** _[Your ID]_
|
||||
**Email:** _[Your Email]_
|
||||
|
||||
## Recommended IDE Setup
|
||||
**Repository:** <https://git.prototyping.id/20256426/Map-Jurnal.git>
|
||||
**Video Demo:** _[YouTube URL]_
|
||||
|
||||
[VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode).
|
||||
---
|
||||
|
||||
## Need an official Svelte framework?
|
||||
## Overview
|
||||
|
||||
Check out [SvelteKit](https://github.com/sveltejs/kit#readme), which is also powered by Vite. Deploy anywhere with its serverless-first approach and adapt to various platforms, with out of the box support for TypeScript, SCSS, and Less, and easily-added support for mdsvex, GraphQL, PostCSS, Tailwind CSS, and more.
|
||||
Map Journal is a single-page web application for documenting and visualizing travel experiences. Users log trips by country, pinning cities, dates, transport modes, and photos, and then explore their journey on an interactive world map or a timeline view.
|
||||
|
||||
## Technical considerations
|
||||
### How It Works
|
||||
|
||||
**Why use this over SvelteKit?**
|
||||
1. **Sign in** with a Google account.
|
||||
2. **Select your home country** — it is automatically marked as visited on the map.
|
||||
3. **Add journal entries** via a multi-step form:
|
||||
- **Step 1** — Choose country, cities, arrival date, days stayed, trip type (solo/friends/family), and transport (flight/train/bus/car/ship/walk).
|
||||
- **Step 2** — Upload photos (stored in Firebase Storage).
|
||||
- **Step 3** — Answer three random reflective questions about the trip (e.g., *"What was the most unexpected thing that happened?"*).
|
||||
4. **Edit entries** through the same form, pre-filled with existing data.
|
||||
5. **View your journey** on a D3-powered world map where visited countries are highlighted and animated flight paths connect entries in chronological order.
|
||||
6. **Browse a timeline** sorted by date, country, or recency.
|
||||
7. **Share** a generated summary card to show off your stats.
|
||||
|
||||
- It brings its own routing solution which might not be preferable for some users.
|
||||
- It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app.
|
||||
---
|
||||
|
||||
This template contains as little as possible to get started with Vite + Svelte, while taking into account the developer experience with regards to HMR and intellisense. It demonstrates capabilities on par with the other `create-vite` templates and is a good starting point for beginners dipping their toes into a Vite + Svelte project.
|
||||
## Code Organization
|
||||
|
||||
Should you later need the extended capabilities and extensibility provided by SvelteKit, the template has been structured similarly to SvelteKit so that it is easy to migrate.
|
||||
|
||||
**Why include `.vscode/extensions.json`?**
|
||||
|
||||
Other templates indirectly recommend extensions via the README, but this file allows VS Code to prompt the user to install the recommended extension upon opening the project.
|
||||
|
||||
**Why enable `checkJs` in the JS template?**
|
||||
|
||||
It is likely that most cases of changing variable types in runtime are likely to be accidental, rather than deliberate. This provides advanced typechecking out of the box. Should you like to take advantage of the dynamically-typed nature of JavaScript, it is trivial to change the configuration.
|
||||
|
||||
**Why is HMR not preserving my local component state?**
|
||||
|
||||
HMR state preservation comes with a number of gotchas! It has been disabled by default in both `svelte-hmr` and `@sveltejs/vite-plugin-svelte` due to its often surprising behavior. You can read the details [here](https://github.com/sveltejs/svelte-hmr/tree/master/packages/svelte-hmr#preservation-of-local-state).
|
||||
|
||||
If you have state that's important to retain within a component, consider creating an external store which would not be replaced by HMR.
|
||||
|
||||
```js
|
||||
// store.js
|
||||
// An extremely simple external store
|
||||
import { writable } from 'svelte/store'
|
||||
export default writable(0)
|
||||
```
|
||||
src/
|
||||
├── App.svelte Root component — mode switching & replay button
|
||||
├── main.js Vite entry point
|
||||
├── app.css Global CSS variables and resets
|
||||
├── assets/ 14 static images (transport icons, profile, defaults)
|
||||
│
|
||||
└── lib/
|
||||
├── firebase.js Firebase init (auth, Firestore, Storage)
|
||||
│
|
||||
├── auth/
|
||||
│ ├── LoginOverlay.svelte Google sign-in dialog
|
||||
│ ├── CountryPicker.svelte Home-country selection step
|
||||
│ └── userStore.svelte.js Auth state & user profile store
|
||||
│
|
||||
├── layout/
|
||||
│ ├── Layout.svelte App shell (auth guard + sidebar)
|
||||
│ ├── TopBar.svelte Segmented nav (Map / Journal)
|
||||
│ └── selection.svelte.js Reactive set of visited countries
|
||||
│
|
||||
├── stores/
|
||||
│ └── entriesStore.svelte.js Firestore CRUD & reactive list
|
||||
│
|
||||
├── shared/
|
||||
│ ├── cities.js Country→cities map
|
||||
│ ├── countries.js Country names, IDs, flag emoji helpers
|
||||
│ ├── SearchInput.svelte Autocomplete text input
|
||||
│ └── types.js JSDoc type definitions
|
||||
│
|
||||
├── world-map/
|
||||
│ ├── WorldMap.svelte D3 globe — visited countries, home marker, tooltips
|
||||
│ ├── JourneyView.svelte Animated flight-path overlay + stats
|
||||
│ ├── StatsPanel.svelte Trip statistics panel
|
||||
│ └── continents.js Continent classification data
|
||||
│
|
||||
└── timeline/
|
||||
├── detail/
|
||||
│ ├── NewEntryForm.svelte Multi-step entry creation (3 steps)
|
||||
│ ├── EditForm.svelte Multi-step entry editing (3 steps)
|
||||
│ ├── StepNavbar.svelte Shared step-navigation top bar
|
||||
│ ├── TripBasicInfo.svelte Step 1 form (country, cities, dates, transport)
|
||||
│ ├── PhotoEditor.svelte Step 2 — upload & manage photos
|
||||
│ ├── JournalDetail.svelte Full entry view with lightbox
|
||||
│ └── DeleteConfirm.svelte Delete confirmation dialog
|
||||
└── view/
|
||||
├── TimelineView.svelte Sorted entry list with year groups
|
||||
├── TimelineCard.svelte Entry card thumbnail
|
||||
├── ShareCard.svelte Generated share image
|
||||
└── SharePreview.svelte Share card preview modal
|
||||
```
|
||||
|
||||
### Architecture
|
||||
|
||||
**Component tree** (simplified):
|
||||
|
||||
```
|
||||
App.svelte
|
||||
└── Layout.svelte
|
||||
├── LoginOverlay.svelte
|
||||
├── TopBar.svelte
|
||||
├── CountryPicker.svelte
|
||||
├── WorldMap.svelte
|
||||
│ └── JourneyView.svelte
|
||||
│ └── StatsPanel.svelte
|
||||
└── TimelineView.svelte
|
||||
├── TimelineCard.svelte
|
||||
├── JournalDetail.svelte
|
||||
│ ├── DeleteConfirm.svelte
|
||||
│ └── EditForm.svelte
|
||||
│ ├── StepNavbar.svelte
|
||||
│ ├── TripBasicInfo.svelte
|
||||
│ └── PhotoEditor.svelte
|
||||
├── NewEntryForm.svelte
|
||||
│ ├── StepNavbar.svelte
|
||||
│ ├── PhotoEditor.svelte
|
||||
│ └── ...
|
||||
├── ShareCard.svelte
|
||||
└── SharePreview.svelte
|
||||
```
|
||||
|
||||
### Data Flow
|
||||
|
||||
```
|
||||
Firebase Auth ──→ userStore.svelte.js ──→ Layout (auth guard)
|
||||
Firebase Firestore ──→ entriesStore.svelte.js ──→ Timeline, Map (via $state/$derived)
|
||||
Firebase Storage ──→ PhotoEditor.svelte (upload)
|
||||
selection.svelte.js ──→ visited set (derived from entries + home country)
|
||||
```
|
||||
|
||||
### Key Patterns
|
||||
|
||||
- **Svelte 5 runes** — `$state`, `$derived`, `$effect`, `$bindable`, `$props` replace the old Svelte store/reactivity model.
|
||||
- **$bindable props** — `TripBasicInfo` uses `$bindable()` for two-way binding with its parent form, keeping form state in the parent while delegating UI rendering.
|
||||
- **Firebase listeners** — `entriesStore` uses `onSnapshot` for real-time Firestore sync; `userStore` uses `onAuthStateChanged`.
|
||||
- **D3.js** — `WorldMap` renders a GeoJSON world map with centered zoom via `d3-geo`; `JourneyView` animates SVG flight paths.
|
||||
- **No framework router** — the app uses a simple `mode` state variable (`'map' | 'journal'`) in `App.svelte` to switch between views.
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
| Feature | Details |
|
||||
|---------|---------|
|
||||
| Google sign-in | Firebase Auth with `GoogleAuthProvider` |
|
||||
| Interactive world map | D3‑projected map with country highlighting, zoom, and pan |
|
||||
| Animated journeys | Flight‑path arcs between entries, played sequentially |
|
||||
| Multi‑step forms | 3‑step wizard for both new and edit modes |
|
||||
| Photo upload | Firebase Storage with CORS support, error display |
|
||||
| Random trip questions | 10 curated prompts, 3 randomly chosen per entry |
|
||||
| Share card | Auto‑generated trip summary image via `html-to-image` |
|
||||
| Home country marker | 16×16 icon placed at country centroid on map |
|
||||
| Tooltips | Country name shown on hover, offset 22px from cursor |
|
||||
|
||||
---
|
||||
|
||||
## Known Bugs & Limitations
|
||||
|
||||
- **Photo Editor** — The `.add-btn` CSS class is unused (replaced by `.add-cell`); leftover from refactoring.
|
||||
- **ShareCard** — Several CSS classes (`.stat-grid`, `.stat-box`, `.cont-section`, etc.) are defined but unused in the template; they were intended for a statistics section that was not implemented.
|
||||
- **Photo upload error** — If Firebase Storage upload fails, the error is displayed but the photo grid does not automatically roll back the failed entry.
|
||||
- **State_referenced_locally warnings** — `EditForm.svelte` initializes `$state` variables from `$props()` at declaration; this is intentional (one‑time init on edit mode) but Svelte 5's analyzer emits warnings.
|
||||
- **A11y warnings** — Some form labels lack `for`/`id` associations (transport pills, trip‑type toggles); these are visual‑only controls where the label wraps the input, which is functional but not strictly valid per WAI‑ARIA.
|
||||
|
||||
---
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Package | Purpose |
|
||||
|---------|---------|
|
||||
| `svelte` ^5.55 | UI framework (runes, snippets, `$props`) |
|
||||
| `firebase` ^12 | Auth, Firestore, Storage |
|
||||
| `d3` ^7 | World map projection and SVG rendering |
|
||||
| `topojson-client` | Convert TopoJSON → GeoJSON for map data |
|
||||
| `world-atlas` | Country boundary data |
|
||||
| `html-to-image` | Generate share card PNG |
|
||||
|
||||
---
|
||||
|
||||
## Setup & Run
|
||||
|
||||
```bash
|
||||
# Install
|
||||
npm install
|
||||
|
||||
# Environment — create .env with your Firebase config:
|
||||
# VITE_FIREBASE_API_KEY=...
|
||||
# VITE_FIREBASE_AUTH_DOMAIN=...
|
||||
# VITE_FIREBASE_PROJECT_ID=...
|
||||
# VITE_FIREBASE_STORAGE_BUCKET=...
|
||||
# VITE_FIREBASE_MESSAGING_SENDER_ID=...
|
||||
# VITE_FIREBASE_APP_ID=...
|
||||
|
||||
# Dev server
|
||||
npm run dev
|
||||
|
||||
# Production build
|
||||
npm run build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
- **D3.js** — [Mike Bostock](https://d3js.org/) for the visualization library.
|
||||
- **world-atlas** — [Topojson world data](https://github.com/topojson/world-atlas) by Mike Bostock.
|
||||
- **Firebase** — Google for the backend suite (Auth, Firestore, Storage).
|
||||
- **Svelte** — [Svelte team](https://svelte.dev/) for the frontend framework.
|
||||
- **html-to-image** — [tsayen](https://github.com/bubkoo/html-to-image) for DOM-to-image capture.
|
||||
- **Flag emoji** — Country-to-flag mapping based on regional indicator symbols.
|
||||
- **Cursor icon** — Derived from the SVG airplane asset used in the app.
|
||||
|
||||
---
|
||||
|
||||
_This project was developed as part of a software prototyping course._
|
||||
|
||||
Reference in New Issue
Block a user