Passed
Push — v2 ( 8d45c0...6ed658 )
by Guillaume
19:55
created

TailwindCSS::removeTopbar()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
namespace App\Docsets;
4
5
use Godbout\DashDocsetBuilder\Docsets\BaseDocset;
6
use Illuminate\Support\Collection;
7
use Illuminate\Support\Facades\Storage;
8
use Illuminate\Support\Str;
9
use Wa72\HtmlPageDom\HtmlPageCrawler;
10
11
class TailwindCSS extends BaseDocset
12
{
13
    public const CODE = 'tailwindcss';
14
    public const NAME = 'Tailwind CSS';
15
    public const URL = 'tailwindcss.com';
16
    public const INDEX = 'docs/installation.html';
17
    public const PLAYGROUND = 'https://play.tailwindcss.com/';
18
    public const ICON_16 = 'favicon-16x16.png';
19
    public const ICON_32 = 'favicon-32x32.png';
20
    public const EXTERNAL_DOMAINS = [
21
    ];
22
23
24
    public function grab(): bool
25
    {
26
        $toIgnore = implode('|', [
27
            'blog.tailwindcss.com',
28
        ]);
29
30
        system(
31
            "echo; wget tailwindcss.com/docs \
32
                --mirror \
33
                --trust-server-names \
34
                --reject-regex='{$toIgnore}' \
35
                --page-requisites \
36
                --adjust-extension \
37
                --convert-links \
38
                --span-hosts \
39
                --domains={$this->externalDomains()} \
40
                --directory-prefix=storage/{$this->downloadedDirectory()} \
41
                -e robots=off \
42
                --quiet \
43
                --show-progress",
44
            $result
45
        );
46
47
        return $result === 0;
48
    }
49
50
    public function entries(string $file): Collection
51
    {
52
        $crawler = HtmlPageCrawler::create(Storage::get($file));
53
54
        $entries = collect();
55
56
        $entries = $entries->union($this->environmentEntries($crawler, $file));
57
        $entries = $entries->union($this->instructionEntries($crawler, $file));
58
        $entries = $entries->union($this->sampleEntries($crawler, $file));
59
        $entries = $entries->union($this->resourceEntries($crawler, $file));
60
        $entries = $entries->union($this->guideEntries($crawler, $file));
61
        $entries = $entries->union($this->sectionEntries($crawler, $file));
62
63
        return $entries;
64
    }
65
66
    protected function environmentEntries(HtmlPageCrawler $crawler, string $file)
67
    {
68
        $entries = collect();
69
70
        if (Str::contains($file, "{$this->url()}/community.html")) {
71
            $crawler->filter('h2')->each(function (HtmlPageCrawler $node) use ($entries, $file) {
72
                $entries->push([
73
                    'name' => $this->cleanAnchorText($node->text()),
74
                    'type' => 'Environment',
75
                    'path' => Str::after($file . '#' . Str::slug($node->text()), $this->innerDirectory()),
76
                ]);
77
            });
78
79
            return $entries;
80
        }
81
    }
82
83
    protected function instructionEntries(HtmlPageCrawler $crawler, string $file)
84
    {
85
        $entries = collect();
86
87
        if (Str::contains($file, "{$this->url()}/course.html")) {
88
            $crawler->filter('span.relative')->each(function (HtmlPageCrawler $node) use ($entries) {
89
                $entries->push([
90
                    'name' => $this->cleanAnchorText($node->text()),
91
                    'type' => 'Instruction',
92
                    'path' => $this->url() . '/' . $node->parents()->first()->attr('href'),
93
                ]);
94
            });
95
96
            return $entries;
97
        }
98
    }
99
100
    protected function sampleEntries(HtmlPageCrawler $crawler, string $file)
101
    {
102
        $entries = collect();
103
104
        if (Str::contains($file, "{$this->url()}/components/")) {
105
            $crawler->filter('span.relative')->each(function (HtmlPageCrawler $node) use ($entries) {
106
                $entries->push([
107
                    'name' => $this->cleanAnchorText($node->text()),
108
                    'type' => 'Sample',
109
                    'path' => $this->url() . '/components/' . $node->parents()->first()->attr('href'),
110
                ]);
111
            });
112
113
            return $entries;
114
        }
115
    }
116
117
    protected function resourceEntries(HtmlPageCrawler $crawler, string $file)
118
    {
119
        $entries = collect();
120
121
        if (Str::contains($file, "{$this->url()}/resources.html")) {
122
            $crawler->filter('h2')->each(function (HtmlPageCrawler $node) use ($entries, $file) {
123
                $entries->push([
124
                    'name' => $this->cleanAnchorText($node->text()),
125
                    'type' => 'Resource',
126
                    'path' => Str::after($file . '#' . Str::slug($node->text()), $this->innerDirectory()),
127
                ]);
128
            });
129
130
            $crawler->filter('h3')->each(function (HtmlPageCrawler $node) use ($entries, $file) {
131
                $entries->push([
132
                    'name' => $this->cleanAnchorText($node->text()),
133
                    'type' => 'Section',
134
                    'path' => Str::after($file . '#' . Str::slug($node->text()), $this->innerDirectory()),
135
                ]);
136
            });
137
138
            return $entries;
139
        }
140
    }
141
142
    protected function guideEntries(HtmlPageCrawler $crawler, string $file)
143
    {
144
        $entries = collect();
145
146
        if (Str::contains($file, "{$this->url()}/docs.html")) {
147
            $crawler->filter('nav#nav li.mt-8 a')->each(function (HtmlPageCrawler $node) use ($entries) {
148
                $entries->push([
149
                    'name' => trim($node->text()),
150
                    'type' => 'Guide',
151
                    'path' => $this->url() . '/' . $node->attr('href'),
152
                ]);
153
            });
154
        }
155
156
        return $entries;
157
    }
158
159
    protected function sectionEntries(HtmlPageCrawler $crawler, string $file)
160
    {
161
        $entries = collect();
162
163
        $crawler->filter('h2')->each(function (HtmlPageCrawler $node) use ($entries, $file) {
164
            $entries->push([
165
                'name' => $this->cleanAnchorText($node->text()),
166
                'type' => 'Section',
167
                'path' => Str::after($file . '#' . Str::slug($node->text()), $this->innerDirectory()),
168
            ]);
169
        });
170
171
        return $entries;
172
    }
173
174
    public function format(string $file): string
175
    {
176
        $crawler = HtmlPageCrawler::create(Storage::get($file));
177
178
        $this->removeTopbar($crawler);
179
        $this->removeLeftSidebar($crawler);
180
        $this->removeRightSidebar($crawler);
181
        $this->removeBottomMenuButton($crawler);
182
183
        $this->updateContainerWidth($crawler);
184
        $this->updateBottomPadding($crawler);
185
186
        $this->ignoreDarkModeForSomeColors($crawler);
187
188
        $this->removeUnwantedJavaScript($crawler);
189
190
        $this->insertOnlineRedirection($crawler, $file);
191
        $this->insertDashTableOfContents($crawler);
192
193
        return $crawler->saveHTML();
194
    }
195
196
    protected function removeTopbar(HtmlPageCrawler $crawler)
197
    {
198
        $crawler->filter('div.sticky.top-0')->remove();
199
    }
200
201
    protected function removeLeftSidebar(HtmlPageCrawler $crawler)
202
    {
203
        $crawler->filter('#sidebar')->remove();
204
    }
205
206
    protected function removeRightSidebar(HtmlPageCrawler $crawler)
207
    {
208
        $crawler->filter('#content-wrapper div.hidden.flex-none.w-64')->remove();
209
    }
210
211
    protected function removeBottomMenuButton(HtmlPageCrawler $crawler)
212
    {
213
        $crawler->filter('#__next > button[type=button]')->remove();
214
    }
215
216
    protected function updateContainerWidth(HtmlPageCrawler $crawler)
217
    {
218
        $crawler->filter('#content-wrapper')->addClass('px-4');
219
    }
220
221
    protected function updateBottomPadding(HtmlPageCrawler $crawler)
222
    {
223
        $crawler->filter('#content-wrapper > div')
224
            ->removeClass('pb-24')
225
            ->addClass('pb-10')
226
        ;
227
    }
228
229
    protected function ignoreDarkModeForSomeColors(HtmlPageCrawler $crawler)
230
    {
231
        $this->ignoreDarkModeForDefaultColorPaletteSection($crawler);
232
        $this->ignoreDarkModeForVariousColorTables($crawler);
233
    }
234
235
    protected function ignoreDarkModeForDefaultColorPaletteSection(HtmlPageCrawler $crawler)
236
    {
237
        $crawler->filter('div.h-10.w-full.rounded.ring-1.ring-inset')->addClass('dash-ignore-dark-mode');
238
    }
239
240
    protected function ignoreDarkModeForVariousColorTables(HtmlPageCrawler $crawler)
241
    {
242
        $crawler->filter('h2 + div td:last-child')->addClass('dash-ignore-dark-mode');
243
    }
244
245
    protected function removeUnwantedJavaScript(HtmlPageCrawler $crawler)
246
    {
247
        $crawler->filter('script')->remove();
248
    }
249
250
    protected function insertOnlineRedirection(HtmlPageCrawler $crawler, string $file)
251
    {
252
        $onlineUrl = Str::substr(Str::after($file, $this->innerDirectory()), 1, -5);
253
254
        $crawler->filter('html')->prepend("<!-- Online page at https://$onlineUrl -->");
255
    }
256
257
    protected function insertDashTableOfContents(HtmlPageCrawler $crawler)
258
    {
259
        $crawler->filter('body')
260
            ->before('<a name="//apple_ref/cpp/Section/Top" class="dashAnchor"></a>');
261
262
        $crawler->filter('h2, h3')->each(function (HtmlPageCrawler $node) {
263
            $node->prepend(
264
                '<a id="' . Str::slug($node->text()) . '" name="//apple_ref/cpp/Section/' . rawurlencode($this->cleanAnchorText($node->text())) . '" class="dashAnchor"></a>'
265
            );
266
        });
267
    }
268
269
    protected function cleanAnchorText($anchorText)
270
    {
271
        return trim(preg_replace('/\s+/', ' ', $anchorText));
272
    }
273
}
274