Files
imagesbyolofsson-se/src/data/business.ts
T
2026-10-27 23:14:55 +01:00

184 lines
6.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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();
}