Skip to content

Commit 502f65a

Browse files
committed
fix: Serve icons sprite from Panel route
1 parent 4502817 commit 502f65a

5 files changed

Lines changed: 75 additions & 51 deletions

File tree

panel/src/components/Misc/Icon.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { mount as vueMount } from "@vue/test-utils";
33
import { hasEmoji } from "@/helpers/string.js";
44
import Icon from "./Icon.vue";
55

6-
const sprite = "/media/panel/1234/img/icons.svg";
6+
const sprite = "/panel/assets/1234/icons.svg";
77

88
/**
99
* Custom mount which injects $helper and $panel stubs

src/Panel/Assets.php

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -185,20 +185,11 @@ public function favicons(): array
185185
*/
186186
public function icons(): string
187187
{
188-
$path = '/panel/' . $this->kirby->versionHash() . '/img/icons.svg';
188+
$version = $this->isDev === true
189+
? F::modified($this->iconsRoot())
190+
: $this->kirby->versionHash();
189191

190-
if ($this->isDev === true) {
191-
$source = $this->iconsRoot();
192-
$target = $this->kirby->root('media') . $path;
193-
$modified = F::modified($source);
194-
195-
if (F::modified($target) !== $modified) {
196-
F::copy($source, $target, true);
197-
touch($target, $modified);
198-
}
199-
}
200-
201-
return $this->kirby->url('media') . $path;
192+
return $this->kirby->url('panel') . '/assets/' . $version . '/icons.svg';
202193
}
203194

204195
/**
@@ -220,6 +211,15 @@ public function importMaps(): array
220211
]);
221212
}
222213

214+
/**
215+
* Whether the Panel is running in dev mode
216+
* @since 6.0.0
217+
*/
218+
public function isDev(): bool
219+
{
220+
return $this->isDev;
221+
}
222+
223223
/**
224224
* Get all js files
225225
*/

src/Panel/Router.php

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,23 @@ protected function garbage(): void
112112
}
113113
}
114114

115+
/**
116+
* Response for the SVG icon sprite
117+
* @since 6.0.0
118+
*/
119+
public function icons(): Response
120+
{
121+
$assets = $this->panel->assets();
122+
$cache = $assets->isDev() === true
123+
? 'no-store'
124+
: 'public, max-age=31536000, immutable';
125+
126+
return Response::file(
127+
$assets->iconsRoot(),
128+
['headers' => ['Cache-Control' => $cache]]
129+
);
130+
}
131+
115132
/**
116133
* Creates a Response object from the result of
117134
* a Panel route call
@@ -155,11 +172,17 @@ public function routes(Areas|null $areas = null): array
155172
{
156173
$kirby = $this->kirby;
157174
$panel = $this->panel;
175+
$router = $this;
158176
$areas ??= $panel->areas();
159177

160-
// the browser incompatibility
161-
// warning is always needed
178+
// the icon sprite and the browser incompatibility
179+
// warning are always needed, no matter the areas
162180
$routes = [
181+
[
182+
'pattern' => 'assets/(:any)/icons.svg',
183+
'auth' => false,
184+
'action' => fn () => $router->icons(),
185+
],
163186
[
164187
'pattern' => 'browser',
165188
'auth' => false,

tests/Panel/AssetsTest.php

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ public function testIcons(): void
307307
$assets = new Assets();
308308

309309
$this->assertSame(
310-
'/media/panel/' . $this->app->versionHash() . '/img/icons.svg',
310+
'/panel/assets/' . $this->app->versionHash() . '/icons.svg',
311311
$assets->icons()
312312
);
313313
}
@@ -316,55 +316,49 @@ public function testIconsInDevMode(): void
316316
{
317317
$this->setDevMode();
318318

319-
$assets = new Assets();
320-
$target = $this->app->root('media') . '/panel/' . $this->app->versionHash() . '/img/icons.svg';
321-
322-
$this->assertFileDoesNotExist($target);
319+
$assets = new Assets();
320+
$modified = F::modified($this->app->root('panel') . '/public/img/icons.svg');
323321

324-
// the sprite is not served by Vite, but synced to the media folder
325322
$this->assertSame(
326-
'/media/panel/' . $this->app->versionHash() . '/img/icons.svg',
323+
'/panel/assets/' . $modified . '/icons.svg',
327324
$assets->icons()
328325
);
329-
330-
$this->assertFileEquals(
331-
$this->app->root('panel') . '/public/img/icons.svg',
332-
$target
333-
);
334326
}
335327

336-
public function testIconsInDevModeWithCurrentCopy(): void
328+
public function testIconsWithCustomMediaUrl(): void
337329
{
338-
$this->setDevMode();
330+
$this->app = $this->app->clone([
331+
'urls' => [
332+
'media' => 'https://cdn.getkirby.com/media'
333+
]
334+
]);
339335

336+
// the sprite must stay on the Panel origin, even if
337+
// the media folder is served from a CDN
340338
$assets = new Assets();
341-
$source = $this->app->root('panel') . '/public/img/icons.svg';
342-
$target = $this->app->root('media') . '/panel/' . $this->app->versionHash() . '/img/icons.svg';
343-
344-
F::write($target, 'current');
345-
touch($target, F::modified($source));
346339

347-
$assets->icons();
348-
349-
// the copy is up to date and does not get repeated
350-
$this->assertSame('current', F::read($target));
340+
$this->assertSame(
341+
'/panel/assets/' . $this->app->versionHash() . '/icons.svg',
342+
$assets->icons()
343+
);
351344
}
352345

353-
public function testIconsInDevModeWithOutdatedCopy(): void
346+
public function testIconsWithCustomPanelSlug(): void
354347
{
355-
$this->setDevMode();
348+
$this->app = $this->app->clone([
349+
'options' => [
350+
'panel' => [
351+
'slug' => 'admin'
352+
]
353+
]
354+
]);
356355

357356
$assets = new Assets();
358-
$source = $this->app->root('panel') . '/public/img/icons.svg';
359-
$target = $this->app->root('media') . '/panel/' . $this->app->versionHash() . '/img/icons.svg';
360-
361-
F::write($target, 'outdated');
362-
touch($target, 1);
363-
364-
$assets->icons();
365357

366-
$this->assertFileEquals($source, $target);
367-
$this->assertSame(F::modified($source), F::modified($target));
358+
$this->assertSame(
359+
'/admin/assets/' . $this->app->versionHash() . '/icons.svg',
360+
$assets->icons()
361+
);
368362
}
369363

370364
public function testIconsRoot(): void
@@ -397,6 +391,13 @@ public function testImportMaps(): void
397391
$this->assertSame('/media/panel/' . $this->app->versionHash() . '/js/vue.esm-browser.prod.js', $importMaps['vue']);
398392
}
399393

394+
public function testIsDev(): void
395+
{
396+
$this->assertFalse((new Assets())->isDev());
397+
$this->setDevMode();
398+
$this->assertTrue((new Assets())->isDev());
399+
}
400+
400401
public function testJs(): void
401402
{
402403
// default asset setup

tests/Panel/StateTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ public function testFilterOnlyRequestWithGlobal(): void
159159
'a' => 'A',
160160
'urls' => [
161161
'api' => '/api',
162-
'icons' => '/media/panel/' . $this->app->versionHash() . '/img/icons.svg',
162+
'icons' => '/panel/assets/' . $this->app->versionHash() . '/icons.svg',
163163
'panel' => '/panel',
164164
'site' => '/'
165165
]

0 commit comments

Comments
 (0)