feat(seo): facts in src/data/business.ts, SEO + JSON-LD components in layout
- business.ts: single source of truth; unknown facts (city, area, prices, packages, phone, delivery time, experience, testimonials) are null and are skipped everywhere. faq.ts builds answers only from known facts. - portfolio-meta.ts: data hook for real per-image alt texts. - SEO.astro: title, description, canonical, Open Graph, Twitter, og:image (EXIF-free JPG via getImage, absolute URL). - SchemaOrg.astro: @graph with WebSite, Person, ProfessionalService (sameAs, ReserveAction to the customer portal, offer catalog without prices), WebPage, optional FAQPage and BreadcrumbList. - MainLayout: lang=sv, Swedish nav (adds Tjänster), consent banner and footer in Swedish, lyxlimo/karleksguiden line removed, info@ address. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WvE3C43Uwtv2vtnoFBLDw7
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
ce5676f552
commit
30e385ec7f
@@ -0,0 +1,63 @@
|
||||
// src/data/faq.ts
|
||||
// Vanliga frågor för /tjanster. Samma text används på sidan och i FAQPage-JSON-LD.
|
||||
// Svaren byggs ENBART av fakta i business.ts. Okända fakta (null) ger ett
|
||||
// "kontakta mig"-svar i stället för en gissning.
|
||||
import { business, basedIn, formatSek, genreList } from './business';
|
||||
|
||||
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}).`,
|
||||
},
|
||||
];
|
||||
Reference in New Issue
Block a user