Skip to content

Commit b078c5b

Browse files
committed
use innmind/ui to build the homepage
1 parent a29c099 commit b078c5b

File tree

4 files changed

+119
-151
lines changed

4 files changed

+119
-151
lines changed

assets/logo.svg

+24
Loading

composer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
"innmind/framework": "~2.0",
2323
"innmind/json": "^1.3",
2424
"innmind/html": "~6.2",
25-
"innmind/url-template": "^3.0"
25+
"innmind/url-template": "^3.0",
26+
"innmind/ui": "dev-develop"
2627
},
2728
"autoload": {
2829
"psr-4": {

src/Template/Index.php

+25-147
Original file line numberDiff line numberDiff line change
@@ -6,169 +6,47 @@
66
use Innmind\Profiler\Profile;
77
use Innmind\Filesystem\File\Content;
88
use Innmind\UrlTemplate\Template;
9-
use Innmind\Html\{
10-
Node\Document,
11-
Element\A,
12-
};
13-
use Innmind\Xml\{
14-
Node\Document\Type,
15-
Node\Text,
16-
Element\Element,
17-
Element\SelfClosingElement,
18-
Attribute,
19-
};
9+
use Innmind\UI;
2010
use Innmind\Immutable\{
2111
Sequence,
22-
Set,
2312
Map,
2413
};
2514

2615
final class Index
2716
{
28-
private Template $list;
2917
private Template $profile;
30-
31-
public function __construct(Template $list, Template $profile)
32-
{
33-
$this->list = $list;
18+
private Template $style;
19+
private Template $logo;
20+
21+
public function __construct(
22+
Template $profile,
23+
Template $style,
24+
Template $logo,
25+
) {
3426
$this->profile = $profile;
27+
$this->style = $style;
28+
$this->logo = $logo;
3529
}
3630

3731
/**
3832
* @param Sequence<Profile> $profiles
3933
*/
4034
public function __invoke(Sequence $profiles): Content
4135
{
42-
$document = Document::of(
43-
Type::of('html'),
44-
Sequence::of(Element::of(
45-
'html',
46-
null,
47-
Sequence::of(
48-
Element::of(
49-
'head',
50-
null,
51-
Sequence::of(
52-
Element::of('title', null, Sequence::of(Text::of('Profiler'))),
53-
SelfClosingElement::of('meta', Set::of(Attribute::of('charset', 'UTF-8'))),
54-
Element::of('style', null, Sequence::of(Text::of(self::css()))),
55-
),
56-
),
57-
Element::of(
58-
'body',
59-
null,
60-
Sequence::of(
61-
Element::of(
62-
'header',
63-
null,
64-
Sequence::of(A::of(
65-
$this->list->expand(Map::of()),
66-
null,
67-
Sequence::of(SelfClosingElement::of(
68-
'img',
69-
Set::of(
70-
Attribute::of('alt', 'home'),
71-
Attribute::of('src', 'data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjUwMCIgd2lkdGg9IjUwMCIgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgogIDxjaXJjbGUgY3g9IjI1MCIgY3k9IjI1MCIgcj0iMjUwIiBmaWxsPSJyZ2IoNDgsNDgsNDgpIiAvPgogIDxkZWZzPgogICAgPGcgaWQ9ImxlYWYiIGZpbHRlcj0idXJsKCNzaGFkb3cpIj4KICAgICAgPHBhdGggZD0ibSAyNTAgMjAgcSAtNjAgMTI1IDAgMTUwIiBmaWxsPSJ3aGl0ZSIgLz4KICAgICAgPHBhdGggZD0ibSAyNTAgMjAgcSA2MCAxMjUgMCAxNTAiIGZpbGw9IndoaXRlIiAvPgogICAgICA8cG9seWdvbiBwb2ludHM9IjI1MCw4MCAyNTEsMTcwIDI0OSwxNzAiIGZpbGw9InJnYig0OCw0OCw0OCkiIC8+CiAgICA8L2c+CiAgICA8ZmlsdGVyIGlkPSJzaGFkb3ciIHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEyMCUiPgogICAgICA8ZmVPZmZzZXQgcmVzdWx0PSJvZmZPdXQiIGluPSJTb3VyY2VBbHBoYSIgZHg9IjAiIGR5PSI1IiAvPgogICAgICA8ZmVHYXVzc2lhbkJsdXIgcmVzdWx0PSJibHVyT3V0IiBpbj0ib2ZmT3V0IiBzdGREZXZpYXRpb249IjEwMCIgLz4KICAgICAgPGZlQmxlbmQgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0ib2ZmT3V0IiBtb2RlPSJub3JtYWwiIC8+CiAgICA8L2ZpbHRlcj4KICA8L2RlZnM+CiAgPHVzZSB4bGluazpocmVmPSIjbGVhZiIgLz4KICA8dXNlIHhsaW5rOmhyZWY9IiNsZWFmIiB0cmFuc2Zvcm09InJvdGF0ZSg0NSAyNTAgMjUwKSIgLz4KICA8dXNlIHhsaW5rOmhyZWY9IiNsZWFmIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAyNTAgMjUwKSIgLz4KICA8dXNlIHhsaW5rOmhyZWY9IiNsZWFmIiB0cmFuc2Zvcm09InJvdGF0ZSgxMzUgMjUwIDI1MCkiIC8+CiAgPHVzZSB4bGluazpocmVmPSIjbGVhZiIgdHJhbnNmb3JtPSJyb3RhdGUoMTgwIDI1MCAyNTApIiAvPgogIDx1c2UgeGxpbms6aHJlZj0iI2xlYWYiIHRyYW5zZm9ybT0icm90YXRlKDIyNSAyNTAgMjUwKSIgLz4KICA8dXNlIHhsaW5rOmhyZWY9IiNsZWFmIiB0cmFuc2Zvcm09InJvdGF0ZSgyNzAgMjUwIDI1MCkiIC8+CiAgPHVzZSB4bGluazpocmVmPSIjbGVhZiIgdHJhbnNmb3JtPSJyb3RhdGUoMzE1IDI1MCAyNTApIiAvPgogIDxjaXJjbGUgY3g9IjI1MCIgY3k9IjI1MCIgcj0iNjAiIHN0cm9rZT0icmdiKDUyLDE0MCwyNTUpIiBzdHJva2Utd2lkdGg9IjEwIiBmaWxsPSJub25lIiAvPgo8L3N2Zz4K'),
72-
),
73-
)),
74-
)),
75-
),
76-
Element::of(
77-
'main',
78-
null,
79-
Sequence::of(Element::of(
80-
'ul',
81-
null,
82-
$profiles->map(fn($profile) => Element::of(
83-
'li',
84-
Set::of(Attribute::of('class', $profile->status()->name)),
85-
Sequence::of(A::of(
86-
$this->profile->expand(Map::of(['id', $profile->id()->toString()])),
87-
null,
88-
Sequence::of(Text::of($profile->toString())),
89-
)),
90-
)),
91-
)),
92-
),
93-
),
36+
return UI\Window::of(
37+
'Profiler',
38+
UI\Stack::vertical(
39+
UI\Toolbar::of(UI\Text::of('Profiler'))
40+
->leading(UI\Image::of($this->logo->expand(Map::of()))),
41+
UI\Listing::of($profiles->map(
42+
fn($profile) => UI\NavigationLink::text(
43+
$this->profile->expand(Map::of(['id', $profile->id()->toString()])),
44+
$profile->toString(),
9445
),
95-
),
96-
)),
97-
);
98-
99-
return $document->asContent();
100-
}
101-
102-
private static function css(): string
103-
{
104-
return <<<CSS
105-
body {
106-
margin: 0;
107-
}
108-
109-
header {
110-
background-color: rgb(48, 48, 48);
111-
display: flex;
112-
height: 60px;
113-
padding: 0 10px;
114-
}
115-
116-
header img {
117-
height: 50px;
118-
padding: 5px 0;
119-
}
120-
121-
main {
122-
margin: 35px;
123-
}
124-
125-
main ul {
126-
border: solid;
127-
border-width: 1px;
128-
border-color: rgba(48, 48, 48, 0.2);
129-
margin: 0;
130-
padding: 0;list-style: none;
131-
border-radius: 4px;
132-
}
133-
134-
main ul li a {
135-
color: rgb(52,140,255);
136-
display: block;
137-
padding: 10px;
138-
text-decoration: none;
139-
}
140-
141-
main ul li.empty {
142-
padding: 10px;
143-
}
144-
145-
main ul li.succeeded {
146-
background-color: rgba(104, 255, 101, 0.3);
147-
}
148-
149-
main ul li.succeeded:hover {
150-
background-color: rgba(104, 255, 101, 0.6);
151-
}
152-
153-
main ul li.failed {
154-
background-color: rgba(255, 79, 86, 0.3);
155-
}
156-
157-
main ul li.failed:hover {
158-
background-color: rgba(255, 79, 86, 0.6);
159-
}
160-
161-
main ul li.started {
162-
background-color: rgba(255, 179, 48, 0.3);
163-
}
164-
165-
main ul li.started:hover {
166-
background-color: rgba(255, 179, 48, 0.6);
167-
}
168-
169-
main ul li + li {
170-
border-top: 1px solid rgba(48, 48, 48, 0.2);
171-
}
172-
CSS;
46+
)),
47+
),
48+
)
49+
->stylesheet($this->style->expand(Map::of()))
50+
->render();
17351
}
17452
}

src/Web/Kernel.php

+68-3
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,22 @@
1414
Middleware,
1515
Http\Service,
1616
};
17+
use Innmind\Filesystem\{
18+
File,
19+
Name,
20+
};
21+
use Innmind\Http\{
22+
Response,
23+
Response\StatusCode,
24+
Headers,
25+
Header\ContentType,
26+
Header\Header,
27+
Header\Value\Value,
28+
};
1729
use Innmind\Router\Route;
30+
use Innmind\UI\Theme;
1831
use Innmind\Url\Path;
32+
use Innmind\Immutable\Predicate\Instance;
1933

2034
/**
2135
* @psalm-suppress ArgumentTypeCoercion
@@ -26,17 +40,23 @@ final class Kernel implements Middleware
2640
private Route $list;
2741
private Route $profile;
2842
private Route $section;
43+
private Route $style;
44+
private Route $logo;
2945

3046
private function __construct(
3147
Path $storage,
3248
Route $list,
3349
Route $profile,
3450
Route $section,
51+
Route $style,
52+
Route $logo,
3553
) {
3654
$this->storage = $storage;
3755
$this->list = $list;
3856
$this->profile = $profile;
3957
$this->section = $section;
58+
$this->style = $style;
59+
$this->logo = $logo;
4060
}
4161

4262
public function __invoke(Application $app): Application
@@ -54,17 +74,58 @@ public function __invoke(Application $app): Application
5474
)
5575
->service('innmind/profiler.listProfiles', fn($get) => new ListProfiles(
5676
$get('innmind/profiler'),
57-
new Index($this->list->template(), $this->profile->template()),
77+
new Index(
78+
$this->profile->template(),
79+
$this->style->template(),
80+
$this->logo->template(),
81+
),
5882
))
5983
->service('innmind/profiler.showProfile', fn($get) => new ShowProfile(
6084
$get('innmind/profiler'),
6185
new Profile($this->list->template(), $this->section->template()),
6286
))
6387
->appendRoutes(
64-
fn($routes, $get) => $routes
88+
fn($routes, $get, $os) => $routes
6589
->add($this->list->handle(Service::of($get, 'innmind/profiler.listProfiles')))
6690
->add($this->profile->handle(Service::of($get, 'innmind/profiler.showProfile')))
67-
->add($this->section->handle(Service::of($get, 'innmind/profiler.showProfile'))),
91+
->add($this->section->handle(Service::of($get, 'innmind/profiler.showProfile')))
92+
->add($this->style->handle(
93+
static fn($request) => Theme::default->load($os->filesystem())->match(
94+
static fn($file) => Response::of(
95+
StatusCode::ok,
96+
$request->protocolVersion(),
97+
Headers::of(
98+
ContentType::of('text', 'css'),
99+
),
100+
$file,
101+
),
102+
static fn() => Response::of(
103+
StatusCode::notFound,
104+
$request->protocolVersion(),
105+
),
106+
),
107+
))
108+
->add($this->logo->handle(
109+
static fn($request) => $os
110+
->filesystem()
111+
->mount(Path::of(\dirname(__DIR__, 2).'/assets/'))
112+
->get(Name::of('logo.svg'))
113+
->keep(Instance::of(File::class))
114+
->match(
115+
static fn($file) => Response::of(
116+
StatusCode::ok,
117+
$request->protocolVersion(),
118+
Headers::of(
119+
new Header('Content-Type', new Value('image/svg+xml')),
120+
),
121+
$file->content(),
122+
),
123+
static fn() => Response::of(
124+
StatusCode::notFound,
125+
$request->protocolVersion(),
126+
),
127+
),
128+
)),
68129
);
69130
}
70131

@@ -75,6 +136,8 @@ public static function standalone(Path $storage): self
75136
Route::literal('GET /'),
76137
Route::literal('GET /profile/{id}'),
77138
Route::literal('GET /profile/{id}/{section}'),
139+
Route::literal('GET /style'),
140+
Route::literal('GET /logo'),
78141
);
79142
}
80143

@@ -85,6 +148,8 @@ public static function inApp(Path $storage): self
85148
Route::literal('GET /_profiler/'),
86149
Route::literal('GET /_profiler/profile/{id}'),
87150
Route::literal('GET /_profiler/profile/{id}/{section}'),
151+
Route::literal('GET /_profiler/style'),
152+
Route::literal('GET /_profiler/logo'),
88153
);
89154
}
90155
}

0 commit comments

Comments
 (0)