@stack-mode/site-manager-kit 1.44.0 → 1.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +618 -606
- package/audit/ts-hooks.mjs +68 -68
- package/audit/wiring-audit.d.mts +37 -37
- package/audit/wiring-audit.mjs +604 -604
- package/bin/site-manager-kit.mjs +10 -10
- package/package.json +73 -72
- package/src/announcements.ts +13 -13
- package/src/attribution-fields.ts +52 -52
- package/src/attribution.tsx +47 -47
- package/src/blog.ts +122 -122
- package/src/chat-route.ts +136 -136
- package/src/chat-types.ts +76 -76
- package/src/client.ts +116 -116
- package/src/config.ts +78 -78
- package/src/copy-keys-route.ts +21 -21
- package/src/copy-keys.ts +77 -77
- package/src/data.ts +189 -189
- package/src/downloads.ts +7 -7
- package/src/faq.ts +21 -21
- package/src/floor-plans.ts +45 -45
- package/src/form-guard.tsx +37 -37
- package/src/form-types.ts +13 -13
- package/src/forms.ts +76 -76
- package/src/glossary.ts +19 -19
- package/src/health-route.ts +34 -34
- package/src/index.ts +36 -36
- package/src/indexnow.ts +40 -40
- package/src/listings.ts +38 -38
- package/src/llms-route.ts +45 -0
- package/src/metadata.ts +55 -55
- package/src/not-found-reporter.tsx +16 -16
- package/src/not-found.ts +53 -53
- package/src/payment.ts +70 -70
- package/src/phone-input.tsx +26 -26
- package/src/phone.ts +37 -37
- package/src/preview-route.ts +48 -48
- package/src/preview.ts +94 -94
- package/src/residents.ts +23 -23
- package/src/revalidate-route.ts +34 -34
- package/src/robots.ts +5 -1
- package/src/rss-route.ts +26 -26
- package/src/services.ts +52 -52
- package/src/site-chat-panel.tsx +537 -537
- package/src/site-chat.tsx +26 -26
- package/src/sitemap.ts +26 -26
- package/src/structured-data.tsx +207 -207
- package/src/types.ts +581 -580
- package/src/version.ts +1 -1
- package/src/visual-accents.ts +126 -126
- package/src/visual-bridge-client.tsx +1070 -1070
- package/src/visual-bridge.tsx +30 -30
- package/src/visual-clicks.ts +13 -13
- package/src/visual-lists.ts +37 -37
- package/src/visual-match.ts +77 -77
- package/src/visual-messages.ts +160 -160
- package/src/visual-mode.ts +18 -18
- package/src/visual-preview.ts +69 -69
- package/src/visual-tags.ts +90 -90
- package/src/visual.ts +59 -59
- package/src/waitlist-form.ts +39 -39
- package/src/waitlist.ts +48 -48
package/src/services.ts
CHANGED
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
import type { Service, Site } from "./types";
|
|
2
|
-
|
|
3
|
-
type Json = Record<string, unknown>;
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* schema.org `Service` structured data for a service page, with the business as its provider. A price becomes an
|
|
7
|
-
* `Offer` (a range as a `PriceSpecification` with min and max); "call for pricing" and no price add no offer, so
|
|
8
|
-
* search engines are never told a price the business didn't give. Amounts stay decimal strings. Prices are in USD,
|
|
9
|
-
* the only currency Site Manager's sites use.
|
|
10
|
-
*/
|
|
11
|
-
export function serviceJsonLd(service: Service, site: Pick<Site, "name" | "business" | "websiteUrl">, url: string): Json {
|
|
12
|
-
const b = site.business;
|
|
13
|
-
const a = b.address;
|
|
14
|
-
const provider: Json = {
|
|
15
|
-
"@type": "LocalBusiness",
|
|
16
|
-
name: b.displayName || site.name,
|
|
17
|
-
...(site.websiteUrl ? { url: site.websiteUrl } : {}),
|
|
18
|
-
...(b.phone ? { telephone: b.phone } : {}),
|
|
19
|
-
...(a.line1 || a.city
|
|
20
|
-
? {
|
|
21
|
-
address: {
|
|
22
|
-
"@type": "PostalAddress",
|
|
23
|
-
...(a.line1 ? { streetAddress: [a.line1, a.line2].filter(Boolean).join(", ") } : {}),
|
|
24
|
-
...(a.city ? { addressLocality: a.city } : {}),
|
|
25
|
-
...(a.region ? { addressRegion: a.region } : {}),
|
|
26
|
-
...(a.postalCode ? { postalCode: a.postalCode } : {}),
|
|
27
|
-
...(a.country ? { addressCountry: a.country } : {}),
|
|
28
|
-
},
|
|
29
|
-
}
|
|
30
|
-
: {}),
|
|
31
|
-
};
|
|
32
|
-
const p = service.price;
|
|
33
|
-
let offers: Json | null = null;
|
|
34
|
-
if (p.kind === "fixed" && p.from) offers = { "@type": "Offer", priceCurrency: "USD", price: p.from };
|
|
35
|
-
else if (p.kind === "starting_at" && p.from) {
|
|
36
|
-
offers = { "@type": "Offer", priceCurrency: "USD", price: p.from, priceSpecification: { "@type": "PriceSpecification", priceCurrency: "USD", minPrice: p.from } };
|
|
37
|
-
} else if (p.kind === "range" && p.from && p.to) {
|
|
38
|
-
offers = { "@type": "Offer", priceCurrency: "USD", priceSpecification: { "@type": "PriceSpecification", priceCurrency: "USD", minPrice: p.from, maxPrice: p.to } };
|
|
39
|
-
}
|
|
40
|
-
return {
|
|
41
|
-
"@context": "https://schema.org",
|
|
42
|
-
"@type": "Service",
|
|
43
|
-
name: service.name,
|
|
44
|
-
url,
|
|
45
|
-
...(service.summary ? { description: service.summary } : {}),
|
|
46
|
-
...(service.category ? { serviceType: service.category } : {}),
|
|
47
|
-
...(service.photos.length ? { image: service.photos.map((ph) => ph.url) } : {}),
|
|
48
|
-
provider,
|
|
49
|
-
...(a.city ? { areaServed: a.region ? `${a.city}, ${a.region}` : a.city } : {}),
|
|
50
|
-
...(offers ? { offers } : {}),
|
|
51
|
-
};
|
|
52
|
-
}
|
|
1
|
+
import type { Service, Site } from "./types";
|
|
2
|
+
|
|
3
|
+
type Json = Record<string, unknown>;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* schema.org `Service` structured data for a service page, with the business as its provider. A price becomes an
|
|
7
|
+
* `Offer` (a range as a `PriceSpecification` with min and max); "call for pricing" and no price add no offer, so
|
|
8
|
+
* search engines are never told a price the business didn't give. Amounts stay decimal strings. Prices are in USD,
|
|
9
|
+
* the only currency Site Manager's sites use.
|
|
10
|
+
*/
|
|
11
|
+
export function serviceJsonLd(service: Service, site: Pick<Site, "name" | "business" | "websiteUrl">, url: string): Json {
|
|
12
|
+
const b = site.business;
|
|
13
|
+
const a = b.address;
|
|
14
|
+
const provider: Json = {
|
|
15
|
+
"@type": "LocalBusiness",
|
|
16
|
+
name: b.displayName || site.name,
|
|
17
|
+
...(site.websiteUrl ? { url: site.websiteUrl } : {}),
|
|
18
|
+
...(b.phone ? { telephone: b.phone } : {}),
|
|
19
|
+
...(a.line1 || a.city
|
|
20
|
+
? {
|
|
21
|
+
address: {
|
|
22
|
+
"@type": "PostalAddress",
|
|
23
|
+
...(a.line1 ? { streetAddress: [a.line1, a.line2].filter(Boolean).join(", ") } : {}),
|
|
24
|
+
...(a.city ? { addressLocality: a.city } : {}),
|
|
25
|
+
...(a.region ? { addressRegion: a.region } : {}),
|
|
26
|
+
...(a.postalCode ? { postalCode: a.postalCode } : {}),
|
|
27
|
+
...(a.country ? { addressCountry: a.country } : {}),
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
: {}),
|
|
31
|
+
};
|
|
32
|
+
const p = service.price;
|
|
33
|
+
let offers: Json | null = null;
|
|
34
|
+
if (p.kind === "fixed" && p.from) offers = { "@type": "Offer", priceCurrency: "USD", price: p.from };
|
|
35
|
+
else if (p.kind === "starting_at" && p.from) {
|
|
36
|
+
offers = { "@type": "Offer", priceCurrency: "USD", price: p.from, priceSpecification: { "@type": "PriceSpecification", priceCurrency: "USD", minPrice: p.from } };
|
|
37
|
+
} else if (p.kind === "range" && p.from && p.to) {
|
|
38
|
+
offers = { "@type": "Offer", priceCurrency: "USD", priceSpecification: { "@type": "PriceSpecification", priceCurrency: "USD", minPrice: p.from, maxPrice: p.to } };
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
"@context": "https://schema.org",
|
|
42
|
+
"@type": "Service",
|
|
43
|
+
name: service.name,
|
|
44
|
+
url,
|
|
45
|
+
...(service.summary ? { description: service.summary } : {}),
|
|
46
|
+
...(service.category ? { serviceType: service.category } : {}),
|
|
47
|
+
...(service.photos.length ? { image: service.photos.map((ph) => ph.url) } : {}),
|
|
48
|
+
provider,
|
|
49
|
+
...(a.city ? { areaServed: a.region ? `${a.city}, ${a.region}` : a.city } : {}),
|
|
50
|
+
...(offers ? { offers } : {}),
|
|
51
|
+
};
|
|
52
|
+
}
|