Compare commits

..

5 Commits
main ... josh

Author SHA1 Message Date
Josh-Dev-Quest
b4fae21038
Basic project structure and some drafts 2026-02-26 12:11:59 +01:00
Josh-Dev-Quest
f98c74d515
feat: add journey map marker creation and editing 2026-02-23 06:34:32 +01:00
Josh-Dev-Quest
b55e4bba31
feat: add responsive map page with sidebar 2026-02-23 06:11:44 +01:00
Josh-Dev-Quest
32fa54196a
Add folder structure 2026-02-10 17:51:44 +01:00
Josh-Dev-Quest
0380e35a58
Draft README.md 2026-02-10 17:32:40 +01:00
11 changed files with 1178 additions and 1 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
Lession_material
*.DS_Store
.aider*

View File

@ -1 +1,24 @@
Our cool project
# Travel Journal (Draft README)
## Projectdescriptio
On this website you can document your travelstories.
Where you where, what you did and what videos and pictures you took.
Keep your journal and share it with friends or just log it for your memory.
## Features
- Blog entry
- Log places
- Add pictures to specific places
## Installation
TBD
## Tech-Stack
- HTML
- CSS
- JavaScript
- WebGL
## Members
- Flepp Stiafen
- Kohler Joshua
- Rüegger André

0
blog-posts.html Normal file
View File

528
css/map.css Normal file
View File

@ -0,0 +1,528 @@
/* Map Page Specific Styles */
/* App Layout */
.app-container {
display: flex;
height: 100vh;
overflow: hidden;
font-family: 'Poppins', sans-serif;
}
/* Sidebar Styles */
.sidebar {
width: 350px;
background-color: #2c3e50;
color: #ecf0f1;
display: flex;
flex-direction: column;
box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease;
z-index: 10;
}
.sidebar-header {
padding: 20px;
border-bottom: 1px solid #34495e;
}
.sidebar-header h1 {
margin: 0;
font-size: 1.5rem;
display: flex;
align-items: center;
gap: 10px;
}
.tagline {
margin: 5px 0 0;
font-size: 0.85rem;
color: #bdc3c7;
font-family: 'Roboto', sans-serif;
}
/* Mode Selector */
.mode-selector {
display: flex;
padding: 15px;
gap: 10px;
border-bottom: 1px solid #34495e;
}
.mode-btn {
flex: 1;
padding: 10px;
background-color: #34495e;
border: none;
color: #ecf0f1;
border-radius: 5px;
cursor: pointer;
font-family: 'Poppins', sans-serif;
font-weight: 500;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
transition: all 0.2s ease;
}
.mode-btn:hover {
background-color: #3d566e;
}
.mode-btn.active {
background-color: #3498db;
box-shadow: 0 2px 5px rgba(52, 152, 219, 0.3);
}
/* Panels */
.panel {
padding: 20px;
border-bottom: 1px solid #34495e;
display: none;
}
.panel.active-panel {
display: block;
}
.panel h3 {
margin-top: 0;
display: flex;
align-items: center;
gap: 10px;
font-size: 1.2rem;
}
/* Form Styles */
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: 500;
display: flex;
align-items: center;
gap: 5px;
}
.form-group input,
.form-group textarea,
.form-group select {
width: 100%;
padding: 10px;
border-radius: 5px;
border: 1px solid #34495e;
background-color: #34495e;
color: #ecf0f1;
font-family: 'Roboto', sans-serif;
}
.form-group textarea {
min-height: 80px;
resize: vertical;
}
/* Instructions */
.instructions {
background-color: rgba(52, 73, 94, 0.5);
border-radius: 5px;
padding: 15px;
margin: 15px 0;
}
.instructions h4 {
margin-top: 0;
display: flex;
align-items: center;
gap: 8px;
}
.instructions ol {
margin: 10px 0 0;
padding-left: 20px;
}
.instructions li {
margin-bottom: 5px;
font-size: 0.9rem;
}
/* Buttons */
.button-group {
display: flex;
gap: 10px;
margin-top: 15px;
}
.btn {
padding: 10px 15px;
border: none;
border-radius: 5px;
cursor: pointer;
font-family: 'Poppins', sans-serif;
font-weight: 500;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
transition: all 0.2s ease;
}
.btn-primary {
background-color: #3498db;
color: white;
}
.btn-primary:hover {
background-color: #2980b9;
}
.btn-secondary {
background-color: #7f8c8d;
color: white;
}
.btn-secondary:hover {
background-color: #6c7b7d;
}
.btn-danger {
background-color: #e74c3c;
color: white;
}
.btn-danger:hover {
background-color: #c0392b;
}
.btn-small {
padding: 5px 10px;
font-size: 0.85rem;
}
/* Filter Options */
.filter-options {
margin: 15px 0;
}
.checkbox-group {
display: flex;
flex-direction: column;
gap: 8px;
}
.checkbox-group label {
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
}
/* Journey Info */
.journey-info {
background-color: rgba(52, 73, 94, 0.5);
border-radius: 5px;
padding: 15px;
margin-top: 15px;
}
.info-content p {
margin: 8px 0;
}
/* Markers List */
.markers-list {
flex: 1;
padding: 20px;
overflow-y: auto;
}
.markers-list h3 {
display: flex;
align-items: center;
gap: 10px;
margin-top: 0;
}
#markers-container {
margin-top: 15px;
}
.empty-message {
text-align: center;
color: #7f8c8d;
font-style: italic;
padding: 20px;
}
/* Footer */
.sidebar-footer {
padding: 15px 20px;
border-top: 1px solid #34495e;
background-color: #253342;
}
.navigation {
display: flex;
justify-content: space-around;
margin-bottom: 10px;
}
.nav-link {
color: #3498db;
text-decoration: none;
display: flex;
align-items: center;
gap: 5px;
font-size: 0.9rem;
}
.nav-link:hover {
text-decoration: underline;
}
.footer-text {
text-align: center;
font-size: 0.8rem;
color: #7f8c8d;
margin: 0;
}
/* Map Area */
.map-area {
flex: 1;
position: relative;
}
#map {
width: 100%;
height: 100%;
}
/* Map Controls */
.map-controls {
position: absolute;
top: 20px;
right: 20px;
display: flex;
flex-direction: column;
gap: 10px;
z-index: 1;
}
.control-btn {
width: 40px;
height: 40px;
border-radius: 5px;
background-color: white;
border: none;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 1rem;
color: #2c3e50;
transition: all 0.2s ease;
}
.control-btn:hover {
background-color: #f8f9fa;
transform: translateY(-2px);
}
/* Mode Indicator */
.mode-indicator {
position: absolute;
top: 20px;
left: 20px;
background-color: rgba(255, 255, 255, 0.9);
padding: 10px 15px;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
gap: 10px;
z-index: 1;
}
.indicator-text {
font-weight: 500;
color: #2c3e50;
}
.indicator-dot {
width: 10px;
height: 10px;
border-radius: 50%;
}
.indicator-dot.creating {
background-color: #3498db;
}
.indicator-dot.viewing {
background-color: #2ecc71;
}
/* Modal */
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 100;
align-items: center;
justify-content: center;
}
.modal.active {
display: flex;
}
.modal-content {
background-color: white;
border-radius: 10px;
width: 90%;
max-width: 500px;
max-height: 90vh;
overflow-y: auto;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.2);
}
.modal-header {
padding: 20px;
border-bottom: 1px solid #eee;
display: flex;
justify-content: space-between;
align-items: center;
}
.modal-header h3 {
margin: 0;
display: flex;
align-items: center;
gap: 10px;
}
.close-btn {
background: none;
border: none;
font-size: 1.5rem;
cursor: pointer;
color: #7f8c8d;
}
.close-btn:hover {
color: #2c3e50;
}
.modal-body {
padding: 20px;
}
/* Image Upload */
.image-upload-area {
border: 2px dashed #ddd;
border-radius: 5px;
padding: 15px;
margin-top: 5px;
}
.image-preview {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 15px;
min-height: 60px;
}
.upload-actions {
display: flex;
gap: 10px;
}
.help-text {
display: block;
margin-top: 5px;
color: #7f8c8d;
font-size: 0.85rem;
}
.coordinates {
padding: 10px;
background-color: #f8f9fa;
border-radius: 5px;
margin-top: 15px;
}
.modal-footer {
padding: 15px 20px;
border-top: 1px solid #eee;
display: flex;
gap: 10px;
justify-content: flex-end;
}
/* Toast */
.toast {
position: fixed;
bottom: 20px;
right: 20px;
background-color: #2ecc71;
color: white;
padding: 15px 20px;
border-radius: 5px;
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.2);
display: none;
z-index: 100;
animation: slideIn 0.3s ease;
}
@keyframes slideIn {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
/* Responsive */
@media (max-width: 768px) {
.sidebar {
position: fixed;
top: 0;
left: 0;
height: 100%;
transform: translateX(-100%);
}
.sidebar.active {
transform: translateX(0);
}
.app-container {
flex-direction: column;
}
.map-controls {
top: auto;
bottom: 20px;
right: 20px;
flex-direction: row;
}
.mode-indicator {
top: 10px;
left: 10px;
font-size: 0.9rem;
}
}

47
css/style.css Normal file
View File

@ -0,0 +1,47 @@
/* Mobile-first approach */
.map-container {
height: 100vh;
width: 100%;
}
/* Tablet and larger */
@media (min-width: 768px) {
.sidebar {
width: 350px;
}
}
/* Journey timeline styles */
.journey-timeline {
padding: 20px;
max-width: 800px;
margin: 0 auto;
}
.timeline-event {
border-left: 3px solid #3498db;
padding: 15px 20px;
margin: 20px 0;
background-color: #f9f9f9;
}
.timeline-event .date {
color: #7f8c8d;
font-style: italic;
}
.timeline-event .location {
font-size: 0.9em;
color: #2c3e50;
}
.images-container {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.images-container img {
max-width: 100px;
height: auto;
}

17
journey.html Normal file
View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Journey Timeline</title>
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
</head>
<body>
<div class="journey-timeline">
<h1 id="journey-title"></h1>
<div id="timeline-container"></div>
</div>
<script src="js/journey-post.js"></script>
</body>
</html>

0
js/blog-posts.js Normal file
View File

37
js/journey-post.js Normal file
View File

@ -0,0 +1,37 @@
function displayJourney(journey) {
document.getElementById('journey-title').textContent = journey.name;
const container = document.getElementById('timeline-container');
container.innerHTML = '';
journey.markers.forEach(marker => {
const markerEl = document.createElement('div');
markerEl.className = 'timeline-event';
markerEl.innerHTML = `
<h3>${marker.content.title || 'Untitled Event'}</h3>
<p class="date">${marker.content.date}</p>
<p class="location">${marker.lngLat.lng.toFixed(4)}, ${marker.lngLat.lat.toFixed(4)}</p>
<p>${marker.content.text}</p>
${marker.content.videoUrl ? `<iframe src="${marker.content.videoUrl}" frameborder="0"></iframe>` : ''}
<div class="images-container">
${marker.content.images.map(img => `<img src="${img}" alt="Event image">`).join('')}
</div>
`;
container.appendChild(markerEl);
});
}
// Get journey ID from URL
const urlParams = new URLSearchParams(window.location.search);
const journeyId = urlParams.get('id');
// Load journey data from localStorage
if (journeyId) {
loadJourneysFromLocalStorage();
const journey = journeys.find(j => j.id === parseInt(journeyId));
if (journey) {
displayJourney(journey);
} else {
document.getElementById('journey-title').textContent = 'Journey not found';
}
}

71
js/main.js Normal file
View File

@ -0,0 +1,71 @@
document.addEventListener('DOMContentLoaded', function() {
// Mode switching
const modeCreateBtn = document.getElementById('mode-create');
const modeViewBtn = document.getElementById('mode-view');
const createPanel = document.getElementById('create-panel');
const viewPanel = document.getElementById('view-panel');
const markersContainer = document.getElementById('markers-container');
const emptyMarkers = document.getElementById('empty-markers');
function switchMode(mode) {
if (mode === 'create') {
-> modeCreateBtn.classList.add('active');
modeViewBtn.classList.remove('active');
createPanel.classList.add('active-panel');
viewPanel.classList.remove('active-panel');
//ҧ Enable marker adding
window.isCreatingJourney = true;
} else { // view mode
modeCreateBtn.classList.remove('active');
modeViewBtn.classList.add('active');
createPanel.classList.remove('active-panel');
viewPanel.classList.add('active-panel');
// Disable marker adding
window.isCreatingJourney = false;
}
}
modeCreateBtn.addEventListener('click', () => switchMode('create'));
modeViewBtn.addEventListener('click', () => switchMode('view'));
// Journey save handler
document.getElementById('save-journey').addEventListener('click', function() {
const title = document.getElementById('journey-title').value;
const description = document.getElementById('journey-description').value;
if (!title.trim()) {
alert('Journey title cannot be empty');
return;
}
window.currentJourney.name = title;
window.currentJourney.description = description;
window.saveJourneyToLocalStorage();
// Show notification
document.getElementById('toast-message').textContent = 'Journey saved successfully!';
document.getElementById('toast').classList.add('show');
setTimeout(() => {
document.getElementById('toast').classList.remove('show');
}, 3000);
});
// Clear markers
document.getElementById('clear-markers').addEventListener('click', function() {
if (window.currentJourney.markers.length > 0 && confirm('Are you sure you want to clear all markers?')) {
window.currentJourney.markers.forEach(marker => marker.remove());
window.currentJourney.markers = [];
markersContainer.innerHTML = '';
emptyMarkers.style.display = 'block';
window.updateJourneyPath();
}
});
// Toggle sidebar
document.getElementById('toggle-sidebar').addEventListener('click', function() {
document.querySelector('.sidebar').classList.toggle('collapsed');
});
// Initialize in create mode
switchMode('create');
});

188
js/map.js Normal file
View File

@ -0,0 +1,188 @@
let map;
let journeys = [];
let currentJourney = {
id: Date.now(),
name: "Untitled Journey",
description: "",
markers: [],
path: null
};
let currentMarkerBeingEdited = null;
let isCreatingJourney = true;
function saveJourneyToLocalStorage() {
journeys.push({
id: currentJourney.id,
name: currentJourney.name,
description: currentJourney.description,
markers: currentJourney.markers.map(marker => ({
id: marker.id,
lngLat: marker.getLngLat(),
content: marker.content
}))
});
localStorage.setItem('journeys', JSON.stringify(journeys));
}
function loadJourneysFromLocalStorage() {
const stored = localStorage.getItem('journeyMapper_journeys');
if (stored) {
journeys = JSON.parse(stored);
}
}
// Function to create a marker at a lngLat and add to the map
function createMarker(lngLat) {
const markerElement = document.createElement('div');
markerElement.className = 'marker';
markerElement.innerHTML = '<i class="fas fa-map-marker"></i>';
const marker = new maplibregl.Marker(markerElement)
.setLngLat(lngLat)
.addTo(map);
marker.id = Date.now();
marker.content = {
title: '',
date: '',
text: '',
images: [],
videoUrl: ''
};
// Add a popup
const popup = new maplibregl.Popup({ offset: 25 })
.setHTML('<strong>New Marker</strong>');
marker.setPopup(popup);
// When the marker is clicked, open the editor
markerElement.addEventListener('click', () => {
openMarkerEditor(marker);
});
return marker;
}
function openMarkerEditor(marker) {
currentMarkerBeingEdited = marker;
document.getElementById('marker-title').value = marker.content.title || '';
document.getElementById('marker-date').value = marker.content.date || '';
document.getElementById('marker-text').value = marker.content.text || '';
document.getElementById('video-url').value = marker.content.videoUrl || '';
document.getElementById('marker-coords').textContent =
`${marker.getLngLat().lng.toFixed(4)}, ${marker.getLngLat().lat.toFixed(4)}`;
// Update imagine review
const imagePreview = document.getElementById('image-preview');
imagePreview.innerHTML = '';
学生学习 if (marker.content.images && marker.content.images.length > 0) {
marker.content.images.forEach(img => {
const imgEl = document.createElement('img');
imgEl.src = img;
imagePreview.appendChild(imgEl);
});
}
document.getElementById('marker-modal').style.display = 'block';
}
function closeMarkerEditor() {
document.getElementById('marker-modal').style.display = 'none';
currentMarkerBeingEdited = null;
}
document.addEventListener('DOMContentLoaded', function() {
map = new maplibregl.Map({
container: 'map',
style: 'https://demotiles.maplibre.org/style.json',
center: [0, 20],
zoom: 2
});
// Add journey path layer
map.on('load', function() {
map.addSource('journey-path', {
type: 'geojson',
data: {
type: 'Feature',
properties: {},
geometry: {
type: 'LineString',
coordinates: []
}
}
});
map.addLayer({
id: 'journey-path',
type: 'line',
source: 'journey-path',
layout: {
'line-join': 'round',
'line-cap': 'round'
},
paint: {
'line-color': '#3887be',
'line-width': 5
}
});
});
// Close editor events
document.getElementById('close-modal').addEventListener('click', closeMarkerEditor);
document.getElementById('cancel-marker').addEventListener('click', closeMarkerEditor);
// Save marker event
document.getElementById('save-marker').addEventListener('click', function() {
if (!currentMarkerBeingEdited) return;
// Update marker content
currentMarkerBeingEdited.content.title = document.getElementById('marker-title').value;
currentMarkerBeingEdited.content.date = document.getElementById('marker-date').value;
currentMarkerBeingEdited.content.text = document.getElementById('marker-text').value;
currentMarkerBeingEdited.content.videoUrl = document.getElementById('video-url').value;
// Update the popup
currentMarkerBeingEdited.getPopup().setHTML(
`<strong>${currentMarkerBeingEdited.content.title || 'Untitled'}</strong>`
);
closeMarkerEditor();
});
// Delete marker event
document.getElementById('delete-marker').addEventListener('click', function() {
if (!currentMarkerBeingEdited) return;
// Remove from map
currentMarkerBeingEdited.remove();
// Remove from currentJourney.markers
const index = currentJourney.markers.findIndex(m => m.id === currentMarkerBeingEdited.id);
if (index !== -1) {
currentJourney.markers.splice(index, 1);
}
closeMarkerEditor();
});
// Add marker on map click
map.on('click', (e) => {
if (isCreatingJourney) {
const marker = createMarker(e.lngLat);
currentJourney.markers.push(marker);
updateJourneyPath();
}
});
// Save journey button
document.getElementById('save-journey-btn').addEventListener('click', function() {
currentJourney.name = document.getElementById('journey-name').value;
currentJourney.description = document.getElementById('journey-description').value;
saveJourneyToLocalStorage();
alert('Journey saved!');
});
// Load journeys on start
loadJourneysFromLocalStorage();
});

263
map-page.html Normal file
View File

@ -0,0 +1,263 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Journey Mapper - Interactive Map</title>
<script src='https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.js'></script>
<link href='https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.css' rel='stylesheet' />
<!-- Font Awesome Icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="css/map.css">
<!-- Favicon -->
<link rel="icon" type="image/x-icon" href="assets/icons/favicon.ico">
</head>
<body>
<!-- Main Container -->
<div class="app-container">
<!-- Sidebar -->
<aside class="sidebar">
<!-- Header Section -->
<div class="sidebar-header">
<h1><i class="fas fa-map-marked-alt"></i> Journey Mapper</h1>
<p class="tagline">Create and explore interactive journey maps</p>
</div>
<!-- Mode Selector -->
<div class="mode-selector">
<button id="mode-create" class="mode-btn active">
<i class="fas fa-plus-circle"></i> Create Journey
</button>
<button id="mode-view" class="mode-btn">
<i class="fas fa-eye"></i> View Journeys
</button>
</div>
<!-- Create Journey Panel (Visible in create mode) -->
<div id="create-panel" class="panel active-panel">
<h3><i class="fas fa-route"></i> Create New Journey</h3>
<div class="form-group">
<label for="journey-title"><i class="fas fa-heading"></i> Journey Title</label>
<input type="text" id="journey-title" placeholder="My European Adventure">
</div>
<div class="form-group">
<label for="journey-description"><i class="fas fa-align-left"></i> Description</label>
<textarea id="journey-description" placeholder="Describe your journey..."></textarea>
</div>
<div class="instructions">
<h4><i class="fas fa-info-circle"></i> How to create:</h4>
<ol>
<li>Click on the map to place markers</li>
<li>Click on a marker to add content</li>
<li>Markers will be automatically connected</li>
<li>Click "Save Journey" when done</li>
</ol>
</div>
<div class="button-group">
<button id="save-journey" class="btn btn-primary">
<i class="fas fa-save"></i> Save Journey
</button>
<button id="clear-markers" class="btn btn-secondary">
<i class="fas fa-trash-alt"></i> Clear Markers
</button>
</div>
</div>
<!-- View Journey Panel (Visible in view mode) -->
<div id="view-panel" class="panel">
<h3><i class="fas fa-map"></i> Explore Journeys</h3>
<!-- Journey Selection -->
<div class="form-group">
<label for="journey-select"><i class="fas fa-list"></i> Select Journey</label>
<select id="journey-select">
<option value="">-- Choose a journey --</option>
<option value="all">Show All Journeys</option>
<!-- Journeys will be populated by JavaScript -->
</select>
</div>
<!-- Filter Options -->
<div class="filter-options">
<h4><i class="fas fa-filter"></i> Filter Options</h4>
<div class="checkbox-group">
<label>
<input type="checkbox" id="filter-markers" checked>
Show Markers
</label>
<label>
<input type="checkbox" id="filter-paths" checked>
Show Paths
</label>
</div>
</div>
<!-- Selected Journey Info -->
<div id="journey-info" class="journey-info">
<h4><i class="fas fa-info-circle"></i> Journey Details</h4>
<div class="info-content">
<p><strong>Title:</strong> <span id="info-title">-</span></p>
<p><strong>Description:</strong> <span id="info-description">-</span></p>
<p><strong>Markers:</strong> <span id="info-marker-count">0</span></p>
<p><strong>Created:</strong> <span id="info-date">-</span></p>
</div>
<div class="button-group">
<button id="view-blog" class="btn btn-primary">
<i class="fas fa-book-open"></i> View Blog Post
</button>
<button id="edit-journey" class="btn btn-secondary">
<i class="fas fa-edit"></i> Edit Journey
</button>
<button id="delete-journey" class="btn btn-danger">
<i class="fas fa-trash"></i> Delete
</button>
</div>
</div>
</div>
<!-- Current Markers List -->
<div class="markers-list">
<h3><i class="fas fa-map-marker-alt"></i> Current Markers</h3>
<div id="markers-container">
<!-- Markers will be added here by JavaScript -->
<p class="empty-message" id="empty-markers">No markers yet. Click on the map to add markers.</p>
</div>
</div>
<!-- Footer -->
<div class="sidebar-footer">
<div class="navigation">
<a href="journeys.html" class="nav-link">
<i class="fas fa-list"></i> All Journeys
</a>
<a href="about.html" class="nav-link">
<i class="fas fa-question-circle"></i> Help
</a>
</div>
<p class="footer-text">Journey Mapper v1.0</p>
</div>
</aside>
<!-- Main Map Area -->
<main class="map-area">
<!-- Map Container -->
<div id="map"></div>
<!-- Map Controls -->
<div class="map-controls">
<button id="toggle-sidebar" class="control-btn" title="Toggle Sidebar">
<i class="fas fa-bars"></i>
</button>
<button id="zoom-in" class="control-btn" title="Zoom In">
<i class="fas fa-plus"></i>
</button>
<button id="zoom-out" class="control-btn" title="Zoom Out">
<i class="fas fa-minus"></i>
</button>
<button id="locate-me" class="control-btn" title="My Location">
<i class="fas fa-location-arrow"></i>
</button>
<button id="fit-all" class="control-btn" title="Fit All Markers">
<i class="fas fa-expand-alt"></i>
</button>
</div>
<!-- Current Mode Indicator -->
<div id="mode-indicator" class="mode-indicator">
<span class="indicator-text">Creating: New Journey</span>
<div class="indicator-dot creating"></div>
</div>
<!-- Marker Content Modal (Hidden by default) -->
<div id="marker-modal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3><i class="fas fa-map-marker-alt"></i> Edit Marker Content</h3>
<button id="close-modal" class="close-btn">&times;</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="marker-title">Title</label>
<input type="text" id="marker-title" placeholder="Location name">
</div>
<div class="form-group">
<label for="marker-date">Date</label>
<input type="date" id="marker-date">
</div>
<div class="form-group">
<label for="marker-text">Description</label>
<textarea id="marker-text" placeholder="Share your experience at this location..."></textarea>
</div>
<div class="form-group">
<label><i class="fas fa-images"></i> Images</label>
<div class="image-upload-area">
<div id="image-preview" class="image-preview">
<!-- Images will appear here -->
</div>
<div class="upload-actions">
<input type="file" id="image-upload" accept="image/*" multiple style="display: none;">
<button id="add-image" class="btn btn-small">
<i class="fas fa-plus"></i> Add Images
</button>
<button id="remove-images" class="btn btn-small btn-secondary">
<i class="fas fa-trash"></i> Clear
</button>
</div>
</div>
</div>
<div class="form-group">
<label for="video-url"><i class="fas fa-video"></i> Video URL</label>
<input type="url" id="video-url" placeholder="YouTube or Vimeo URL">
<small class="help-text">Paste a YouTube or Vimeo video link</small>
</div>
<div class="coordinates">
<p><strong>Coordinates:</strong> <span id="marker-coords">0, 0</span></p>
</div>
</div>
<div class="modal-footer">
<button id="save-marker" class="btn btn-primary">
<i class="fas fa-save"></i> Save Marker
</button>
<button id="delete-marker" class="btn btn-danger">
<i class="fas fa-trash"></i> Delete Marker
</button>
<button id="cancel-marker" class="btn btn-secondary">
Cancel
</button>
</div>
</div>
</div>
<!-- Notification Toast (Hidden by default) -->
<div id="toast" class="toast">
<div class="toast-content">
<span id="toast-message">Journey saved successfully!</span>
</div>
</div>
</main>
</div>
<!-- JavaScript Files -->
<script src="js/main.js"></script>
<script src="js/map.js"></script>
<script src="js/journey-post.js"></script>