Phone, prices, packages, delivery time and years stay null until Linus confirms them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WvE3C43Uwtv2vtnoFBLDw7
184 lines
6.2 KiB
TypeScript
184 lines
6.2 KiB
TypeScript
// src/data/business.ts
|
||
// ALLA fakta om Images by Olofsson på ett ställe. Sidor, JSON-LD, llms.txt och
|
||
// sitemap läser härifrån – skriv aldrig in fakta direkt i en sida.
|
||
//
|
||
// Regel: det vi inte vet är `null`. Allt som läser filen hoppar över null-värden
|
||
// (ingen "TODO", inga påhittade siffror syns på sajten). När Linus lämnar ett
|
||
// värde: fyll i det här, så dyker det upp på /tjanster, i FAQ och i JSON-LD.
|
||
|
||
export type Genre = {
|
||
/** Kort id, används som ankare på /tjanster (#portratt osv.) */
|
||
id: string;
|
||
name: string;
|
||
description: string;
|
||
};
|
||
|
||
export type Business = {
|
||
brand: string;
|
||
url: string;
|
||
person: {
|
||
name: string;
|
||
jobTitle: string;
|
||
};
|
||
email: string;
|
||
/** Telefonnummer i format +46... – okänt */
|
||
phone: string | null;
|
||
country: { code: string; name: string };
|
||
/** Ort Linus utgår från (hans publika Flickr- och LinkedIn-profil, 2026-10-27) */
|
||
city: string | null;
|
||
/** Län/region (LinkedIn, 2026-10-27) */
|
||
region: string | null;
|
||
/** Område han tar uppdrag i (fritext, t.ex. "Stockholm med omnejd") – okänt */
|
||
serviceArea: string | null;
|
||
/** Lägsta pris i SEK för en fotografering – okänt */
|
||
priceFromSek: number | null;
|
||
/** schema.org priceRange, t.ex. "$$" eller "1500–5000 kr" – okänt */
|
||
priceRange: string | null;
|
||
/** Paket och vad som ingår – okänt */
|
||
packages: { name: string; includes: string[]; priceSek: number | null }[] | null;
|
||
/** Typisk leveranstid, fritext (t.ex. "inom två veckor") – okänt */
|
||
deliveryTime: string | null;
|
||
/** Antal år som fotograf – okänt */
|
||
yearsOfExperience: number | null;
|
||
/** Kundomdömen – inga kända */
|
||
testimonials: { name: string; text: string }[] | null;
|
||
camera: string;
|
||
lenses: string[];
|
||
editing: string;
|
||
/** Linus egen formulering: "featured by Adobe three times". Inga datum/detaljer. Jag-form för sidtext. */
|
||
recognition: string;
|
||
/** Samma fakta i tredje person (llms.txt, JSON-LD, meta descriptions). */
|
||
recognitionThirdPerson: string;
|
||
portal: {
|
||
url: string;
|
||
bookingUrl: string;
|
||
};
|
||
social: {
|
||
instagram: { handle: string; url: string };
|
||
facebook: string;
|
||
flickr: string;
|
||
lightroom: string;
|
||
linkedin: string;
|
||
github: string;
|
||
};
|
||
genres: Genre[];
|
||
bookingSteps: { title: string; text: string }[];
|
||
};
|
||
|
||
export const business: Business = {
|
||
brand: 'Images by Olofsson',
|
||
url: 'https://imagesbyolofsson.se',
|
||
person: {
|
||
name: 'Linus Olofsson',
|
||
jobTitle: 'Fotograf',
|
||
},
|
||
email: 'Admin@imagesbyolofsson.se',
|
||
phone: null,
|
||
country: { code: 'SE', name: 'Sverige' },
|
||
city: 'Örebro',
|
||
region: 'Örebro län',
|
||
serviceArea: null,
|
||
priceFromSek: null,
|
||
priceRange: null,
|
||
packages: null,
|
||
deliveryTime: null,
|
||
yearsOfExperience: null,
|
||
testimonials: null,
|
||
camera: 'Sony A7R V',
|
||
lenses: ['Sony FE 70-200mm f/4 G OSS', 'Sony FE 20mm f/1.8 G'],
|
||
editing: 'Adobe Lightroom Classic',
|
||
recognition: 'Mina bilder har lyfts fram av Adobe tre gånger.',
|
||
recognitionThirdPerson: 'Hans bilder har lyfts fram av Adobe tre gånger.',
|
||
portal: {
|
||
url: 'https://customer.imagesbyolofsson.se',
|
||
bookingUrl: 'https://customer.imagesbyolofsson.se/boka',
|
||
},
|
||
social: {
|
||
instagram: { handle: '@imagesbyolofsson', url: 'https://www.instagram.com/imagesbyolofsson/' },
|
||
facebook: 'https://www.facebook.com/imagesbyolofsson',
|
||
flickr: 'https://www.flickr.com/photos/imagesbyolofsson/',
|
||
lightroom: 'https://lightroom.adobe.com/u/linusolofsson1',
|
||
linkedin: 'https://www.linkedin.com/in/linus-olofsson-/',
|
||
github: 'https://github.com/LinusOlofsson-maker',
|
||
},
|
||
// Bara genrer som redan finns i sajtens texter och gamla sidnamn
|
||
// (/my-people, /animales-and-nature, /celebrations-with-family, /northen-lights).
|
||
genres: [
|
||
{
|
||
id: 'portratt',
|
||
name: 'Porträtt och människor',
|
||
description: 'Porträtt och ögonblick med människor – uttryck som berättar något utan ord.',
|
||
},
|
||
{
|
||
id: 'natur',
|
||
name: 'Natur och djur',
|
||
description: 'Skog, landskap och djur – naturens stillhet och de små detaljerna i den.',
|
||
},
|
||
{
|
||
id: 'stad',
|
||
name: 'Stad och arkitektur',
|
||
description: 'Gator, byggnader, strukturer och kontraster – stadens energi och dess tomma stunder.',
|
||
},
|
||
{
|
||
id: 'makro',
|
||
name: 'Makro och detaljer',
|
||
description: 'Mönster, texturer och små detaljer som de flesta går förbi.',
|
||
},
|
||
{
|
||
id: 'norrsken',
|
||
name: 'Norrsken',
|
||
description: 'Norrskenets ljus och färger över himlen.',
|
||
},
|
||
{
|
||
id: 'fest',
|
||
name: 'Fester och familjehögtider',
|
||
description: 'Bilder från fester och högtider tillsammans med familj och vänner.',
|
||
},
|
||
],
|
||
bookingSteps: [
|
||
{
|
||
title: 'Skicka en förfrågan',
|
||
text: 'Berätta vad du vill ha fotograferat, när och var – via kundportalen.',
|
||
},
|
||
{
|
||
title: 'Få en offert',
|
||
text: 'Jag återkommer med ett förslag och en offert för just ditt uppdrag.',
|
||
},
|
||
{
|
||
title: 'Bokning',
|
||
text: 'När du har godkänt offerten bokar vi in fotograferingen.',
|
||
},
|
||
{
|
||
title: 'Leverans i ett privat galleri',
|
||
text: 'Du får bilderna i ett eget, privat galleri i kundportalen.',
|
||
},
|
||
{
|
||
title: 'Originalfilerna efter betalning',
|
||
text: 'När betalningen är klar kan du ladda ner originalfilerna i full upplösning.',
|
||
},
|
||
],
|
||
};
|
||
|
||
/** Genrer som läsbar lista: "a, b, c samt d". */
|
||
export function genreList(lowercase = true): string {
|
||
const names = business.genres.map((g) => (lowercase ? g.name.toLowerCase() : g.name));
|
||
if (names.length <= 1) return names.join('');
|
||
// "samt" före sista ledet, eftersom genrenamnen själva innehåller "och".
|
||
return `${names.slice(0, -1).join(', ')} samt ${names[names.length - 1]}`;
|
||
}
|
||
|
||
/** "Sverige", eller "Ort, Sverige" när orten är känd. */
|
||
export function basedIn(): string {
|
||
return [business.city, business.country.name].filter(Boolean).join(', ');
|
||
}
|
||
|
||
/** Formaterat pris ("1 500 kr") eller null. */
|
||
export function formatSek(value: number | null): string | null {
|
||
if (value == null) return null;
|
||
return `${value.toLocaleString('sv-SE')} kr`;
|
||
}
|
||
|
||
export function absoluteUrl(path: string): string {
|
||
return new URL(path, business.url).toString();
|
||
}
|