feat(content): Swedish copy, new /tjanster page with booking flow and FAQ

- New /tjanster: genres from existing copy, where/price (contact for offer
  while unknown), booking flow via customer portal, delivery in a private
  gallery, originals after payment, FAQ (also emitted as FAQPage).
- Homepage: tagline + text section on who/what/where/how to book.
- About: Swedish, photographer framing instead of "by day/by night",
  Adobe line. Contact: Swedish, plain mailto info@, booking CTA, fixed
  unclosed div. Privacy: Swedish (Google Limited Use line kept in English).
- Unique Swedish title and description per page; scripts moved inside the
  layout (no <script> after </html>).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WvE3C43Uwtv2vtnoFBLDw7
This commit is contained in:
Linus Olofsson
2026-10-27 19:13:07 +01:00
co-authored by Claude Opus 5.5
parent f452d6d237
commit 206d31d9c2
5 changed files with 401 additions and 208 deletions
+34 -24
View File
@@ -4,9 +4,18 @@ import MainLayout from '../layouts/MainLayout.astro';
import { Image } from 'astro:assets'; import { Image } from 'astro:assets';
import profileImg from '../assets/images/about/profile.jpg'; import profileImg from '../assets/images/about/profile.jpg';
import WaveBackground from '../components/WaveBackground.astro'; import WaveBackground from '../components/WaveBackground.astro';
import { business, basedIn } from '../data/business';
--- ---
<MainLayout title="About | Images by Olofsson"> <MainLayout
title="Om Linus Olofsson – fotograf | Images by Olofsson"
description={`Linus Olofsson är fotografen bakom Images by Olofsson, baserad i ${basedIn()}. ${business.recognitionThirdPerson} Läs om hans bildspråk och utrustning.`}
path="/about"
image={profileImg}
imageAlt="Porträtt av fotografen Linus Olofsson"
pageType="AboutPage"
breadcrumb="Om mig"
>
<WaveBackground opacity="opacity-80" /> <WaveBackground opacity="opacity-80" />
@@ -21,7 +30,7 @@ import WaveBackground from '../components/WaveBackground.astro';
<div class="relative rounded-2xl overflow-hidden shadow-2xl border border-white/10 transform transition duration-500 group-hover:scale-[1.01]"> <div class="relative rounded-2xl overflow-hidden shadow-2xl border border-white/10 transform transition duration-500 group-hover:scale-[1.01]">
<Image <Image
src={profileImg} src={profileImg}
alt="Linus Olofsson Photographer" alt="Porträtt av fotografen Linus Olofsson"
width={800} width={800}
height={1000} height={1000}
class="w-full h-auto object-cover grayscale hover:grayscale-0 transition-all duration-700 ease-in-out" class="w-full h-auto object-cover grayscale hover:grayscale-0 transition-all duration-700 ease-in-out"
@@ -31,25 +40,24 @@ import WaveBackground from '../components/WaveBackground.astro';
<div class="w-full lg:w-1/2 space-y-6"> <div class="w-full lg:w-1/2 space-y-6">
<h1 class="text-4xl md:text-5xl font-bold leading-tight"> <h1 class="text-4xl md:text-5xl font-bold leading-tight">
Dynamic moments, <br/> Levande ögonblick, <br/>
<span class="text-transparent bg-clip-text bg-gradient-to-r from-white to-gray-500">Frozen in high resolution.</span> <span class="text-transparent bg-clip-text bg-gradient-to-r from-white to-gray-400">fångade i hög upplösning.</span>
</h1> </h1>
<div class="space-y-4 text-gray-300 text-lg leading-relaxed"> <div class="space-y-4 text-gray-300 text-lg leading-relaxed">
<p> <p>
Hi — I’m Linus Olofsson. Hej, jag heter {business.person.name} och är fotografen bakom {business.brand}.
Cloud specialist by day, passionate photographer by night.
</p> </p>
<p> <p>
Based in Sweden, my journey began with a simple curiosity for how light shapes the way we perceive the world. Over time, that curiosity evolved into an obsession with capturing the subtle details most people overlook — textures, structures, contrasts and moments that flicker by unnoticed. Jag är baserad i {basedIn()}. Allt började med en enkel nyfikenhet på hur ljuset formar sättet vi ser världen på. Med tiden blev nyfikenheten en besatthet av att fånga detaljerna som de flesta missar – texturer, strukturer, kontraster och ögonblick som passerar obemärkt förbi.
</p> </p>
<p> <p>
I find beauty in the small things: a stone, a tree, an empty street, a quiet forest path, or the expression of a stranger passing by. Jag hittar skönheten i det lilla: en sten, ett träd, en tom gata, en stilla skogsstig eller uttrycket hos en främling som går förbi.
</p> </p>
<p> <p>
Whether it’s the intricate patterns of a macro shot, the vast silence of nature, or the energy of a city, my goal is Oavsett om det är de invecklade mönstren i en makrobild, naturens stora tystnad eller stadens energi är målet alltid detsamma – att skapa bilder som förmedlar känslor och berättar en historia utan ord.
always the same — to create images that convey emotion and tell a story without words.
</p> </p>
<p>{business.recognition}</p>
</div> </div>
<div class="pt-4"> <div class="pt-4">
@@ -58,10 +66,13 @@ import WaveBackground from '../components/WaveBackground.astro';
<div class="flex flex-wrap gap-4 pt-6"> <div class="flex flex-wrap gap-4 pt-6">
<a href="/contact" class="inline-block bg-white text-black px-8 py-3 rounded-full font-bold hover:bg-gray-200 transition-colors shadow-lg"> <a href="/contact" class="inline-block bg-white text-black px-8 py-3 rounded-full font-bold hover:bg-gray-200 transition-colors shadow-lg">
Get in touch Kontakta mig
</a> </a>
<a href="/portfolio" class="inline-block border border-white text-white px-8 py-3 rounded-full font-bold hover:bg-white/10 transition-colors"> <a href="/portfolio" class="inline-block border border-white text-white px-8 py-3 rounded-full font-bold hover:bg-white/10 transition-colors">
View the world through my eyes Se världen genom mina ögon
</a>
<a href="/tjanster" class="inline-block border border-white/40 text-white px-8 py-3 rounded-full font-bold hover:bg-white/10 transition-colors">
Tjänster och bokning
</a> </a>
</div> </div>
</div> </div>
@@ -69,7 +80,7 @@ import WaveBackground from '../components/WaveBackground.astro';
</div> </div>
</div> </div>
<div class="border-t border-white/10 pt-16"> <div class="border-t border-white/10 pt-16">
<h2 class="text-3xl font-bold mb-10 text-center text-white">What's in my bag?</h2> <h2 class="text-3xl font-bold mb-10 text-center text-white">Vad har jag i kameraväskan?</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-8"> <div class="grid grid-cols-1 md:grid-cols-3 gap-8">
@@ -77,20 +88,19 @@ import WaveBackground from '../components/WaveBackground.astro';
<div class="icon-box"> <div class="icon-box">
<svg class="w-8 h-8 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z" /><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M15 13a3 3 0 11-6 0 3 3 0 016 0z" /></svg> <svg class="w-8 h-8 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z" /><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M15 13a3 3 0 11-6 0 3 3 0 016 0z" /></svg>
</div> </div>
<h3 class="text-xl font-bold mb-2 text-white">Camera Body</h3> <h3 class="text-xl font-bold mb-2 text-white">Kamerahus</h3>
<p class="text-gray-400">Sony A7RV</p> <p class="text-gray-300">{business.camera}</p>
<p class="text-gray-500 text-sm mt-2">A trusty companion that has been with me on countless adventures.</p> <p class="text-gray-400 text-sm mt-2">En pålitlig följeslagare som har varit med mig på otaliga äventyr.</p>
</div> </div>
<div data-trail-box class="gear-card"> <div data-trail-box class="gear-card">
<div class="icon-box"> <div class="icon-box">
<svg class="w-8 h-8 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" /></svg> <svg class="w-8 h-8 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" /></svg>
</div> </div>
<h3 class="text-xl font-bold mb-2 text-white">Lenses</h3> <h3 class="text-xl font-bold mb-2 text-white">Objektiv</h3>
<ul class="text-gray-400 text-sm space-y-1"> <ul class="text-gray-300 text-sm space-y-1">
<li>Sony FE 70-200mm f/4 G OSS</li> {business.lenses.map((lens) => <li>{lens}</li>)}
<li>Sony FE 20mm f/1.8 G</li> <li>och ett par extra batterier</li>
<li>and a couple of extra batteries</li>
</ul> </ul>
</div> </div>
@@ -98,9 +108,9 @@ import WaveBackground from '../components/WaveBackground.astro';
<div class="icon-box"> <div class="icon-box">
<svg class="w-8 h-8 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" /></svg> <svg class="w-8 h-8 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" /></svg>
</div> </div>
<h3 class="text-xl font-bold mb-2 text-white">Editing</h3> <h3 class="text-xl font-bold mb-2 text-white">Redigering</h3>
<p class="text-gray-400">Adobe Lightroom Classic</p> <p class="text-gray-300">{business.editing}</p>
<p class="text-gray-500 text-sm mt-2">Where the raw captures come to life. I focus on natural tones and contrast.</p> <p class="text-gray-400 text-sm mt-2">Här får råfilerna liv. Jag fokuserar på naturliga toner och kontrast.</p>
</div> </div>
</div> </div>
+55 -42
View File
@@ -2,55 +2,66 @@
// src/pages/contact.astro // src/pages/contact.astro
import MainLayout from '../layouts/MainLayout.astro'; import MainLayout from '../layouts/MainLayout.astro';
import WaveBackground from '../components/WaveBackground.astro'; import WaveBackground from '../components/WaveBackground.astro';
import { business } from '../data/business';
--- ---
<MainLayout title="Contact | Images by Olofsson"> <MainLayout
title="Kontakt och bokning | Images by Olofsson"
description={`Kontakta fotograf Linus Olofsson på ${business.email} eller Instagram ${business.social.instagram.handle}, eller skicka en bokningsförfrågan via kundportalen.`}
path="/contact"
pageType="ContactPage"
breadcrumb="Kontakt"
>
<div> <div>
<WaveBackground opacity="opacity-80" theme="purple" /> <WaveBackground opacity="opacity-80" theme="purple" />
</div> </div>
<div class="container mx-auto px-4 py-12 md:py-20 relative z-10"> <div class="container mx-auto px-4 py-12 md:py-20 relative z-10">
<div class="container mx-auto px-4 py-12 md:py-20">
<div class="grid grid-cols-1 md:grid-cols-2 gap-12 lg:gap-20 max-w-6xl mx-auto items-start"> <div class="grid grid-cols-1 md:grid-cols-2 gap-12 lg:gap-20 max-w-6xl mx-auto items-start">
<div class="space-y-8"> <div class="space-y-8">
<div> <div>
<h1 class="text-4xl md:text-5xl font-bold mb-6">Get in touch</h1> <h1 class="text-4xl md:text-5xl font-bold mb-6">Kontakta mig</h1>
<p class="text-gray-400 text-lg leading-relaxed"> <p class="text-gray-300 text-lg leading-relaxed">
Do you have questions about any of my photos, collaborations, or just want to say hi? Har du frågor om någon av mina bilder, vill du samarbeta eller bara säga hej?
Connect with me on social media or send me a direct email. Hör av dig via sociala medier eller mejla mig direkt.
</p> </p>
<p class="text-gray-300 text-lg leading-relaxed mt-4">
Vill du boka en fotografering? Skicka en förfrågan i kundportalen så återkommer jag med en offert.
Läs mer om hur det går till under <a href="/tjanster" class="text-white underline underline-offset-4 hover:text-gray-300">Tjänster</a>.
</p>
<a href={business.portal.bookingUrl} class="inline-block mt-6 px-8 py-3 bg-white text-black font-bold rounded-full hover:bg-gray-200 transition">Skicka en bokningsförfrågan</a>
</div> </div>
<div> <div>
<h2 class="text-white font-semibold text-xl mb-4">You can also find me on...</h2> <h2 class="text-white font-semibold text-xl mb-4">Du hittar mig också på</h2>
<div class="grid grid-cols-3 gap-4"> <div class="grid grid-cols-3 gap-4">
<a href="https://www.instagram.com/imagesbyolofsson/" target="_blank" rel="noopener noreferrer" class="social-card group" aria-label="Instagram"> <a href={business.social.instagram.url} target="_blank" rel="noopener noreferrer" class="social-card group" aria-label="Instagram">
<svg class="w-8 h-8 group-hover:text-pink-500 transition-colors" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z"/></svg> <svg class="w-8 h-8 group-hover:text-pink-500 transition-colors" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z"/></svg>
</a> </a>
<a href="https://www.flickr.com/photos/imagesbyolofsson/" target="_blank" rel="noopener noreferrer" class="social-card group" aria-label="Flickr"> <a href={business.social.flickr} target="_blank" rel="noopener noreferrer" class="social-card group" aria-label="Flickr">
<svg class="w-8 h-8 group-hover:text-blue-500 transition-colors" viewBox="0 0 24 24" fill="currentColor"><path d="M24 4v16h-24v-16h24zm-16.146 11.908c1.652 0 2.992-1.339 2.992-2.991 0-1.652-1.34-2.991-2.992-2.991-1.651 0-2.99 1.339-2.99 2.991 0 1.652 1.339 2.991 2.99 2.991zm8.008 0c1.652 0 2.992-1.339 2.992-2.991 0-1.652-1.34-2.991-2.992-2.991-1.652 0-2.992 1.339-2.992 2.991 0 1.652 1.34 2.991 2.992 2.991z"/></svg> <svg class="w-8 h-8 group-hover:text-blue-500 transition-colors" viewBox="0 0 24 24" fill="currentColor"><path d="M24 4v16h-24v-16h24zm-16.146 11.908c1.652 0 2.992-1.339 2.992-2.991 0-1.652-1.34-2.991-2.992-2.991-1.651 0-2.99 1.339-2.99 2.991 0 1.652 1.339 2.991 2.99 2.991zm8.008 0c1.652 0 2.992-1.339 2.992-2.991 0-1.652-1.34-2.991-2.992-2.991-1.652 0-2.992 1.339-2.992 2.991 0 1.652 1.34 2.991 2.992 2.991z"/></svg>
</a> </a>
<a href="https://lightroom.adobe.com/u/linusolofsson1" target="_blank" rel="noopener noreferrer" class="social-card group" aria-label="Adobe Lightroom"> <a href={business.social.lightroom} target="_blank" rel="noopener noreferrer" class="social-card group" aria-label="Adobe Lightroom">
<svg class="w-8 h-8 group-hover:text-cyan-400 transition-colors" viewBox="0 0 24 24" fill="currentColor"> <svg class="w-8 h-8 group-hover:text-cyan-400 transition-colors" viewBox="0 0 24 24" fill="currentColor">
<path d="M4 4v16h11v-4H8V4H4zm13 4c-2.21 0-4 1.79-4 4v8h4v-7c0-1.1.9-2 2-2v-3h-2z"/> <path d="M4 4v16h11v-4H8V4H4zm13 4c-2.21 0-4 1.79-4 4v8h4v-7c0-1.1.9-2 2-2v-3h-2z"/>
</svg> </svg>
</a> </a>
<a href="https://github.com/LinusOlofsson-maker" target="_blank" rel="noopener noreferrer" class="social-card group" aria-label="Github"> <a href={business.social.github} target="_blank" rel="noopener noreferrer" class="social-card group" aria-label="GitHub">
<svg class="w-8 h-8 group-hover:text-purple-500 transition-colors" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg> <svg class="w-8 h-8 group-hover:text-purple-500 transition-colors" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
</a> </a>
<a href="https://www.linkedin.com/in/linus-olofsson-/" target="_blank" rel="noopener noreferrer" class="social-card group" aria-label="LinkedIn"> <a href={business.social.linkedin} target="_blank" rel="noopener noreferrer" class="social-card group" aria-label="LinkedIn">
<svg class="w-8 h-8 group-hover:text-blue-400 transition-colors" viewBox="0 0 24 24" fill="currentColor"><path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"/></svg> <svg class="w-8 h-8 group-hover:text-blue-400 transition-colors" viewBox="0 0 24 24" fill="currentColor"><path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"/></svg>
</a> </a>
<a href="mailto:Admin@imagesbyolofsson.se" class="social-card group" aria-label="Email"> <a href={`mailto:${business.email}`} class="social-card group" aria-label="E-post">
<svg class="w-8 h-8 group-hover:text-green-500 transition-colors" viewBox="0 0 24 24" fill="currentColor"><path d="M0 3v18h24v-18h-24zm6.623 7.929l-4.623 5.712v-11.174l4.623 5.462zm5.377 2.738l-5.354-6.324-3.791 3.214 9.145 10.829 9.145-10.829-3.791-3.214-5.354 6.324zm5.377-2.738l4.623-5.462v11.174l-4.623-5.712z"/></svg> <svg class="w-8 h-8 group-hover:text-green-500 transition-colors" viewBox="0 0 24 24" fill="currentColor"><path d="M0 3v18h24v-18h-24zm6.623 7.929l-4.623 5.712v-11.174l4.623 5.462zm5.377 2.738l-5.354-6.324-3.791 3.214 9.145 10.829 9.145-10.829-3.791-3.214-5.354 6.324zm5.377-2.738l4.623-5.462v11.174l-4.623-5.712z"/></svg>
</a> </a>
@@ -63,8 +74,8 @@ import WaveBackground from '../components/WaveBackground.astro';
<div data-trail-box class="relative bg-neutral-900 ring-1 ring-white/10 rounded-xl p-8 md:p-12 text-center space-y-10"> <div data-trail-box class="relative bg-neutral-900 ring-1 ring-white/10 rounded-xl p-8 md:p-12 text-center space-y-10">
<div> <div>
<h3 class="text-2xl font-bold text-white mb-2">Waiting to hear from you</h3> <h2 class="text-2xl font-bold text-white mb-2">Jag ser fram emot att höra av dig</h2>
<p class="text-gray-400">Feel free to reach out for inquiries or just a chat.</p> <p class="text-gray-300">Hör gärna av dig med frågor, förfrågningar eller bara för att prata.</p>
</div> </div>
<div class="space-y-4"> <div class="space-y-4">
@@ -74,18 +85,21 @@ import WaveBackground from '../components/WaveBackground.astro';
</svg> </svg>
</div> </div>
<div> <div>
<p class="text-sm text-gray-500 uppercase tracking-widest mb-2">Email me at</p> <p class="text-sm text-gray-400 uppercase tracking-widest mb-2">Mejla mig på</p>
<button id="email-btn" class="text-xl md:text-3xl font-bold text-white hover:text-purple-400 transition-colors break-all" data-email="Admin@imagesbyolofsson.se"> <a href={`mailto:${business.email}`} class="text-xl md:text-3xl font-bold text-white hover:text-purple-400 transition-colors break-all">
Admin@imagesbyolofsson.se {business.email}
</button> </a>
<p id="copy-feedback" class="h-4 text-xs text-green-400 mt-2 opacity-0 transition-opacity">Copied to clipboard!</p> <div>
<button type="button" id="email-btn" class="mt-3 text-xs uppercase tracking-widest text-gray-400 hover:text-white transition-colors" data-email={business.email}>Kopiera adressen</button>
</div>
<p id="copy-feedback" class="h-4 text-xs text-green-400 mt-2 opacity-0 transition-opacity" aria-live="polite">Kopierad!</p>
</div> </div>
</div> </div>
<div class="pt-2"> <div class="pt-2">
<p class="text-sm text-gray-500 uppercase tracking-widest mb-4">Or DM me on Instagram</p> <p class="text-sm text-gray-400 uppercase tracking-widest mb-4">Eller skriv till mig på Instagram</p>
<a href="https://www.instagram.com/imagesbyolofsson/" target="_blank" class="inline-flex items-center gap-2 text-xl font-bold text-white hover:text-pink-500 transition-colors"> <a href={business.social.instagram.url} target="_blank" rel="noopener noreferrer" class="inline-flex items-center gap-2 text-xl font-bold text-white hover:text-pink-500 transition-colors">
@imagesbyolofsson {business.social.instagram.handle}
</a> </a>
</div> </div>
</div> </div>
@@ -93,6 +107,24 @@ import WaveBackground from '../components/WaveBackground.astro';
</div> </div>
</div> </div>
<script>
const emailBtn = document.getElementById('email-btn');
const feedback = document.getElementById('copy-feedback');
if (emailBtn && feedback) {
emailBtn.addEventListener('click', () => {
const email = emailBtn.getAttribute('data-email');
if (email) {
navigator.clipboard.writeText(email).then(() => {
feedback.style.opacity = '1';
setTimeout(() => {
feedback.style.opacity = '0';
}, 2000);
});
}
});
}
</script>
</MainLayout> </MainLayout>
<style> <style>
@@ -107,22 +139,3 @@ import WaveBackground from '../components/WaveBackground.astro';
@apply bg-neutral-700 border-white/20 transform -translate-y-1 shadow-lg shadow-white/5; @apply bg-neutral-700 border-white/20 transform -translate-y-1 shadow-lg shadow-white/5;
} }
</style> </style>
<script>
const emailBtn = document.getElementById('email-btn');
const feedback = document.getElementById('copy-feedback');
if (emailBtn && feedback) {
emailBtn.addEventListener('click', () => {
const email = emailBtn.getAttribute('data-email');
if (email) {
navigator.clipboard.writeText(email).then(() => {
feedback.style.opacity = '1';
setTimeout(() => {
feedback.style.opacity = '0';
}, 2000);
});
}
});
}
</script>
+135 -105
View File
@@ -3,9 +3,14 @@
import MainLayout from '../layouts/MainLayout.astro'; import MainLayout from '../layouts/MainLayout.astro';
import ThreeDScroll from '../components/ThreeDScroll.astro'; import ThreeDScroll from '../components/ThreeDScroll.astro';
import WaveBackground from '../components/WaveBackground.astro'; import WaveBackground from '../components/WaveBackground.astro';
import { business, basedIn, genreList } from '../data/business';
--- ---
<MainLayout title="Home | Images by Olofsson"> <MainLayout
title="Images by Olofsson – fotograf Linus Olofsson i Sverige"
description={`Fotograf Linus Olofsson (Images by Olofsson) i ${basedIn()}: porträtt, natur och djur, stad, makro, norrsken och familjefester. Boka via kundportalen.`}
path="/"
>
<div id="wave-wrapper" class="fixed inset-0 z-0 pointer-events-none transition-opacity duration-1000 ease-in-out" style="opacity: 0.4;"> <div id="wave-wrapper" class="fixed inset-0 z-0 pointer-events-none transition-opacity duration-1000 ease-in-out" style="opacity: 0.4;">
<WaveBackground opacity="opacity-100" theme="cyan" /> <WaveBackground opacity="opacity-100" theme="cyan" />
@@ -38,7 +43,8 @@ import WaveBackground from '../components/WaveBackground.astro';
</div> </div>
<p id="scroll-arrow" class="text-white/70 mt-6 text-lg font-light tracking-widest uppercase transition-opacity duration-300">↓</p> <p class="text-white/80 mt-4 text-base md:text-lg tracking-widest uppercase">Fotograf {business.person.name} &middot; {basedIn()}</p>
<p id="scroll-arrow" aria-hidden="true" class="text-white/70 mt-6 text-lg font-light tracking-widest uppercase transition-opacity duration-300">↓</p>
</div> </div>
</div> </div>
@@ -52,14 +58,14 @@ import WaveBackground from '../components/WaveBackground.astro';
<div class="flex flex-col md:flex-row gap-12 md:gap-24 items-center text-center"> <div class="flex flex-col md:flex-row gap-12 md:gap-24 items-center text-center">
<div data-trail-box class="flex flex-col items-center px-6 py-4 rounded-2xl"> <div data-trail-box class="flex flex-col items-center px-6 py-4 rounded-2xl">
<h2 class="text-3xl md:text-4xl text-white font-bold mb-6">Looking for inspiration?</h2> <h2 class="text-3xl md:text-4xl text-white font-bold mb-6">Letar du inspiration?</h2>
<a href="/portfolio" class="inline-block px-8 py-3 bg-white text-black font-bold rounded-full hover:bg-gray-200 transition transform hover:scale-105"> <a href="/portfolio" class="inline-block px-8 py-3 bg-white text-black font-bold rounded-full hover:bg-gray-200 transition transform hover:scale-105">
My Portfolio Se min portfolio
</a> </a>
</div> </div>
<div class="flex flex-row md:flex-col gap-6 items-center justify-center"> <div class="flex flex-row md:flex-col gap-6 items-center justify-center">
<a href="https://www.instagram.com/imagesbyolofsson/" target="_blank" rel="noopener noreferrer" class="circle-btn group" aria-label="Instagram"> <a href={business.social.instagram.url} target="_blank" rel="noopener noreferrer" class="circle-btn group" aria-label="Instagram">
<svg class="outline-ring" viewBox="0 0 100 100"> <svg class="outline-ring" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="48" /> <circle cx="50" cy="50" r="48" />
</svg> </svg>
@@ -69,7 +75,7 @@ import WaveBackground from '../components/WaveBackground.astro';
</svg> </svg>
</div> </div>
</a> </a>
<a href="https://lightroom.adobe.com/u/linusolofsson1" target="_blank" rel="noopener noreferrer" class="circle-btn group" aria-label="Lightroom"> <a href={business.social.lightroom} target="_blank" rel="noopener noreferrer" class="circle-btn group" aria-label="Adobe Lightroom">
<svg class="outline-ring" viewBox="0 0 100 100"> <svg class="outline-ring" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="48" /> <circle cx="50" cy="50" r="48" />
</svg> </svg>
@@ -80,15 +86,135 @@ import WaveBackground from '../components/WaveBackground.astro';
</div> </div>
<div data-trail-box class="flex flex-col items-center px-6 py-4 rounded-2xl"> <div data-trail-box class="flex flex-col items-center px-6 py-4 rounded-2xl">
<h2 class="text-3xl md:text-4xl text-white font-bold mb-6">Ready to collaborate?</h2> <h2 class="text-3xl md:text-4xl text-white font-bold mb-6">Vill du boka en fotografering?</h2>
<a href="/contact" class="inline-block px-8 py-3 bg-white text-black font-bold rounded-full hover:bg-gray-200 transition transform hover:scale-105"> <a href="/tjanster" class="inline-block px-8 py-3 bg-white text-black font-bold rounded-full hover:bg-gray-200 transition transform hover:scale-105">
Contact me Tjänster och bokning
</a> </a>
</div> </div>
</div> </div>
</div> </div>
<!-- Fakta om vem, vad, var och bokning: läsbar text för besökare, sökmotorer och AI-assistenter. -->
<section id="om-images-by-olofsson" class="relative z-30 bg-neutral-900 border-t border-white/10 py-16 md:py-24">
<div class="container mx-auto px-4 max-w-5xl grid gap-12 md:grid-cols-2">
<div class="space-y-5 text-gray-300 text-lg leading-relaxed">
<h2 class="text-3xl md:text-4xl font-bold text-white">Fotograf {business.person.name}</h2>
<p>
Jag heter {business.person.name} och fotograferar under namnet {business.brand}.
Jag är baserad i {basedIn()} och fotograferar {genreList()}.
</p>
<p>{business.recognition}</p>
<p>
Jag fotograferar med en {business.camera} och redigerar i {business.editing}, med fokus på naturliga toner och kontrast.
</p>
<p class="flex flex-wrap gap-x-6 gap-y-2 text-base">
<a href="/about" class="text-white underline underline-offset-4 hover:text-gray-300">Mer om mig</a>
<a href="/portfolio" class="text-white underline underline-offset-4 hover:text-gray-300">Portfolio</a>
<a href={`mailto:${business.email}`} class="text-white underline underline-offset-4 hover:text-gray-300">{business.email}</a>
</p>
</div>
<div class="space-y-5">
<h2 class="text-3xl md:text-4xl font-bold text-white">Så bokar du</h2>
<ol class="space-y-4 text-gray-300">
{business.bookingSteps.map((step, i) => (
<li class="flex gap-4">
<span class="shrink-0 w-8 h-8 rounded-full border border-white/30 flex items-center justify-center text-sm font-bold text-white">{i + 1}</span>
<span><strong class="text-white">{step.title}.</strong> {step.text}</span>
</li>
))}
</ol>
<div class="flex flex-wrap gap-4 pt-2">
<a href={business.portal.bookingUrl} class="inline-block px-6 py-3 bg-white text-black font-bold rounded-full hover:bg-gray-200 transition">Skicka en förfrågan</a>
<a href="/tjanster" class="inline-block px-6 py-3 border border-white text-white font-bold rounded-full hover:bg-white/10 transition">Vanliga frågor</a>
</div>
</div>
</div>
</section>
<script>
// SVG Längd
const path = document.getElementById('outline-path') as unknown as SVGPathElement;
if (path) {
const length = path.getTotalLength();
path.closest('svg')?.style.setProperty('--length', length.toString());
}
const heroText = document.getElementById('hero-text');
const textWrapper = document.getElementById('text-wrapper');
const arrow = document.getElementById('scroll-arrow');
const smokyPath = document.querySelector('.smoky-path') as SVGElement;
const waveWrapper = document.getElementById('wave-wrapper'); // Hämta bakgrunden
// LOGIK FÖR GRADVIS FADE BASERAT PÅ SCROLL
window.addEventListener('scroll', () => {
const scrollY = window.scrollY;
const windowHeight = window.innerHeight;
if (arrow) {
arrow.style.opacity = scrollY > 50 ? '0' : '1';
}
if (heroText && !footerIsVisible) {
const fadeProgress = Math.min(scrollY / (windowHeight * 3), 1);
heroText.style.opacity = fadeProgress.toString();
}
if (scrollY > 2500) {
if (smokyPath) smokyPath.style.animationDuration = '4s';
} else {
if (smokyPath) smokyPath.style.animationDuration = '6s';
}
});
// FOOTER INTERAKTION
const footer = document.getElementById('footer-section');
const imagesContainer = document.getElementById('images-container');
let footerIsVisible = false;
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
footerIsVisible = entry.isIntersecting;
if (entry.isIntersecting) {
// -- FOOTER SYNS --
if (imagesContainer) imagesContainer.style.opacity = '0';
if (heroText) {
heroText.style.opacity = '1';
heroText.style.transform = 'translateY(-25vh)';
}
// Tänd Brackets
if (textWrapper) textWrapper.classList.add('show-brackets');
// HÖJ OPACITY TILL 90% (Hårdkodat via style)
if (waveWrapper) {
waveWrapper.style.opacity = '0.9';
}
} else {
// -- FOOTER SYNS INTE --
if (imagesContainer) imagesContainer.style.opacity = '1';
if (heroText) {
heroText.style.transform = 'translateY(0)';
}
// Släck Brackets
if (textWrapper) textWrapper.classList.remove('show-brackets');
// ÅTERSTÄLL OPACITY TILL 40% (Hårdkodat via style)
if (waveWrapper) {
waveWrapper.style.opacity = '0.4';
}
}
});
}, { threshold: 0.1 });
if (footer) observer.observe(footer);
</script>
</MainLayout> </MainLayout>
<style> <style>
@@ -213,99 +339,3 @@ import WaveBackground from '../components/WaveBackground.astro';
.outline-ring circle { fill: none; stroke: white; stroke-width: 2; stroke-dasharray: 302; stroke-dashoffset: 302; transition: stroke-dashoffset 0.6s cubic-bezier(0.25, 1, 0.5, 1); opacity: 0.8; } .outline-ring circle { fill: none; stroke: white; stroke-width: 2; stroke-dasharray: 302; stroke-dashoffset: 302; transition: stroke-dashoffset 0.6s cubic-bezier(0.25, 1, 0.5, 1); opacity: 0.8; }
.circle-btn:hover .outline-ring circle { stroke-dashoffset: 0; } .circle-btn:hover .outline-ring circle { stroke-dashoffset: 0; }
</style> </style>
<script>
// SVG Längd
const path = document.getElementById('outline-path') as unknown as SVGPathElement;
if (path) {
const length = path.getTotalLength();
path.closest('svg')?.style.setProperty('--length', length.toString());
}
const heroText = document.getElementById('hero-text');
const textWrapper = document.getElementById('text-wrapper');
const arrow = document.getElementById('scroll-arrow');
const smokyPath = document.querySelector('.smoky-path') as SVGElement;
const waveWrapper = document.getElementById('wave-wrapper'); // Hämta bakgrunden
// LOGIK FÖR GRADVIS FADE BASERAT PÅ SCROLL
window.addEventListener('scroll', () => {
const scrollY = window.scrollY;
const windowHeight = window.innerHeight;
if (arrow) {
arrow.style.opacity = scrollY > 50 ? '0' : '1';
}
if (heroText && !footerIsVisible) {
const fadeProgress = Math.min(scrollY / (windowHeight * 3), 1);
heroText.style.opacity = fadeProgress.toString();
}
if (scrollY > 2500) {
if (smokyPath) smokyPath.style.animationDuration = '4s';
} else {
if (smokyPath) smokyPath.style.animationDuration = '6s';
}
});
// FOOTER INTERAKTION
const footer = document.getElementById('footer-section');
const imagesContainer = document.getElementById('images-container');
let footerIsVisible = false;
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
footerIsVisible = entry.isIntersecting;
if (entry.isIntersecting) {
// -- FOOTER SYNS --
if (imagesContainer) imagesContainer.style.opacity = '0';
if (heroText) {
heroText.style.opacity = '1';
heroText.style.transform = 'translateY(-25vh)';
}
// Tänd Brackets
if (textWrapper) textWrapper.classList.add('show-brackets');
// HÖJ OPACITY TILL 90% (Hårdkodat via style)
if (waveWrapper) {
waveWrapper.style.opacity = '0.9';
}
} else {
// -- FOOTER SYNS INTE --
if (imagesContainer) imagesContainer.style.opacity = '1';
if (heroText) {
heroText.style.transform = 'translateY(0)';
}
// Släck Brackets
if (textWrapper) textWrapper.classList.remove('show-brackets');
// ÅTERSTÄLL OPACITY TILL 40% (Hårdkodat via style)
if (waveWrapper) {
waveWrapper.style.opacity = '0.4';
}
}
});
}, { threshold: 0.1 });
if (footer) observer.observe(footer);
// FOOTER-LÄNKAR HOVER: ändra logo-glow när användare hovrar lyxlimo/karleksguiden-länkar
const glowLinks = document.querySelectorAll<HTMLElement>('[data-glow-link]');
glowLinks.forEach(link => {
link.addEventListener('mouseenter', () => {
if (!textWrapper) return;
const tint = link.getAttribute('data-glow-link');
if (tint) textWrapper.setAttribute('data-logo-tint', tint);
});
link.addEventListener('mouseleave', () => {
if (!textWrapper) return;
textWrapper.removeAttribute('data-logo-tint');
});
});
</script>
+50 -37
View File
@@ -2,89 +2,102 @@
// src/pages/privacy.astro // src/pages/privacy.astro
import MainLayout from '../layouts/MainLayout.astro'; import MainLayout from '../layouts/MainLayout.astro';
import WaveBackground from '../components/WaveBackground.astro'; import WaveBackground from '../components/WaveBackground.astro';
import { business } from '../data/business';
const link = 'text-white underline hover:text-gray-300';
--- ---
<MainLayout title="Privacy Policy | Images by Olofsson"> <MainLayout
title="Integritetspolicy | Images by Olofsson"
description="Hur imagesbyolofsson.se hanterar personuppgifter: Meta Pixel endast med samtycke, anonym bildstatistik utan cookies och dina rättigheter enligt GDPR."
path="/privacy"
breadcrumb="Integritetspolicy"
>
<WaveBackground opacity="opacity-80" /> <WaveBackground opacity="opacity-80" />
<div class="container mx-auto px-4 py-12 md:py-20 relative z-10"> <div class="container mx-auto px-4 py-12 md:py-20 relative z-10">
<div data-trail-box class="bg-neutral-900/60 backdrop-blur-md border border-white/10 rounded-3xl p-8 md:p-12 shadow-2xl mb-20 max-w-3xl mx-auto"> <div data-trail-box class="bg-neutral-900/60 backdrop-blur-md border border-white/10 rounded-3xl p-8 md:p-12 shadow-2xl mb-20 max-w-3xl mx-auto">
<h1 class="text-4xl md:text-5xl font-bold leading-tight mb-2">Privacy Policy</h1> <h1 class="text-4xl md:text-5xl font-bold leading-tight mb-2">Integritetspolicy</h1>
<p class="text-gray-500 mb-10">Last updated: 25 October 2026</p> <p class="text-gray-400 mb-10">Senast uppdaterad: 27 oktober 2026</p>
<div class="space-y-8 text-gray-300 text-lg leading-relaxed"> <div class="space-y-8 text-gray-300 text-lg leading-relaxed">
<section class="space-y-3"> <section class="space-y-3">
<h2 class="text-2xl font-bold text-white">Who is responsible</h2> <h2 class="text-2xl font-bold text-white">Vem som är ansvarig</h2>
<p> <p>
Images by Olofsson is run by Linus Olofsson, Sweden. Questions about privacy: {business.brand} drivs av {business.person.name}, {business.country.name}. Frågor om integritet:
<a href="mailto:Admin@imagesbyolofsson.se" class="text-white underline hover:text-gray-300">Admin@imagesbyolofsson.se</a>. <a href={`mailto:${business.email}`} class={link}>{business.email}</a>.
</p> </p>
</section> </section>
<section class="space-y-3"> <section class="space-y-3">
<h2 class="text-2xl font-bold text-white">This website</h2> <h2 class="text-2xl font-bold text-white">Den här webbplatsen</h2>
<ul class="list-disc pl-6 space-y-2"> <ul class="list-disc pl-6 space-y-2">
<li>There are no user accounts and no contact forms.</li> <li>Det finns inga användarkonton och inga kontaktformulär på den här webbplatsen. Bokningar görs i den separata kundportalen.</li>
<li>If you email me, your address and message are used only to answer you and are not shared with anyone.</li> <li>Om du mejlar mig används din adress och ditt meddelande bara för att svara dig och delas inte med någon.</li>
<li>Password-protected galleries keep the password only in your open browser tab; it is not stored after you close it.</li> <li>Lösenordsskyddade nedladdningar sparar lösenordet bara i din öppna webbläsarflik; det finns inte kvar när du stänger den.</li>
<li> <li>
The site is delivered through Cloudflare, which processes technical data such as your IP address to deliver Webbplatsen levereras via Cloudflare, som behandlar tekniska uppgifter som din IP-adress för att leverera
and protect the site. See <a href="https://www.cloudflare.com/privacypolicy/" target="_blank" rel="noopener noreferrer" class="text-white underline hover:text-gray-300">Cloudflare's privacy policy</a>. och skydda webbplatsen. Se <a href="https://www.cloudflare.com/privacypolicy/" target="_blank" rel="noopener noreferrer" class={link}>Cloudflares integritetspolicy</a>.
</li> </li>
<li>If you appear in one of my photos and want it removed, email me and I will take it down.</li> <li>Om du syns på någon av mina bilder och vill att den tas bort, mejla mig så tar jag bort den.</li>
</ul> </ul>
</section> </section>
<section class="space-y-3"> <section class="space-y-3">
<h2 class="text-2xl font-bold text-white">Meta Pixel (only with your consent)</h2> <h2 class="text-2xl font-bold text-white">Meta Pixel (bara med ditt samtycke)</h2>
<p> <p>
If you click "Accept" in the cookie box, the site loads the Meta Pixel from Meta Platforms Ireland Ltd. Om du klickar på ”Godkänn” i cookierutan laddar webbplatsen Meta Pixel från Meta Platforms Ireland Ltd.
I use it to see how visitors coming from my Instagram and Facebook use the site. Jag använder den för att se hur besökare som kommer från mitt Instagram och Facebook använder webbplatsen.
</p> </p>
<ul class="list-disc pl-6 space-y-2"> <ul class="list-disc pl-6 space-y-2">
<li>It sets cookies (such as <code>_fbp</code>) and sends Meta information like the pages you visit, your IP address and browser details.</li> <li>Den sätter cookies (till exempel <code>_fbp</code>) och skickar uppgifter till Meta, som vilka sidor du besöker, din IP-adress och information om din webbläsare.</li>
<li>Meta may link this to your Facebook or Instagram account and may transfer data outside the EU. See <li>Meta kan koppla detta till ditt Facebook- eller Instagramkonto och kan föra över uppgifter utanför EU. Se
<a href="https://www.facebook.com/privacy/policy/" target="_blank" rel="noopener noreferrer" class="text-white underline hover:text-gray-300">Meta's privacy policy</a>.</li> <a href="https://www.facebook.com/privacy/policy/" target="_blank" rel="noopener noreferrer" class={link}>Metas integritetspolicy</a>.</li>
<li>If you click "Decline" or do nothing, the pixel is never loaded.</li> <li>Om du klickar på ”Avböj” eller inte gör något laddas pixeln aldrig.</li>
<li>You can change your choice at any time via "Cookie settings" at the bottom of every page. Your choice is stored in your own browser.</li> <li>Du kan ändra ditt val när som helst via ”Cookie-inställningar” längst ner på varje sida. Ditt val sparas i din egen webbläsare.</li>
</ul> </ul>
</section> </section>
<section class="space-y-3"> <section class="space-y-3">
<h2 class="text-2xl font-bold text-white">Anonymous portfolio statistics</h2> <h2 class="text-2xl font-bold text-white">Anonym statistik för portfolion</h2>
<p> <p>
To see which photos people like, the portfolio counts how many times each photo is opened or downloaded, per day. För att se vilka bilder som uppskattas räknar portfolion hur många gånger varje bild öppnas eller laddas ner, per dag.
Only the count is stored, on my own server in Sweden. No cookies, no IP address, no browser details and nothing Bara antalet sparas, på min egen server i Sverige. Inga cookies, ingen IP-adress, ingen webbläsarinformation och inget
that could identify you. This happens without consent because nothing about you is collected. som kan identifiera dig. Det sker utan samtycke eftersom inga uppgifter om dig samlas in.
</p> </p>
</section> </section>
<section class="space-y-3"> <section class="space-y-3">
<h2 class="text-2xl font-bold text-white">Photo backup app (Google)</h2> <h2 class="text-2xl font-bold text-white">App för säkerhetskopiering av bilder (Google)</h2>
<p> <p>
"townhouse-backup" is a private tool used only by me to back up my own photos to my own Google account. ”townhouse-backup” är ett privat verktyg som bara jag använder för att säkerhetskopiera mina egna bilder till mitt eget Google-konto.
</p> </p>
<ul class="list-disc pl-6 space-y-2"> <ul class="list-disc pl-6 space-y-2">
<li>Google Drive: it only accesses files it has created itself (a backup copy of my photo archive).</li> <li>Google Drive: verktyget kommer bara åt filer som det själv har skapat (en säkerhetskopia av mitt bildarkiv).</li>
<li>Google Photos: it only uploads my photos and adds them to albums it created; it cannot see anything else in the library.</li> <li>Google Foto: verktyget laddar bara upp mina bilder och lägger dem i album som det själv har skapat; det kan inte se något annat i biblioteket.</li>
<li>No data from anyone else is collected. Nothing is sold, shared with third parties, used for advertising or used to train AI models.</li> <li>Inga uppgifter om någon annan samlas in. Ingenting säljs, delas med tredje part, används för reklam eller används för att träna AI-modeller.</li>
<li> <li>
Its use of information received from Google APIs adheres to the Verktygets användning av information från Googles API:er följer
<a href="https://developers.google.com/terms/api-services-user-data-policy" target="_blank" rel="noopener noreferrer" class="text-white underline hover:text-gray-300">Google API Services User Data Policy</a>, <a href="https://developers.google.com/terms/api-services-user-data-policy" target="_blank" rel="noopener noreferrer" class={link}>Google API Services User Data Policy</a>,
including the Limited Use requirements. inklusive kraven på begränsad användning (Limited Use).
</li> </li>
</ul> </ul>
<p lang="en" class="text-base text-gray-400">
In English: townhouse-backup's use of information received from Google APIs adheres to the
<a href="https://developers.google.com/terms/api-services-user-data-policy" target="_blank" rel="noopener noreferrer" class={link}>Google API Services User Data Policy</a>,
including the Limited Use requirements.
</p>
</section> </section>
<section class="space-y-3"> <section class="space-y-3">
<h2 class="text-2xl font-bold text-white">Your rights</h2> <h2 class="text-2xl font-bold text-white">Dina rättigheter</h2>
<p> <p>
Under the GDPR you can ask what personal data I hold about you, and have it corrected or deleted — just email me. Enligt GDPR kan du fråga vilka personuppgifter jag har om dig och få dem rättade eller raderade – mejla mig bara.
You can also complain to the Swedish Authority for Privacy Protection Du kan också klaga hos Integritetsskyddsmyndigheten
(<a href="https://www.imy.se/" target="_blank" rel="noopener noreferrer" class="text-white underline hover:text-gray-300">IMY</a>). (<a href="https://www.imy.se/" target="_blank" rel="noopener noreferrer" class={link}>IMY</a>).
</p> </p>
</section> </section>
+127
View File
@@ -0,0 +1,127 @@
---
// src/pages/tjanster.astro
// Vad Linus fotograferar, för vem, var, pris, leverans och hur man bokar + FAQ.
// Allt från src/data/business.ts och src/data/faq.ts – okända fakta visas inte.
import MainLayout from '../layouts/MainLayout.astro';
import WaveBackground from '../components/WaveBackground.astro';
import { business, basedIn, formatSek } from '../data/business';
import { faq } from '../data/faq';
import heroImg from '../assets/images/3d-scroll/img2.jpg';
const priceFrom = formatSek(business.priceFromSek);
const packages = business.packages ?? [];
const portalHost = new URL(business.portal.url).host;
---
<MainLayout
title="Tjänster och bokning – fotografering | Images by Olofsson"
description={`Fotograf Linus Olofsson i ${basedIn()}: porträtt, natur, stad, makro, norrsken och familjefester. Så bokar du via kundportalen, leverans i privat galleri och vanliga frågor.`}
path="/tjanster"
image={heroImg}
imageAlt="Veteranbil med tända strålkastare på en stadsgata i kvällsljus"
breadcrumb="Tjänster"
faq={faq}
>
<WaveBackground opacity="opacity-70" />
<div class="container mx-auto px-4 py-12 md:py-20 relative z-10 max-w-5xl">
<header class="text-center mb-16">
<h1 class="text-4xl md:text-6xl font-bold mb-6">Tjänster och bokning</h1>
<p class="text-gray-300 text-lg md:text-xl leading-relaxed max-w-3xl mx-auto">
Jag heter {business.person.name} och är fotografen bakom {business.brand}, baserad i {basedIn()}.
Här ser du vad jag fotograferar, hur en bokning går till och hur du får dina bilder.
</p>
<div class="flex flex-wrap justify-center gap-4 mt-8">
<a href={business.portal.bookingUrl} class="inline-block px-8 py-3 bg-white text-black font-bold rounded-full hover:bg-gray-200 transition">Skicka en förfrågan</a>
<a href="#vanliga-fragor" class="inline-block px-8 py-3 border border-white text-white font-bold rounded-full hover:bg-white/10 transition">Vanliga frågor</a>
</div>
</header>
<section aria-labelledby="vad" class="mb-20">
<h2 id="vad" class="text-3xl font-bold text-white mb-8">Det här fotograferar jag</h2>
<ul class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{business.genres.map((g) => (
<li id={g.id} data-trail-box class="bg-neutral-900/80 backdrop-blur-sm p-6 rounded-xl border border-white/10">
<h3 class="text-xl font-bold text-white mb-2">{g.name}</h3>
<p class="text-gray-300">{g.description}</p>
</li>
))}
</ul>
<p class="text-gray-300 mt-6">
Se exempel i min <a href="/portfolio" class="text-white underline underline-offset-4 hover:text-gray-300">portfolio</a>.
Har du något annat i tankarna? Beskriv det i din förfrågan, så återkommer jag med ett förslag.
</p>
</section>
<section aria-labelledby="var-pris" class="mb-20 grid gap-6 md:grid-cols-2">
<div data-trail-box class="bg-neutral-900/80 backdrop-blur-sm p-6 md:p-8 rounded-xl border border-white/10">
<h2 id="var-pris" class="text-2xl font-bold text-white mb-3">Var</h2>
{business.serviceArea ? (
<p class="text-gray-300">Jag utgår från {basedIn()} och tar uppdrag i {business.serviceArea}.</p>
) : (
<p class="text-gray-300">Jag är baserad i {basedIn()}. Kontakta mig så stämmer vi av om jag kan fotografera där du befinner dig.</p>
)}
</div>
<div data-trail-box class="bg-neutral-900/80 backdrop-blur-sm p-6 md:p-8 rounded-xl border border-white/10">
<h2 class="text-2xl font-bold text-white mb-3">Pris</h2>
{priceFrom ? (
<p class="text-gray-300">Fotografering från <strong class="text-white">{priceFrom}</strong>. Det slutliga priset står i offerten.</p>
) : (
<p class="text-gray-300">Priset beror på uppdraget. Kontakta mig eller skicka en förfrågan, så får du en offert för just det du vill ha fotograferat.</p>
)}
{packages.length > 0 && (
<ul class="mt-4 space-y-3">
{packages.map((p) => (
<li class="text-gray-300">
<strong class="text-white">{p.name}</strong>
{formatSek(p.priceSek) && <span> – {formatSek(p.priceSek)}</span>}
{p.includes.length > 0 && <span class="block text-sm text-gray-400">{p.includes.join(', ')}</span>}
</li>
))}
</ul>
)}
</div>
</section>
<section aria-labelledby="boka" class="mb-20">
<h2 id="boka" class="text-3xl font-bold text-white mb-8">Så går en bokning till</h2>
<ol class="space-y-4">
{business.bookingSteps.map((step, i) => (
<li class="flex gap-4 bg-neutral-900/70 backdrop-blur-sm p-5 rounded-xl border border-white/10">
<span class="shrink-0 w-10 h-10 rounded-full border border-white/30 flex items-center justify-center font-bold text-white">{i + 1}</span>
<div>
<h3 class="text-lg font-bold text-white">{step.title}</h3>
<p class="text-gray-300">{step.text}</p>
</div>
</li>
))}
</ol>
<p class="text-gray-300 mt-6">
Leverans: bilderna levereras i ett privat galleri i kundportalen
({portalHost}).{business.deliveryTime && ` Normal leveranstid är ${business.deliveryTime}.`}
</p>
<a href={business.portal.bookingUrl} class="inline-block mt-6 px-8 py-3 bg-white text-black font-bold rounded-full hover:bg-gray-200 transition">Skicka en förfrågan i kundportalen</a>
</section>
<section aria-labelledby="vanliga-fragor" class="mb-12">
<h2 id="vanliga-fragor" class="text-3xl font-bold text-white mb-8">Vanliga frågor</h2>
<div class="space-y-4">
{faq.map((item) => (
<details class="group bg-neutral-900/80 backdrop-blur-sm rounded-xl border border-white/10 p-5 open:border-white/20">
<summary class="cursor-pointer list-none flex justify-between items-center gap-4">
<h3 class="text-lg font-bold text-white">{item.question}</h3>
<span aria-hidden="true" class="text-gray-400 transition-transform group-open:rotate-45 text-2xl leading-none">+</span>
</summary>
<p class="text-gray-300 mt-3">{item.answer}</p>
</details>
))}
</div>
<p class="text-gray-300 mt-8">
Fler frågor? Mejla <a href={`mailto:${business.email}`} class="text-white underline underline-offset-4 hover:text-gray-300">{business.email}</a>
eller skriv på Instagram <a href={business.social.instagram.url} target="_blank" rel="noopener noreferrer" class="text-white underline underline-offset-4 hover:text-gray-300">{business.social.instagram.handle}</a>.
</p>
</section>
</div>
</MainLayout>