initial version

This commit is contained in:
2023-11-01 20:27:34 +01:00
commit a5f25d1cd7
27 changed files with 7072 additions and 0 deletions

69
pages/about.vue Normal file
View File

@@ -0,0 +1,69 @@
<template>
<div class="about-container">
<h1 class="about-title">Augsburg Mosaic</h1>
<p class="about-description">
Welcome to Augsburg Mosaic, a delightful endeavor crafted by the creative mind <a href="https://wieerwill.de" class="external-link">WieErWill</a>.
This project blossomed from a genuine fondness for the city of Augsburg, aiming to unfold its hidden gems and notable locales to both visitors and residents alike.
</p>
<p class="about-detail">
Augsburg Mosaic serves as a digital guide, offering a curated list of places categorized as Attractions, Food spots, Cultural hubs, Nature retreats, and Others.
Through an interactive map and a user-friendly list, one can explore, filter, and learn more about each location.
Utilizing technologies such as Vue.js, Nuxt.js, Leaflet.js for map rendering, and Pinia for state management, this project embodies a seamless blend of design and functionality,
all while being a purely static site optimized for SEO. This also means, i don't use cookies or any other data, especially not yours in any way.
</p>
<p class="about-note">
This endeavor is purely a hobby, unfunded yet rich in spirit. Feel free to traverse through the mosaic of Augsburg,
all I hope is for it to bring joy and not to cause harm. The icons embellishing this site are courtesy of FontAwesome,
while the images are captured through my lens.
</p>
<a href="/" class="back-link"><strong>Back to Map</strong></a>
</div>
</template>
<style scoped>
.about-container {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
margin: auto;
max-width: 800px;
background-color: #f7f4f4;
border: 1px solid #e0e0e0;
border-radius: 10px;
box-shadow: 0 16px 16px rgba(0, 0, 0, 0.2);
margin-top: 3rem;
}
.about-title {
font-size: 36px;
margin-bottom: 20px;
}
.about-description,
.about-detail,
.about-note {
text-align: left;
margin-bottom: 20px;
line-height: 1.6;
}
.external-link,
.back-link {
color: #3498db;
text-decoration: none;
transition: color 0.3s;
}
.external-link:hover,
.back-link:hover {
color: #2c3e50;
}
.back-link {
margin-top: 20px;
padding: 10px 20px;
border: 1px solid #3498db;
border-radius: 5px;
text-align: center;
}
</style>

160
pages/index.vue Normal file
View File

@@ -0,0 +1,160 @@
<template>
<Header />
<div class="container">
<div class="sidebar" :class="{ 'is-mobile': isMobile }">
<Filter :locations="locations" @update-filter="updateFilteredLocations" />
<div class="location-list-container">
<LocationList :locations="filteredLocations" :selectedLocation="selectedLocation"
@location-click="handleLocationClick" />
</div>
</div>
<div class="map-container" v-if="!isMobile">
<Map :center="mapCenter" :zoom="mapZoom" :maxBounds="maxBounds" :locations="filteredLocations"
@marker-click="handleMarkerClick" :selectedLocation="selectedLocation" ref="map" />
</div>
</div>
<Footer />
</template>
<script>
import locationsData from '~/assets/locations.json';
import Header from '~/components/Header.vue';
import Footer from '~/components/Footer.vue';
import Filter from '~/components/Filter.vue';
import LocationList from '~/components/LocationList.vue';
import Map from '~/components/Map.vue';
export default {
data() {
return {
isMobile: false,
maxBounds: [
[48.2, 10.6], // Southwest coordinates
[48.6, 11.2] // Northeast coordinates
],
mapCenter: [48.3689, 10.8979],
mapZoom: 12,
selectedLocation: null,
filteredLocations: [],
locations: locationsData
}
},
components: {
Header,
Footer,
Filter,
LocationList,
Map
},
created() {
this.filteredLocations = [...this.locations].sort((a, b) => a.title.localeCompare(b.title))
},
mounted() {
this.$nextTick(this.updateHeaderFooterHeight);
window.addEventListener('resize', this.updateHeaderFooterHeight);
this.$nextTick(this.updateLocationListHeight);
window.addEventListener('resize', this.updateLocationListHeight);
this.handleResize();
window.addEventListener('resize', this.handleResize);
},
beforeDestroy() {
window.removeEventListener('resize', this.updateHeaderFooterHeight);
window.removeEventListener('resize', this.updateLocationListHeight);
window.removeEventListener('resize', this.handleResize);
},
methods: {
updateFilteredLocations(filteredLocations) {
this.filteredLocations = filteredLocations;
},
handleLocationClick(location) {
this.selectedLocation = location;
this.mapCenter = location.coordinates;
this.mapZoom = 16;
},
handleMarkerClick(location) {
this.selectedLocation = location;
this.mapCenter = location.coordinates;
},
handleResize() {
this.isMobile = window.innerWidth <= 768;
},
updateHeaderFooterHeight() {
const headerHeight = document.querySelector('header').offsetHeight;
const footerHeight = document.querySelector('footer').offsetHeight;
const totalHeight = headerHeight + footerHeight;
document.documentElement.style.setProperty('--header-footer-height', `${totalHeight}px`);
},
updateLocationListHeight() {
const filterHeight = document.querySelector('.filter-container').offsetHeight;
const containerHeight = document.querySelector('.container').clientHeight;
const newHeight = containerHeight - filterHeight - 45
const locationListElement = document.querySelector('.location-list');
locationListElement.style.height = `${newHeight}px`;
}
}
}
</script>
<style scoped>
.header {
background-color: #e0f7fa;
padding: 20px;
margin: 0;
text-align: center;
}
.container {
display: flex;
flex-direction: row;
height: calc(100vh - var(--header-footer-height));
}
.sidebar {
flex: 1;
background-color: #f9f9f9;
display: flex;
flex-direction: column;
border: 1px solid #434343
}
.location-list-container {
overflow-y: auto;
flex-grow: 1;
}
.map-container {
flex: 1;
transition: flex 0.3s;
min-width: 10rem;
min-height: 10rem;
height: 100%;
}
.is-mobile {
flex: 3;
}
.is-mobile .map-container {
display: none;
}
.title {
color: #2c3e50;
}
.description {
color: #2c3e50;
}
/* Mosaic style background for body */
body {
background-color: #ffffff;
background-image:
linear-gradient(45deg, #f06, #f06 25%, transparent 25%, transparent 75%, #f06 75%, #f06),
linear-gradient(45deg, #f06, #f06 25%, transparent 25%, transparent 75%, #f06 75%, #f06);
background-size: 20px 20px;
background-position: 0 0, 10px 10px;
}
</style>