'integer', 'overlay_strength' => 'integer', 'active' => 'boolean', ]; protected static function booted(): void { $flushCache = static function (self $page): void { $story = $page->relationLoaded('story') ? $page->story : $page->story()->with('world')->first(); if (! ($story instanceof WorldWebStory)) { return; } Cache::forget('web_story:' . $story->slug); Cache::forget('web_story_index'); if ($story->world?->slug) { Cache::forget('world:' . $story->world->slug . ':web_story'); } }; static::saved($flushCache); static::deleted($flushCache); static::restored($flushCache); } public function story(): BelongsTo { return $this->belongsTo(WorldWebStory::class, 'story_id'); } public function artwork(): BelongsTo { return $this->belongsTo(Artwork::class); } public function scopeOrderedPages(Builder $query): Builder { return $query->orderBy('position')->orderBy('id'); } public function backgroundUrl(): ?string { return $this->assetUrl($this->background_mobile_path ?: $this->background_path); } public function desktopBackgroundUrl(): ?string { return $this->assetUrl($this->background_path ?: $this->background_mobile_path); } private function assetUrl(?string $path): ?string { $resolved = trim((string) $path); if ($resolved === '') { return null; } if (str_starts_with($resolved, 'http://') || str_starts_with($resolved, 'https://')) { return $resolved; } return rtrim((string) config('cdn.files_url', 'https://files.skinbase.org'), '/') . '/' . ltrim($resolved, '/'); } }