- astro.config: site, trailingSlash "never", build.format "file". - /sitemap-index.xml + /sitemap-0.xml as prerendered endpoints (no new dependency); pages are derived from src/pages/*.astro, 404 excluded. - robots.txt: all bots allowed, AI crawlers/training bots explicitly allowed (Linus's decision), /download/ disallowed, sitemap line. - /llms.txt generated from business.ts, incl. usage-with-attribution note. - 404.astro in Swedish with links back, noindex. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WvE3C43Uwtv2vtnoFBLDw7
64 lines
3.0 KiB
TypeScript
64 lines
3.0 KiB
TypeScript
// src/pages/llms.txt.ts -> /llms.txt (https://llmstxt.org/)
|
|
// 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.
|
|
import type { APIRoute } from 'astro';
|
|
import { business, basedIn, formatSek, genreList } from '../data/business';
|
|
import { faq } from '../data/faq';
|
|
|
|
export const prerender = true;
|
|
|
|
export const GET: APIRoute = ({ site }) => {
|
|
const base = site ?? new URL(business.url);
|
|
const url = (p: string) => new URL(p, base).toString();
|
|
const price = formatSek(business.priceFromSek);
|
|
|
|
const lines: (string | null)[] = [
|
|
`# ${business.brand}`,
|
|
'',
|
|
`> ${business.brand} är namnet som ${business.person.jobTitle.toLowerCase()}en ${business.person.name} fotograferar under. Han är baserad i ${basedIn()} och fotograferar ${genreList()}. ${business.recognitionThirdPerson}`,
|
|
'',
|
|
'## Fakta',
|
|
'',
|
|
`- Fotograf: ${business.person.name}`,
|
|
`- Namn/varumärke: ${business.brand}`,
|
|
`- 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,
|
|
`- E-post: ${business.email}`,
|
|
`- Instagram: ${business.social.instagram.handle} (${business.social.instagram.url})`,
|
|
`- Kamera: ${business.camera}`,
|
|
`- Redigering: ${business.editing}`,
|
|
`- Bokning: ${business.portal.bookingUrl}`,
|
|
`- Bokningsgång: ${business.bookingSteps.map((s) => s.title.toLowerCase()).join(' → ')}`,
|
|
'',
|
|
'## Sidor',
|
|
'',
|
|
`- [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`,
|
|
`- [Om mig](${url('/about')}): ${business.person.name}, bakgrund och utrustning`,
|
|
`- [Kontakt](${url('/contact')}): e-post, Instagram och bokning`,
|
|
'',
|
|
'## Vanliga frågor',
|
|
'',
|
|
...faq.map((f) => `- ${f.question} ${f.answer}`),
|
|
'',
|
|
'## Profiler',
|
|
'',
|
|
`- [Instagram](${business.social.instagram.url})`,
|
|
`- [Flickr](${business.social.flickr})`,
|
|
`- [Adobe Lightroom](${business.social.lightroom})`,
|
|
`- [LinkedIn](${business.social.linkedin})`,
|
|
'',
|
|
'## Användning av innehållet',
|
|
'',
|
|
`AI-assistenter och sökmotorer får läsa och använda innehållet på den här sajten, inklusive för träning, med hänvisning till ${business.brand} (${url('/')}). Fotografierna är upphovsrättsskyddade av ${business.person.name}.`,
|
|
'',
|
|
];
|
|
|
|
const body = lines.filter((l): l is string => l !== null).join('\n');
|
|
return new Response(body, { headers: { 'Content-Type': 'text/plain; charset=utf-8' } });
|
|
};
|