✨ feat: enhance medialib image handling and add asset URL resolution
- Implemented `resolveApiAssetUrl` function to normalize asset URLs based on API base. - Updated `MedialibImage` component to utilize new asset URL resolution and added support for alt text and class properties. - Enhanced image loading behavior with improved width measurement and focal point handling. - Added placeholder image handling and improved accessibility with alt text. - Introduced new test script for auditing broken links in skill documentation. - Expanded seeded test content to include medialib entries and updated related tests for pagebuilder previews. - Improved global setup and teardown logging for clarity on seeded content management.
This commit is contained in:
@@ -343,6 +343,48 @@ decrementRequests() → LoadingBar disappears
|
||||
Return { data, count, buildTime }
|
||||
```
|
||||
|
||||
### `_count` endpoint
|
||||
|
||||
Der tibi-server stellt einen dedizierten `_count`-Endpoint bereit, der **nur** `{"count": N}` zurückgibt – kein Data-Transfer:
|
||||
|
||||
```
|
||||
GET /api/{collection}/_count?filter={"active":true,"category":"<id>"}
|
||||
→ {"count": 8}
|
||||
```
|
||||
|
||||
Der Endpoint wird durch den BrowserSync-Proxy korrekt geroutet (`/api` → `/api/v1/_/{namespace}`).
|
||||
|
||||
**Frontend-Aufruf:**
|
||||
|
||||
```ts
|
||||
const res = await api<{ count: number }>("machines/_count", {
|
||||
filter: { active: true, category: catId },
|
||||
})
|
||||
// res.data.count === 8
|
||||
```
|
||||
|
||||
Das ist effizienter als `count=1&limit=1`, weil keine Collection-Objekte serialisiert/übertragen werden.
|
||||
|
||||
### `select` für schlanke Queries
|
||||
|
||||
Der tibi-server unterstützt einen `select`-Parameter als Komma-Liste der gewünschten Felder. Nicht gelistete Felder werden nicht übertragen:
|
||||
|
||||
```ts
|
||||
const res = await api<MachineEntry[]>("machines", {
|
||||
filter: { active: true, category: catId },
|
||||
sort: "sortOrder",
|
||||
limit: 20,
|
||||
params: {
|
||||
lookup: "images:medialib",
|
||||
select: "name,slug,tagline,priceFrom,weight,sku,images",
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Nicht aufgeführte Felder (z.B. `description`, `specs`) entfallen – spart Bandbreite bei Listen/Grids. `_lookup` und `id` werden automatisch ergänzt.
|
||||
|
||||
**Wichtig:** `select` muss als String im `params`-Objekt übergeben werden (der `apiRequest` hängt es als Query-Parameter an). Es wird direkt an den tibi-server durchgereicht.
|
||||
|
||||
---
|
||||
|
||||
## i18n system
|
||||
@@ -389,3 +431,30 @@ Return { data, count, buildTime }
|
||||
- **Content cache is 1 hour** — `getCachedEntries` caches in memory for 1h. For admin previews, use `getDBEntries` (uncached).
|
||||
- **`$effect` alone is not SSR** — server-side rendering must trigger the same data path explicitly outside browser-only reactive effects.
|
||||
- **A rendered shell is not enough** — always verify that SSR HTML actually contains page-critical content and navigation.
|
||||
|
||||
## Cart persistence (localStorage)
|
||||
|
||||
For SSR-safe cart/inquiry persistence:
|
||||
|
||||
```ts
|
||||
let cartItems = $state<any[]>([])
|
||||
// Laden
|
||||
$effect(() => {
|
||||
try {
|
||||
if (typeof localStorage !== "undefined") {
|
||||
const saved = localStorage.getItem("cart_key")
|
||||
if (saved) cartItems = JSON.parse(saved)
|
||||
}
|
||||
} catch {}
|
||||
})
|
||||
// Speichern
|
||||
$effect(() => {
|
||||
try {
|
||||
if (typeof localStorage !== "undefined") {
|
||||
localStorage.setItem("cart_key", JSON.stringify(cartItems))
|
||||
}
|
||||
} catch {}
|
||||
})
|
||||
```
|
||||
|
||||
Immer mit `typeof localStorage !== "undefined"` für SSR-Sicherheit.
|
||||
|
||||
Reference in New Issue
Block a user