No services: /tjanster, booking steps, offers, galleries and downloads removed everywhere
Linus 2026-11-06: he offers no services; the site has posters and collaborations only. /tjanster went live with the move to Cleura (it came with the SEO pull request #1) and was redirected to the start page in Caddy the same morning. - tjanster.astro deleted; Tjänster out of the menu and the 404 page. - Start page: "Vill du boka en fotografering?" -> "Vill du ha en bild på väggen?" (Se posters); "Så bokar du" -> "Posters och samarbeten"; description without "Boka via kundportalen". - Portfolio intro points to the posters; privacy page: orders of posters and collaborations instead of bookings. - JSON-LD: Organization instead of ProfessionalService, no ReserveAction, offer catalog, price range or service area. - llms.txt: no prices, booking, booking steps, services page or booking FAQ; faq.ts keeps only the type. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
d841cf98b5
commit
c760e11c4c
@@ -12,7 +12,7 @@ export interface Props {
|
|||||||
description: string;
|
description: string;
|
||||||
path?: string;
|
path?: string;
|
||||||
pageType?: 'WebPage' | 'AboutPage' | 'ContactPage' | 'CollectionPage';
|
pageType?: 'WebPage' | 'AboutPage' | 'ContactPage' | 'CollectionPage';
|
||||||
/** Namn i brödsmulan för undersidor, t.ex. "Tjänster". */
|
/** Namn i brödsmulan för undersidor, t.ex. "Portfolio". */
|
||||||
breadcrumb?: string;
|
breadcrumb?: string;
|
||||||
faq?: FaqItem[];
|
faq?: FaqItem[];
|
||||||
/** Absolut URL till sidans huvudbild (og:image). */
|
/** Absolut URL till sidans huvudbild (og:image). */
|
||||||
@@ -80,7 +80,7 @@ const graph: Record<string, unknown>[] = [
|
|||||||
sameAs: [business.social.linkedin, business.social.lightroom],
|
sameAs: [business.social.linkedin, business.social.lightroom],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'@type': 'ProfessionalService',
|
'@type': 'Organization',
|
||||||
'@id': ids.business,
|
'@id': ids.business,
|
||||||
name: business.brand,
|
name: business.brand,
|
||||||
url: `${site}/`,
|
url: `${site}/`,
|
||||||
@@ -89,31 +89,9 @@ const graph: Record<string, unknown>[] = [
|
|||||||
telephone: business.phone,
|
telephone: business.phone,
|
||||||
image: imageUrl,
|
image: imageUrl,
|
||||||
address,
|
address,
|
||||||
areaServed: business.serviceArea,
|
|
||||||
priceRange: business.priceRange,
|
|
||||||
founder: { '@id': ids.person },
|
founder: { '@id': ids.person },
|
||||||
employee: { '@id': ids.person },
|
employee: { '@id': ids.person },
|
||||||
sameAs: [business.social.instagram.url, business.social.facebook, business.social.flickr, business.social.lightroom],
|
sameAs: [business.social.instagram.url, business.social.facebook, business.social.flickr, business.social.lightroom],
|
||||||
potentialAction: {
|
|
||||||
'@type': 'ReserveAction',
|
|
||||||
name: 'Skicka en bokningsförfrågan',
|
|
||||||
target: business.portal.bookingUrl,
|
|
||||||
},
|
|
||||||
hasOfferCatalog: {
|
|
||||||
'@type': 'OfferCatalog',
|
|
||||||
name: 'Fotografering',
|
|
||||||
itemListElement: business.genres.map((g) => ({
|
|
||||||
'@type': 'Offer',
|
|
||||||
priceCurrency: business.priceFromSek != null ? 'SEK' : null,
|
|
||||||
price: business.priceFromSek,
|
|
||||||
itemOffered: {
|
|
||||||
'@type': 'Service',
|
|
||||||
name: g.name,
|
|
||||||
description: g.description,
|
|
||||||
provider: { '@id': ids.business },
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
+2
-60
@@ -1,63 +1,5 @@
|
|||||||
// src/data/faq.ts
|
// src/data/faq.ts
|
||||||
// Vanliga frågor för /tjanster. Samma text används på sidan och i FAQPage-JSON-LD.
|
// Typ för vanliga frågor (FAQPage-JSON-LD). Frågorna om bokning, offert och gallerier togs bort 2026-11-06:
|
||||||
// Svaren byggs ENBART av fakta i business.ts. Okända fakta (null) ger ett
|
// Linus erbjuder inga tjänster, bara posters och samarbeten.
|
||||||
// "kontakta mig"-svar i stället för en gissning.
|
|
||||||
import { business, basedIn, formatSek, genreList } from './business';
|
|
||||||
|
|
||||||
export type FaqItem = { question: string; answer: string };
|
export type FaqItem = { question: string; answer: string };
|
||||||
|
|
||||||
function areaAnswer(): string {
|
|
||||||
if (business.serviceArea) {
|
|
||||||
return `Jag utgår från ${basedIn()} och tar uppdrag i ${business.serviceArea}. Hör av dig om du är osäker på om jag kan komma till dig.`;
|
|
||||||
}
|
|
||||||
return `Jag är baserad i ${basedIn()}. Kontakta mig så stämmer vi av om jag kan fotografera där du befinner dig.`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function priceAnswer(): string {
|
|
||||||
const from = formatSek(business.priceFromSek);
|
|
||||||
if (from) {
|
|
||||||
return `En fotografering kostar från ${from}. Det slutliga priset beror på uppdraget och står i offerten du får efter din förfrågan.`;
|
|
||||||
}
|
|
||||||
return 'Priset beror på uppdraget. Kontakta mig eller skicka en förfrågan i kundportalen, så får du en offert för just det du vill ha fotograferat.';
|
|
||||||
}
|
|
||||||
|
|
||||||
function deliveryAnswer(): string {
|
|
||||||
const base = 'Du får bilderna i ett privat galleri i kundportalen. När betalningen är klar kan du ladda ner originalfilerna i full upplösning.';
|
|
||||||
if (business.deliveryTime) return `${base} Normal leveranstid är ${business.deliveryTime}.`;
|
|
||||||
return base;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const faq: FaqItem[] = [
|
|
||||||
{
|
|
||||||
question: 'Vad fotograferar du?',
|
|
||||||
answer: `Jag fotograferar ${genreList()}.`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: 'Var finns du och var kan du fotografera?',
|
|
||||||
answer: areaAnswer(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: 'Vad kostar en fotografering?',
|
|
||||||
answer: priceAnswer(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: 'Hur bokar jag en fotografering?',
|
|
||||||
answer: `Skicka en förfrågan i kundportalen (${business.portal.bookingUrl}). Jag återkommer med en offert, och när du har godkänt den bokar vi in fotograferingen.`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: 'Hur får jag mina bilder?',
|
|
||||||
answer: deliveryAnswer(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: 'Vilken utrustning använder du?',
|
|
||||||
answer: `Jag fotograferar med en ${business.camera} och redigerar i ${business.editing}.`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: 'Har dina bilder uppmärksammats?',
|
|
||||||
answer: business.recognition,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: 'Hur kontaktar jag dig?',
|
|
||||||
answer: `Mejla ${business.email} eller skicka ett meddelande på Instagram (${business.social.instagram.handle}).`,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export interface Props {
|
|||||||
title: string;
|
title: string;
|
||||||
/** Unik svensk meta description, ca 120–160 tecken. */
|
/** Unik svensk meta description, ca 120–160 tecken. */
|
||||||
description: string;
|
description: string;
|
||||||
/** Kanonisk sökväg, t.ex. "/tjanster". Utelämnas = härleds från URL:en. */
|
/** Kanonisk sökväg, t.ex. "/portfolio". Utelämnas = härleds från URL:en. */
|
||||||
path?: string;
|
path?: string;
|
||||||
image?: ImageMetadata;
|
image?: ImageMetadata;
|
||||||
imageAlt?: string;
|
imageAlt?: string;
|
||||||
@@ -46,7 +46,6 @@ const ogHeight = Number(og.attributes.height) || undefined;
|
|||||||
const nav = [
|
const nav = [
|
||||||
{ href: '/portfolio', label: 'Portfolio' },
|
{ href: '/portfolio', label: 'Portfolio' },
|
||||||
{ href: '/posters', label: 'Posters' },
|
{ href: '/posters', label: 'Posters' },
|
||||||
{ href: '/tjanster', label: 'Tjänster' },
|
|
||||||
{ href: '/about', label: 'Om mig' },
|
{ href: '/about', label: 'Om mig' },
|
||||||
{ href: '/contact', label: 'Kontakt' },
|
{ href: '/contact', label: 'Kontakt' },
|
||||||
];
|
];
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// src/lib/url.ts
|
// src/lib/url.ts
|
||||||
// Gör om en byggsökväg till kanonisk form: "/", "/about", "/tjanster".
|
// Gör om en byggsökväg till kanonisk form: "/", "/about", "/portfolio".
|
||||||
// Klarar både build.format "file" (/about.html) och "directory" (/about/).
|
// Klarar både build.format "file" (/about.html) och "directory" (/about/).
|
||||||
export function normalizePath(p: string): string {
|
export function normalizePath(p: string): string {
|
||||||
let out = p.replace(/\/index\.html$/, '/').replace(/\.html$/, '');
|
let out = p.replace(/\/index\.html$/, '/').replace(/\.html$/, '');
|
||||||
|
|||||||
+1
-2
@@ -7,14 +7,13 @@ const links = [
|
|||||||
{ href: '/', label: 'Startsidan' },
|
{ href: '/', label: 'Startsidan' },
|
||||||
{ href: '/portfolio', label: 'Portfolio' },
|
{ href: '/portfolio', label: 'Portfolio' },
|
||||||
{ href: '/posters', label: 'Posters' },
|
{ href: '/posters', label: 'Posters' },
|
||||||
{ href: '/tjanster', label: 'Tjänster och bokning' },
|
|
||||||
{ href: '/contact', label: 'Kontakt' },
|
{ href: '/contact', label: 'Kontakt' },
|
||||||
];
|
];
|
||||||
---
|
---
|
||||||
|
|
||||||
<MainLayout
|
<MainLayout
|
||||||
title="Sidan hittades inte | Images by Olofsson"
|
title="Sidan hittades inte | Images by Olofsson"
|
||||||
description="Sidan du letade efter finns inte. Gå till startsidan, portfolion eller tjänsterna hos fotograf Linus Olofsson."
|
description="Sidan du letade efter finns inte. Gå till startsidan, portfolion eller posters av fotograf Linus Olofsson."
|
||||||
noindex
|
noindex
|
||||||
>
|
>
|
||||||
<WaveBackground opacity="opacity-60" />
|
<WaveBackground opacity="opacity-60" />
|
||||||
|
|||||||
+12
-16
@@ -8,7 +8,7 @@ import { business, basedIn, genreList } from '../data/business';
|
|||||||
|
|
||||||
<MainLayout
|
<MainLayout
|
||||||
title="Images by Olofsson – fotograf Linus Olofsson i Sverige"
|
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.`}
|
description={`Fotograf Linus Olofsson (Images by Olofsson) i ${basedIn()}: porträtt, natur och djur, stad, makro, norrsken och familjefester. Fotografierna finns som posters.`}
|
||||||
path="/"
|
path="/"
|
||||||
>
|
>
|
||||||
|
|
||||||
@@ -86,16 +86,16 @@ import { business, basedIn, genreList } from '../data/business';
|
|||||||
</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">Vill du boka en fotografering?</h2>
|
<h2 class="text-3xl md:text-4xl text-white font-bold mb-6">Vill du ha en bild på väggen?</h2>
|
||||||
<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">
|
<a href="/posters" class="inline-block px-8 py-3 bg-white text-black font-bold rounded-full hover:bg-gray-200 transition transform hover:scale-105">
|
||||||
Tjänster och bokning
|
Se posters
|
||||||
</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. -->
|
<!-- Fakta om vem, vad och var: 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">
|
<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="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">
|
<div class="space-y-5 text-gray-300 text-lg leading-relaxed">
|
||||||
@@ -116,18 +116,14 @@ import { business, basedIn, genreList } from '../data/business';
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="space-y-5">
|
<div class="space-y-5">
|
||||||
<h2 class="text-3xl md:text-4xl font-bold text-white">Så bokar du</h2>
|
<h2 class="text-3xl md:text-4xl font-bold text-white">Posters och samarbeten</h2>
|
||||||
<ol class="space-y-4 text-gray-300">
|
<p class="text-gray-300 text-lg leading-relaxed">
|
||||||
{business.bookingSteps.map((step, i) => (
|
Fotografierna finns som posters: välj motiv, storlek och material. Vill du skapa något tillsammans,
|
||||||
<li class="flex gap-4">
|
eller synas genom reklam eller sponsring, hör av dig om ett samarbete.
|
||||||
<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>
|
</p>
|
||||||
<span><strong class="text-white">{step.title}.</strong> {step.text}</span>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ol>
|
|
||||||
<div class="flex flex-wrap gap-4 pt-2">
|
<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="/posters" class="inline-block px-6 py-3 bg-white text-black font-bold rounded-full hover:bg-gray-200 transition">Se posters</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>
|
<a href="/contact" class="inline-block px-6 py-3 border border-white text-white font-bold rounded-full hover:bg-white/10 transition">Samarbeten</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+1
-13
@@ -2,15 +2,13 @@
|
|||||||
// Byggs från src/data/business.ts så att fakta bara finns på ett ställe.
|
// Byggs från src/data/business.ts så att fakta bara finns på ett ställe.
|
||||||
// Okända fakta (null) skrivs som "lämnas på förfrågan", aldrig som gissningar.
|
// Okända fakta (null) skrivs som "lämnas på förfrågan", aldrig som gissningar.
|
||||||
import type { APIRoute } from 'astro';
|
import type { APIRoute } from 'astro';
|
||||||
import { business, basedIn, formatSek, genreList } from '../data/business';
|
import { business, basedIn, genreList } from '../data/business';
|
||||||
import { faq } from '../data/faq';
|
|
||||||
|
|
||||||
export const prerender = true;
|
export const prerender = true;
|
||||||
|
|
||||||
export const GET: APIRoute = ({ site }) => {
|
export const GET: APIRoute = ({ site }) => {
|
||||||
const base = site ?? new URL(business.url);
|
const base = site ?? new URL(business.url);
|
||||||
const url = (p: string) => new URL(p, base).toString();
|
const url = (p: string) => new URL(p, base).toString();
|
||||||
const price = formatSek(business.priceFromSek);
|
|
||||||
|
|
||||||
const lines: (string | null)[] = [
|
const lines: (string | null)[] = [
|
||||||
`# ${business.brand}`,
|
`# ${business.brand}`,
|
||||||
@@ -22,31 +20,21 @@ export const GET: APIRoute = ({ site }) => {
|
|||||||
`- Fotograf: ${business.person.name}`,
|
`- Fotograf: ${business.person.name}`,
|
||||||
`- Namn/varumärke: ${business.brand}`,
|
`- Namn/varumärke: ${business.brand}`,
|
||||||
`- Baserad i: ${basedIn()}`,
|
`- Baserad i: ${basedIn()}`,
|
||||||
business.serviceArea ? `- Tar uppdrag i: ${business.serviceArea}` : '- Upptagningsområde: stäms av vid förfrågan',
|
|
||||||
price ? `- Pris från: ${price}` : '- Priser: lämnas som offert efter förfrågan',
|
|
||||||
business.deliveryTime ? `- Leveranstid: ${business.deliveryTime}` : null,
|
|
||||||
business.phone ? `- Telefon: ${business.phone}` : null,
|
business.phone ? `- Telefon: ${business.phone}` : null,
|
||||||
`- E-post: ${business.email}`,
|
`- E-post: ${business.email}`,
|
||||||
`- Instagram: ${business.social.instagram.handle} (${business.social.instagram.url})`,
|
`- Instagram: ${business.social.instagram.handle} (${business.social.instagram.url})`,
|
||||||
`- Facebook: ${business.social.facebook}`,
|
`- Facebook: ${business.social.facebook}`,
|
||||||
`- Kamera: ${business.camera}`,
|
`- Kamera: ${business.camera}`,
|
||||||
`- Redigering: ${business.editing}`,
|
`- Redigering: ${business.editing}`,
|
||||||
`- Bokning: ${business.portal.bookingUrl}`,
|
|
||||||
`- Bokningsgång: ${business.bookingSteps.map((s) => s.title.toLowerCase()).join(' → ')}`,
|
|
||||||
'',
|
'',
|
||||||
'## Sidor',
|
'## Sidor',
|
||||||
'',
|
'',
|
||||||
`- [Startsida](${url('/')}): vem ${business.person.name} är och vad han fotograferar`,
|
`- [Startsida](${url('/')}): vem ${business.person.name} är och vad han fotograferar`,
|
||||||
`- [Tjänster och vanliga frågor](${url('/tjanster')}): vad du kan boka, hur bokningen går till och svar på vanliga frågor`,
|
|
||||||
`- [Portfolio](${url('/portfolio')}): urval av fotografier`,
|
`- [Portfolio](${url('/portfolio')}): urval av fotografier`,
|
||||||
`- [Om mig](${url('/about')}): ${business.person.name}, bakgrund och utrustning`,
|
`- [Om mig](${url('/about')}): ${business.person.name}, bakgrund och utrustning`,
|
||||||
`- [Posters](${url('/posters')}): fotografier som posters, välj storlek och material`,
|
`- [Posters](${url('/posters')}): fotografier som posters, välj storlek och material`,
|
||||||
`- [Kontakt och samarbeten](${url('/contact')}): samarbeten, reklam och sponsring`,
|
`- [Kontakt och samarbeten](${url('/contact')}): samarbeten, reklam och sponsring`,
|
||||||
'',
|
'',
|
||||||
'## Vanliga frågor',
|
|
||||||
'',
|
|
||||||
...faq.map((f) => `- ${f.question} ${f.answer}`),
|
|
||||||
'',
|
|
||||||
'## Profiler',
|
'## Profiler',
|
||||||
'',
|
'',
|
||||||
`- [Instagram](${business.social.instagram.url})`,
|
`- [Instagram](${business.social.instagram.url})`,
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ const uniqueMonths = [...new Map(allMonths.map(item => [item.name, item])).value
|
|||||||
<div class="text-center mb-12">
|
<div class="text-center mb-12">
|
||||||
<h1 class="text-4xl md:text-6xl font-bold mb-4">Portfolio</h1>
|
<h1 class="text-4xl md:text-6xl font-bold mb-4">Portfolio</h1>
|
||||||
<p class="text-gray-300 max-w-2xl mx-auto">Ett urval av mina bilder i olika stilar – {genreList()}.
|
<p class="text-gray-300 max-w-2xl mx-auto">Ett urval av mina bilder i olika stilar – {genreList()}.
|
||||||
Vill du boka en fotografering? Läs om <a href="/tjanster" class="text-white underline underline-offset-4 hover:text-gray-300">tjänster och bokning</a>.</p>
|
Vill du ha en bild på väggen? Se <a href="/posters" class="text-white underline underline-offset-4 hover:text-gray-300">posters</a>.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col items-center gap-6 mb-12">
|
<div class="flex flex-col items-center gap-6 mb-12">
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const link = 'text-white underline hover:text-gray-300';
|
|||||||
<section class="space-y-3">
|
<section class="space-y-3">
|
||||||
<h2 class="text-2xl font-bold text-white">Den här webbplatsen</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>Det finns inga användarkonton och inga kontaktformulär på den här webbplatsen. Bokningar görs i den separata kundportalen.</li>
|
<li>Det finns inga användarkonton och inga kontaktformulär på den här webbplatsen. Beställningar av posters och samarbeten sköts i den separata kundportalen.</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>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>
|
<li>
|
||||||
Webbplatsen levereras via Cloudflare, som behandlar tekniska uppgifter som din IP-adress för att leverera
|
Webbplatsen levereras via Cloudflare, som behandlar tekniska uppgifter som din IP-adress för att leverera
|
||||||
|
|||||||
@@ -1,127 +0,0 @@
|
|||||||
---
|
|
||||||
// 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>
|
|
||||||
Reference in New Issue
Block a user