6 Commits

Author SHA1 Message Date
63f7e0cc4c fix:csp issue 2025-10-07 14:41:17 +02:00
a806664ce3 chore:update logboek 2025-10-07 14:33:58 +02:00
8d3922e71c fix:build issues 2025-10-07 14:28:23 +02:00
716c05c256 feat: SEO, PWA, and performance optimizations
- Add sitemap.xml endpoint and update robots.txt for SEO - Improve
manifest.json with richer metadata and categories - Add meta tags for
social sharing and accessibility - Preload critical assets and fonts for
faster loading - Optimize login background image and resource hints -
Enhance service worker for better caching strategies - Add security
headers to server responses - Update Vite config for chunking and
dependency optimization - Add logboek.md for project tracking
2025-10-07 14:26:41 +02:00
5f0cae604d fix:logo padding 2025-10-07 12:44:07 +02:00
fbe0a759b7 fix:typo in redirect uri that broke google oauth 2025-10-03 17:04:31 +02:00
23 changed files with 484 additions and 37 deletions

Binary file not shown.

Binary file not shown.

191
logs/logboek.md Normal file
View File

@@ -0,0 +1,191 @@
# Logboek - Serengo Project
## Oktober 2025
### 7 Oktober 2025 (Maandag) - 4 uren
**Werk uitgevoerd:**
- **Grote SEO, PWA en performance optimalisaties**
- Logo padding gefixed
- Favicon bestanden opgeruimd (verwijderd oude favicon bestanden)
- Manifest.json geoptimaliseerd
- Sitemap.xml automatisch gegenereerd
- Service worker uitgebreid voor caching
- Meta tags en Open Graph voor SEO
- Background afbeelding gecomprimeerd (50% kleiner)
- Performance logs/PDFs opgeslagen voor vergelijking
- Vite config optimalisaties
- Build issues opgelost
**Commits:** 3 commits (8d3922e, 716c05c, 5f0cae6)
**Details:**
- Complete SEO optimalisatie met meta tags
- PWA verbeteringen en caching strategie
- Performance optimalisaties door image compression
- Automatische sitemap generatie
- Service worker caching voor offline functionaliteit
---
### 3 Oktober 2025 (Donderdag) - 8 uren
**Werk uitgevoerd:**
- Google OAuth implementatie toegevoegd
- Database schema uitgebreid voor OAuth
- Login formulier met shadcn/ui componenten
- Background afbeelding toegevoegd voor login pagina
- Location tracking en kaart functionaliteit geïmplementeerd
- Sonner toast notifications voor foutmeldingen
- Skeleton loading states toegevoegd
- MapLibre GL JS maps geïntegreerd
- Diverse styling fixes en verbeteringen
**Commits:** 10 commits (fbe0a75, 0caa5dc, 6fddf42, d8aa99e, 101b6cf, 5cb0b9e, d82f590, 00da815, b82141e, 0abf4f9)
**Details:**
- Complexe OAuth flow met Google
- Geolocation API integratie
- Real-time location watching
- UI component library uitbreiding
- Map integration met zoom functionaliteit
---
### 2 Oktober 2025 (Woensdag) - 5 uren
**Werk uitgevoerd:**
- MapLibre maps feature toegevoegd
- Header component verbeterd
- Basis kaart functionaliteit geïmplementeerd
- Heel wat testen met self-hosted maps adhv OpenMapTiles
**Commits:** 1 commit (b44a69b)
---
### 29 September 2025 (Zondag) - 3 uren
**Werk uitgevoerd:**
- Modal component geïmplementeerd
- Header component toegevoegd aan layout
- Profile panel component ontwikkeld
- UI verbeteringen voor login pagina
- Code cleanup en refactoring
**Commits:** 6 commits (aa8161f, 0b44f10, 13d9303, 204a443, cc24bc0, b6cf77e)
**Details:**
- Grote refactor van UI componenten
- Herbruikbare modal component
- Verbeterde gebruikersinterface
---
### 28 September 2025 (Zaterdag) - 5 uren
**Werk uitgevoerd:**
- Complete UI overhaul van homepage
- Storybook integratie verwijderd
- Custom componenten geïmplementeerd (Button, Input, ErrorMessage, UserInfo)
- ProfileIcon en ProfilePanel componenten
- Login UI drastisch verbeterd met custom styling
- Washington font toegevoegd
- CSS styling uitgebreid
**Commits:** 6 commits (19c1b7b, aa72a3b, 62b2108, 98d745b, bc8a76b, c4deeb8)
**Details:**
- Grote codebase cleanup (1000+ lijnen verwijderd)
- Custom component library opgebouwd
- Professionele login interface
- Typography verbeteringen
---
### 27 September 2025 (Vrijdag) - 6 uren
**Werk uitgevoerd:**
- Vercel deployment configuratie
- Auth systeem naar main applicatie verplaatst
- Docker configuratie fixes
- Container deployment setup
- CSRF auth fixes
- Database migraties
**Commits:** 12 commits (925e716, bb118ca, 806fb92, 79f57c1, d8e2569, dd20a12, 219a78e, 0bcf6c8, 752cb04, 62c7c5e, 1b413e1, 88a7e74, bbe68c6, fc39408)
**Details:**
- Production deployment voorbereiding
- Docker containerization
- Auth system integratie
- Security verbeteringen
---
### 26 September 2025 (Donderdag) - 5 uren
**Werk uitgevoerd:**
- Lucia auth systeem geïmplementeerd
- Database schema voor gebruikers
- Login/logout functionaliteit
- pnpm-lock.yaml cleanup
- AGENTS.md documentatie toegevoegd
- Database setup en migraties
- Logo en PWA manifest
- Chromatic integration
- Code formatting
- Tailwind CSS verwijderd
**Commits:** 10 commits (7e4570c, 3cdb35b, e4fdfc4, f0d30bc, 9b4e956, fe0f939, ad72884, 8745ef1, 9ce6f96, d8f7921, 93eded5, fc5b927, faa2f94)
**Details:**
- Volledige authenticatie systeem
- Database structuur opgezet
- Project configuratie
- PWA functionaliteit
- Initial project setup
---
## Totaal Overzicht
**Totale geschatte uren:** 36 uren
**Werkdagen:** 6 dagen
**Gemiddelde uren per dag:** 6 uur
### Project Milestones:
1. **26 Sept**: Project initialisatie en auth systeem
2. **27 Sept**: Deployment en productie setup
3. **28 Sept**: UI/UX complete overhaul
4. **29 Sept**: Component architectuur verbetering
5. **2-3 Okt**: Maps en location features
6. **7 Okt**: SEO, PWA en performance optimalisaties
### Hoofdfunctionaliteiten geïmplementeerd:
- ✅ Gebruikersauthenticatie (Lucia + Google OAuth)
- ✅ Responsive UI met custom componenten
- ✅ Real-time locatie tracking
- ✅ Interactive maps (MapLibre GL JS)
- ✅ PWA functionaliteit
- ✅ Docker deployment
- ✅ Database (PostgreSQL + Drizzle ORM)
- ✅ Toast notifications
- ✅ Loading states en error handling
- ✅ SEO optimalisatie (meta tags, Open Graph, sitemap)
- ✅ Performance optimalisaties (image compression, caching)

View File

@@ -80,6 +80,7 @@
src: url('/fonts/Washington.ttf') format('truetype');
font-weight: normal;
font-style: normal;
font-display: swap;
}
* {
@@ -131,5 +132,30 @@
a {
color: inherit;
text-decoration: none;
outline: none;
transition: all 0.2s ease;
}
/* Ensure links have visible focus indicators and non-color differentiation */
a:hover {
text-decoration: underline;
}
a:focus {
outline: 2px solid var(--color-ring);
outline-offset: 2px;
text-decoration: underline;
}
/* Special handling for map attribution links */
.maplibregl-ctrl-attrib a {
color: #0078a8 !important;
text-decoration: underline !important;
}
.maplibregl-ctrl-attrib a:hover,
.maplibregl-ctrl-attrib a:focus {
text-decoration: underline !important;
background-color: rgba(0, 120, 168, 0.1) !important;
}
}

View File

@@ -2,8 +2,16 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta name="theme-color" content="#333333" />
<meta name="theme-color" content="#f8f8f8" media="(prefers-color-scheme: light)" />
<meta name="theme-color" content="#333333" media="(prefers-color-scheme: dark)" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
<meta name="apple-mobile-web-app-title" content="Serengo" />
<meta name="mobile-web-app-capable" content="yes" />
<link rel="manifest" href="/manifest.json" />
<link rel="apple-touch-icon" href="/logo.svg" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">

View File

@@ -39,5 +39,32 @@ export const handle: Handle = async ({ event, resolve }) => {
event.locals.user = user;
event.locals.session = session;
return resolve(event);
const response = await resolve(event);
// Add security headers
response.headers.set(
'Content-Security-Policy',
"default-src 'self'; " +
"script-src 'self' 'unsafe-inline' 'unsafe-eval'; " +
"worker-src 'self' blob:; " +
"style-src 'self' 'unsafe-inline' fonts.googleapis.com; " +
"font-src 'self' fonts.gstatic.com; " +
"img-src 'self' data: blob: *.openstreetmap.org *.tile.openstreetmap.org; " +
"connect-src 'self' *.openstreetmap.org; " +
"frame-ancestors 'none'; " +
"base-uri 'self'; " +
"form-action 'self';"
);
response.headers.set('X-Frame-Options', 'DENY');
response.headers.set('X-Content-Type-Options', 'nosniff');
response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
// Add HSTS for HTTPS in production
if (event.url.protocol === 'https:') {
response.headers.set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
}
return response;
};

View File

@@ -1,4 +1,4 @@
<svg width="250" height="250" viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="250" height="250" fill="#D9D9D9"/>
<path d="M122.823 166.616C111.473 166.616 100.892 165.037 91.0785 161.88L89.2865 137.304H90.4385C98.0332 154.712 108.999 163.416 123.335 163.416C129.82 163.416 134.812 162.307 138.311 160.088C141.809 157.784 143.559 154.413 143.559 149.976C143.559 147.672 143.004 145.581 141.895 143.704C140.785 141.741 138.993 139.907 136.519 138.2C134.129 136.408 131.697 134.872 129.223 133.592C126.748 132.312 123.548 130.776 119.623 128.984L115.271 127.064C112.881 126.04 110.791 125.059 108.999 124.12C107.207 123.181 105.201 122.072 102.983 120.792C100.849 119.512 99.0145 118.189 97.4785 116.824C95.9425 115.459 94.4918 114.008 93.1265 112.472C91.7612 110.851 90.7372 109.101 90.0545 107.224C89.3718 105.261 89.0305 103.256 89.0305 101.208C89.0305 95.832 90.7372 91.2667 94.1505 87.512C97.6492 83.7573 102.215 81.0693 107.847 79.448C113.479 77.7413 120.049 76.888 127.559 76.888C136.604 76.888 146.204 78.424 156.359 81.496L158.535 106.2H157.511C153.841 97.8373 149.404 91.3947 144.199 86.872C138.993 82.3493 132.593 80.088 124.999 80.088C119.879 80.088 115.825 81.24 112.839 83.544C109.852 85.7627 108.359 88.7067 108.359 92.376C108.359 94.424 108.785 96.2587 109.639 97.88C110.577 99.5013 112.028 100.995 113.991 102.36C116.039 103.64 118.044 104.749 120.007 105.688C121.969 106.627 124.572 107.736 127.815 109.016L133.191 111.192C137.287 112.813 140.956 114.52 144.199 116.312C147.441 118.019 150.556 120.109 153.543 122.584C156.529 124.973 158.833 127.747 160.455 130.904C162.076 134.061 162.887 137.475 162.887 141.144C162.887 146.861 161.009 151.683 157.255 155.608C153.585 159.533 148.807 162.349 142.919 164.056C137.031 165.763 130.332 166.616 122.823 166.616Z" fill="black"/>
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M759 0H265C118.645 0 0 118.645 0 265V759C0 905.355 118.645 1024 265 1024H759C905.355 1024 1024 905.355 1024 759V265C1024 118.645 905.355 0 759 0Z" fill="#D9D9D9"/>
<path d="M502.383 651.8C466.916 651.8 433.849 646.867 403.183 637L397.583 560.2H401.183C424.916 614.6 459.183 641.8 503.983 641.8C524.249 641.8 539.849 638.333 550.783 631.4C561.716 624.2 567.183 613.667 567.183 599.8C567.183 592.6 565.449 586.067 561.983 580.2C558.516 574.067 552.916 568.333 545.183 563C537.716 557.4 530.116 552.6 522.383 548.6C514.649 544.6 504.649 539.8 492.383 534.2L478.783 528.2C471.316 525 464.783 521.933 459.183 519C453.583 516.067 447.316 512.6 440.383 508.6C433.716 504.6 427.983 500.467 423.183 496.2C418.383 491.933 413.849 487.4 409.583 482.6C405.316 477.533 402.116 472.067 399.983 466.2C397.849 460.067 396.783 453.8 396.783 447.4C396.783 430.6 402.116 416.333 412.783 404.6C423.716 392.867 437.983 384.467 455.583 379.4C473.183 374.067 493.716 371.4 517.183 371.4C545.449 371.4 575.449 376.2 607.183 385.8L613.983 463H610.783C599.316 436.867 585.449 416.733 569.183 402.6C552.916 388.467 532.916 381.4 509.183 381.4C493.183 381.4 480.516 385 471.183 392.2C461.849 399.133 457.183 408.333 457.183 419.8C457.183 426.2 458.516 431.933 461.183 437C464.116 442.067 468.649 446.733 474.783 451C481.183 455 487.449 458.467 493.583 461.4C499.716 464.333 507.849 467.8 517.983 471.8L534.783 478.6C547.583 483.667 559.049 489 569.183 494.6C579.316 499.933 589.049 506.467 598.383 514.2C607.716 521.667 614.916 530.333 619.983 540.2C625.049 550.067 627.583 560.733 627.583 572.2C627.583 590.067 621.716 605.133 609.983 617.4C598.516 629.667 583.583 638.467 565.183 643.8C546.783 649.133 525.849 651.8 502.383 651.8ZM684.717 646.2C680.184 650.733 674.584 653 667.917 653C661.517 653 656.051 650.733 651.517 646.2C646.984 641.667 644.717 636.2 644.717 629.8C644.717 623.133 646.984 617.533 651.517 613C656.051 608.467 661.517 606.2 667.917 606.2C674.584 606.2 680.184 608.467 684.717 613C689.517 617.533 691.917 623.133 691.917 629.8C691.917 636.2 689.517 641.667 684.717 646.2Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -4,5 +4,5 @@ import { GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET } from '$env/static/private';
export const google = new Google(
GOOGLE_CLIENT_ID,
GOOGLE_CLIENT_SECRET,
'https://sergeno.ziasvannes.tech/login/google/callback'
'https://serengo.ziasvannes.tech/login/google/callback'
);

View File

@@ -14,6 +14,20 @@
<svelte:head>
<link rel="icon" href={favicon} />
<!-- Performance optimizations -->
<link
rel="preload"
href="/fonts/Washington.ttf"
as="font"
type="font/ttf"
crossorigin="anonymous"
/>
<link rel="dns-prefetch" href="//tile.openstreetmap.org" />
<link rel="preconnect" href="https://tile.openstreetmap.org" crossorigin="anonymous" />
<!-- Resource hints for login page background -->
{#if isLoginRoute}
<link rel="preload" href="/cafe-bg-compressed.jpg" as="image" />
{/if}
</svelte:head>
<Toaster />

View File

@@ -2,6 +2,26 @@
import { Map } from '$lib';
</script>
<svelte:head>
<title>Serengo - Meet the Unexpected</title>
<meta
name="description"
content="Discover unexpected places and experiences with Serengo's interactive map. Find hidden gems and explore your surroundings like never before."
/>
<meta property="og:title" content="Serengo - Meet the Unexpected" />
<meta
property="og:description"
content="Discover unexpected places and experiences with Serengo's interactive map. Find hidden gems and explore your surroundings like never before."
/>
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Serengo - Meet the Unexpected" />
<meta
name="twitter:description"
content="Discover unexpected places and experiences with Serengo's interactive map. Find hidden gems and explore your surroundings like never before."
/>
</svelte:head>
<div class="home-container">
<main class="main-content">
<div class="map-section">

View File

@@ -5,6 +5,26 @@
let { form }: { form: ActionData } = $props();
</script>
<svelte:head>
<title>Login - Serengo</title>
<meta
name="description"
content="Sign in to your Serengo account to access personalized maps and discover unexpected places around you."
/>
<meta property="og:title" content="Login - Serengo" />
<meta
property="og:description"
content="Sign in to your Serengo account to access personalized maps and discover unexpected places around you."
/>
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Login - Serengo" />
<meta
name="twitter:description"
content="Sign in to your Serengo account to access personalized maps and discover unexpected places around you."
/>
</svelte:head>
<div class="login-background flex min-h-svh flex-col items-center justify-center gap-6 p-6 md:p-10">
<div class="flex w-full max-w-sm flex-col gap-6">
<LoginForm {form} />
@@ -12,7 +32,7 @@
<style>
.login-background {
background-image: url('/cafe-bg.jpeg');
background-image: url('/cafe-bg-compressed.jpg');
background-size: cover;
background-position: center;
background-repeat: no-repeat;
@@ -34,5 +54,16 @@
position: relative;
z-index: 2;
}
/* Preload hint for faster loading */
@media (prefers-reduced-data: no-preference) {
.login-background::after {
content: '';
position: absolute;
background-image: url('/cafe-bg-compressed.jpg');
opacity: 0;
z-index: -1;
}
}
</style>
</div>

View File

@@ -0,0 +1,29 @@
import type { RequestHandler } from '@sveltejs/kit';
export const GET: RequestHandler = async ({ url }) => {
const baseUrl = url.origin;
const lastmod = new Date().toISOString().split('T')[0]; // YYYY-MM-DD format
const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>${baseUrl}/</loc>
<lastmod>${lastmod}</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>${baseUrl}/login</loc>
<lastmod>${lastmod}</lastmod>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
</urlset>`;
return new Response(sitemap, {
headers: {
'Content-Type': 'application/xml',
'Cache-Control': 'max-age=86400' // Cache for 24 hours
}
});
};

View File

@@ -15,33 +15,71 @@ import { build, files, version } from '$service-worker';
// This gives `self` the correct types
const self = globalThis.self as unknown as ServiceWorkerGlobalScope;
// Create a unique cache name for this deployment
// Create cache names for this deployment
const CACHE = `cache-${version}`;
const RUNTIME_CACHE = `runtime-${version}`;
const IMAGE_CACHE = `images-${version}`;
const ASSETS = [
...build, // the app itself
...files // everything in `static`
];
// Assets to precache for better performance
const CRITICAL_ASSETS = ['/cafe-bg-compressed.jpg', '/fonts/Washington.ttf', '/logo.svg'];
self.addEventListener('install', (event) => {
// Create a new cache and add all files to it
async function addFilesToCache() {
const cache = await caches.open(CACHE);
const imageCache = await caches.open(IMAGE_CACHE);
// Cache core assets
await cache.addAll(ASSETS);
// Precache critical assets with error handling
await Promise.allSettled(
CRITICAL_ASSETS.map(async (asset) => {
try {
const response = await fetch(asset);
if (response.ok) {
if (
asset.includes('jpg') ||
asset.includes('jpeg') ||
asset.includes('png') ||
asset.includes('webp')
) {
await imageCache.put(asset, response);
} else {
await cache.put(asset, response);
}
}
} catch (error) {
console.warn(`Failed to cache ${asset}:`, error);
}
})
);
}
event.waitUntil(addFilesToCache());
// Skip waiting to activate immediately
self.skipWaiting();
});
self.addEventListener('activate', (event) => {
// Remove previous cached data from disk
async function deleteOldCaches() {
const currentCaches = [CACHE, RUNTIME_CACHE, IMAGE_CACHE];
for (const key of await caches.keys()) {
if (key !== CACHE) await caches.delete(key);
if (!currentCaches.includes(key)) {
await caches.delete(key);
}
}
}
event.waitUntil(deleteOldCaches());
// Claim clients immediately
self.clients.claim();
});
self.addEventListener('fetch', (event) => {
@@ -51,6 +89,8 @@ self.addEventListener('fetch', (event) => {
async function respond() {
const url = new URL(event.request.url);
const cache = await caches.open(CACHE);
const runtimeCache = await caches.open(RUNTIME_CACHE);
const imageCache = await caches.open(IMAGE_CACHE);
// `build`/`files` can always be served from the cache
if (ASSETS.includes(url.pathname)) {
@@ -61,6 +101,50 @@ self.addEventListener('fetch', (event) => {
}
}
// Handle images with cache-first strategy
if (url.pathname.match(/\.(jpg|jpeg|png|gif|webp|svg)$/i)) {
const cachedResponse = await imageCache.match(event.request);
if (cachedResponse) {
return cachedResponse;
}
try {
const response = await fetch(event.request);
if (response.ok) {
imageCache.put(event.request, response.clone());
}
return response;
} catch {
// Return a fallback image or the cached version
return cachedResponse || new Response('Image not available', { status: 404 });
}
}
// Handle fonts with cache-first strategy
if (url.pathname.match(/\.(woff|woff2|ttf|otf)$/i)) {
const cachedResponse = await cache.match(event.request);
if (cachedResponse) {
return cachedResponse;
}
}
// Handle API and dynamic content with network-first strategy
if (url.pathname.startsWith('/api/') || url.searchParams.has('_data')) {
try {
const response = await fetch(event.request);
if (response.ok) {
runtimeCache.put(event.request, response.clone());
}
return response;
} catch (err) {
const cachedResponse = await runtimeCache.match(event.request);
if (cachedResponse) {
return cachedResponse;
}
throw err;
}
}
// for everything else, try the network first, but
// fall back to the cache if we're offline
try {
@@ -73,15 +157,19 @@ self.addEventListener('fetch', (event) => {
}
if (response.status === 200) {
cache.put(event.request, response.clone());
runtimeCache.put(event.request, response.clone());
}
return response;
} catch (err) {
const response = await cache.match(event.request);
// Try all caches for fallback
const cachedResponse =
(await cache.match(event.request)) ||
(await runtimeCache.match(event.request)) ||
(await imageCache.match(event.request));
if (response) {
return response;
if (cachedResponse) {
return cachedResponse;
}
// if there's no cache, then just error out

Binary file not shown.

Before

Width:  |  Height:  |  Size: 594 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 719 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 343 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 551 B

View File

@@ -1,4 +1,6 @@
<svg width="250" height="250" viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="250" height="250" fill="#D9D9D9"/>
<path d="M122.823 166.616C111.473 166.616 100.892 165.037 91.0785 161.88L89.2865 137.304H90.4385C98.0332 154.712 108.999 163.416 123.335 163.416C129.82 163.416 134.812 162.307 138.311 160.088C141.809 157.784 143.559 154.413 143.559 149.976C143.559 147.672 143.004 145.581 141.895 143.704C140.785 141.741 138.993 139.907 136.519 138.2C134.129 136.408 131.697 134.872 129.223 133.592C126.748 132.312 123.548 130.776 119.623 128.984L115.271 127.064C112.881 126.04 110.791 125.059 108.999 124.12C107.207 123.181 105.201 122.072 102.983 120.792C100.849 119.512 99.0145 118.189 97.4785 116.824C95.9425 115.459 94.4918 114.008 93.1265 112.472C91.7612 110.851 90.7372 109.101 90.0545 107.224C89.3718 105.261 89.0305 103.256 89.0305 101.208C89.0305 95.832 90.7372 91.2667 94.1505 87.512C97.6492 83.7573 102.215 81.0693 107.847 79.448C113.479 77.7413 120.049 76.888 127.559 76.888C136.604 76.888 146.204 78.424 156.359 81.496L158.535 106.2H157.511C153.841 97.8373 149.404 91.3947 144.199 86.872C138.993 82.3493 132.593 80.088 124.999 80.088C119.879 80.088 115.825 81.24 112.839 83.544C109.852 85.7627 108.359 88.7067 108.359 92.376C108.359 94.424 108.785 96.2587 109.639 97.88C110.577 99.5013 112.028 100.995 113.991 102.36C116.039 103.64 118.044 104.749 120.007 105.688C121.969 106.627 124.572 107.736 127.815 109.016L133.191 111.192C137.287 112.813 140.956 114.52 144.199 116.312C147.441 118.019 150.556 120.109 153.543 122.584C156.529 124.973 158.833 127.747 160.455 130.904C162.076 134.061 162.887 137.475 162.887 141.144C162.887 146.861 161.009 151.683 157.255 155.608C153.585 159.533 148.807 162.349 142.919 164.056C137.031 165.763 130.332 166.616 122.823 166.616Z" fill="black"/>
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(102.4, 102.4) scale(0.8)">
<path d="M759 0H265C118.645 0 0 118.645 0 265V759C0 905.355 118.645 1024 265 1024H759C905.355 1024 1024 905.355 1024 759V265C1024 118.645 905.355 0 759 0Z" fill="#D9D9D9"/>
<path d="M502.383 651.8C466.916 651.8 433.849 646.867 403.183 637L397.583 560.2H401.183C424.916 614.6 459.183 641.8 503.983 641.8C524.249 641.8 539.849 638.333 550.783 631.4C561.716 624.2 567.183 613.667 567.183 599.8C567.183 592.6 565.449 586.067 561.983 580.2C558.516 574.067 552.916 568.333 545.183 563C537.716 557.4 530.116 552.6 522.383 548.6C514.649 544.6 504.649 539.8 492.383 534.2L478.783 528.2C471.316 525 464.783 521.933 459.183 519C453.583 516.067 447.316 512.6 440.383 508.6C433.716 504.6 427.983 500.467 423.183 496.2C418.383 491.933 413.849 487.4 409.583 482.6C405.316 477.533 402.116 472.067 399.983 466.2C397.849 460.067 396.783 453.8 396.783 447.4C396.783 430.6 402.116 416.333 412.783 404.6C423.716 392.867 437.983 384.467 455.583 379.4C473.183 374.067 493.716 371.4 517.183 371.4C545.449 371.4 575.449 376.2 607.183 385.8L613.983 463H610.783C599.316 436.867 585.449 416.733 569.183 402.6C552.916 388.467 532.916 381.4 509.183 381.4C493.183 381.4 480.516 385 471.183 392.2C461.849 399.133 457.183 408.333 457.183 419.8C457.183 426.2 458.516 431.933 461.183 437C464.116 442.067 468.649 446.733 474.783 451C481.183 455 487.449 458.467 493.583 461.4C499.716 464.333 507.849 467.8 517.983 471.8L534.783 478.6C547.583 483.667 559.049 489 569.183 494.6C579.316 499.933 589.049 506.467 598.383 514.2C607.716 521.667 614.916 530.333 619.983 540.2C625.049 550.067 627.583 560.733 627.583 572.2C627.583 590.067 621.716 605.133 609.983 617.4C598.516 629.667 583.583 638.467 565.183 643.8C546.783 649.133 525.849 651.8 502.383 651.8ZM684.717 646.2C680.184 650.733 674.584 653 667.917 653C661.517 653 656.051 650.733 651.517 646.2C646.984 641.667 644.717 636.2 644.717 629.8C644.717 623.133 646.984 617.533 651.517 613C656.051 608.467 661.517 606.2 667.917 606.2C674.584 606.2 680.184 608.467 684.717 613C689.517 617.533 691.917 623.133 691.917 629.8C691.917 636.2 689.517 641.667 684.717 646.2Z" fill="black"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -1,26 +1,20 @@
{
"short_name": "Serengo",
"name": "Serengo",
"description": "meet the unexpected.",
"name": "Serengo - meet the unexpected.",
"description": "Discover unexpected places and experiences with Serengo's interactive map. Find hidden gems and explore your surroundings like never before.",
"icons": [
{
"src": "/favicon-64x64.png",
"sizes": "64x64",
"type": "image/png"
},
{
"src": "/favicon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/favicon-512x512.png",
"sizes": "512x512",
"type": "image/png"
"src": "/logo.svg",
"sizes": "any",
"type": "image/svg+xml",
"purpose": "any maskable"
}
],
"start_url": ".",
"start_url": "/",
"display": "standalone",
"theme_color": "black",
"background_color": "white"
"orientation": "portrait-primary",
"theme_color": "#333333",
"background_color": "#f8f8f8",
"scope": "/",
"categories": ["travel", "maps", "discovery"]
}

View File

@@ -1,3 +1,13 @@
# allow crawling everything by default
# Serengo - meet the unexpected.
User-agent: *
Disallow:
Allow: /
Disallow: /api/
Disallow: /logout
Disallow: /_app/
Disallow: /.svelte-kit/
# Sitemap location
Sitemap: https://serengo.ziasvannes.tech/sitemap.xml
# Crawl delay for polite crawling
Crawl-delay: 1

View File

@@ -4,5 +4,12 @@ import { defineConfig } from 'vite';
export default defineConfig({
plugins: [tailwindcss(), sveltekit()],
preview: { allowedHosts: ['ziasvannes.tech'] }
preview: { allowedHosts: ['ziasvannes.tech'] },
build: {
target: 'es2020',
cssCodeSplit: true
},
optimizeDeps: {
include: ['maplibre-gl', 'svelte-maplibre']
}
});