├── .gitignore
├── CONTRIBUTING.md
├── LICENSE.md
├── composer.json
├── config
└── breakpoints.php
├── phpunit.xml
├── readme.md
├── resources
└── components
│ ├── save-to-session.blade.php
│ └── test-windowsize.blade.php
├── routes
└── web.php
├── src
├── Helpers.php
├── LaravelWindowSizeController.php
└── LaravelWindowSizeServiceProvider.php
└── tests
└── TestCase.php
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor
2 | .env
3 | .phpunit.result.cache
4 | /.idea
5 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Contributions are **welcome** and will be fully **credited**.
4 |
5 | We accept contributions via Pull Requests on [Github](https://github.com/tanthammar/laravel-window-size).
6 |
7 |
8 | ## Pull Requests
9 |
10 | - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer).
11 |
12 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests.
13 |
14 | - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date.
15 |
16 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option.
17 |
18 | - **Create feature branches** - Don't ask us to pull from your master branch.
19 |
20 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.
21 |
22 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting.
23 |
24 |
25 | ## Running Tests
26 |
27 | ``` bash
28 | $ composer test
29 | ```
30 |
31 |
32 | **Happy coding**!
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 tanthammar
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tanthammar/laravel-window-size",
3 | "description": "Laravel blade directives and php helpers for serverside rendered content, based on browser window size WITHOUT css",
4 | "type": "package",
5 | "license": "MIT",
6 | "keywords": [
7 | "laravel",
8 | "breakpoints"
9 | ],
10 | "authors": [
11 | {
12 | "name": "Tina Hammar",
13 | "email": "tinahammar@gmail.com"
14 | }
15 | ],
16 | "require": {
17 | "php": "^8.0|^8.1|^8.2|^8.3|^8.4",
18 | "illuminate/support": "^8.0|^9.0|^10.0|^11.0|^12.0"
19 | },
20 | "autoload": {
21 | "psr-4": {
22 | "Tanthammar\\LaravelWindowSize\\": "./src"
23 | }
24 | },
25 | "autoload-dev": {
26 | "psr-4": {
27 | "Tanthammar\\LaravelWindowSize\\Tests\\": "tests"
28 | }
29 | },
30 | "scripts": {
31 | "test": "vendor/bin/phpunit"
32 | },
33 | "extra": {
34 | "laravel": {
35 | "providers": [
36 | "Tanthammar\\LaravelWindowSize\\LaravelWindowSizeServiceProvider"
37 | ]
38 | }
39 | },
40 | "require-dev": {
41 | "orchestra/testbench": "^6.0"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/config/breakpoints.php:
--------------------------------------------------------------------------------
1 | [
5 | // 0 = undefined|false
6 | // @windowXs (>= 1px && < Sm)
7 | 'Sm' => 640, // => @windowSm (>= 640px && < Md)
8 | 'Md' => 768, // => @windowMd (>= 768px && < Lg)
9 | 'Lg' => 1024, // => @windowLg (>= 1024px && < Xl)
10 | 'Xl' => 1280, // => @windowXl (>= 1280px && < 2xl)
11 | '2xl' => 1536, // => @window2xl (>= 1536px)
12 | ],
13 | ];
14 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | tests
9 |
10 |
11 |
12 |
13 | ./app
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Laravel Window Size and Breakpoints
2 | Laravel `blade` directives and `php helpers` for **server side rendered content**, based on browser window size WITHOUT css.
3 |
4 | An example to show the purpose of this package:
5 | ```php
6 | >>](https://github.com/TinaHammar/livewire-window-size)
27 |
28 |
29 | ## Description
30 | The main purpose of this package is not to avoid duplicated html,
31 | but to avoid unnecessary server side code execution, just to render content that will never be seen.
32 |
33 | * Vanilla JS syncs the browsers inner `width` and `height`, in realtime (debounced 750ms), when the browser window is resized.
34 | * The corresponding Laravel controller will store the values to the Laravel `Session`.
35 | * The package has a `config/breakpoints` file where you set your breakpoints
36 | * The package provides multiple `@blade` directives and Laravel `helpers()`
37 | * You have access to the browser window width/height via `session('windowW')` and `session('windowH')`
38 | * You can change the config dynamically with Laravel `Config::set(...)`
39 | * The route is throttling the request `15:1`. (The route is: `/update-laravel-window-size`)
40 |
41 | # Important note
42 | It's important to understand the difference between the server side rendered breakpoints, that this package provides, and css media queries.
43 |
44 | When using css, the content of the page will update in realtime as the user resizes the window,
45 | whereas this package debounces a network request and updates the page on the next page request.
46 |
47 | It's important that you place the `` at first point of contact with the user, for your application to look its best. I have it in my `app.blade.php` and on the `login`/`register` pages.
48 |
49 |
50 | ## Installation
51 | ```
52 | composer require tanthammar/laravel-window-size
53 | ```
54 |
55 | ## Publish config
56 | ```
57 | php artisan vendor:publish --tag=laravel-window-size
58 | ```
59 |
60 |
61 | The default settings are based on TailwindCSS breakpoints
62 | ```php
63 | 'window-width' => [
64 | // 0 = undefined|false
65 | // @windowXs (>= 1px && < Sm)
66 | 'Sm' => 640, // => @windowSm (>= 640px && < Md)
67 | 'Md' => 768, // => @windowMd (>= 768px && < Lg)
68 | 'Lg' => 1024, // => @windowLg (>= 1024px && < Xl)
69 | 'Xl' => 1280, // => @windowXl (>= 1280px && < 2xl)
70 | '2xl' => 1536, // => @window2xl (>= 1536px)
71 | ],
72 | ```
73 |
74 | ## Add the component to your layout
75 | * Add this to all layouts where you want to keep track of the browser window size.
76 | * You will have access to the browser window width/height via `session('windowW')` and `session('windowH')`
77 |
78 | Example: `app.blade.php`
79 | ```blade
80 |
81 | ```
82 |
83 | ## Blade directives
84 | @elsif..., @else..., @end..., @unless... and @endif works with all the directives. Explanation in [Laravel docs](https://laravel.com/docs/8.x/blade#custom-if-statements).
85 | ```blade
86 | //Browser width, with example values
87 | @windowWidthLessThan(400)
88 | @windowWidthGreaterThan(399)
89 | @windowWidthBetween(400, 1500)
90 |
91 | //Browser height, with example values
92 | @windowHeightLessThan(500)
93 | @windowHeightGreaterThan(499)
94 | @windowHeightBetween(400, 900)
95 |
96 | //Breakpoints based on config values
97 | @windowXs()
98 | @windowSm()
99 | @windowMd()
100 | @windowLg()
101 | @windowXl()
102 | @window2xl()
103 | ```
104 | Example
105 | ```blade
106 | @windowXs()
107 |
This window is extra small
108 | @endif
109 |
110 | @window2xl()
111 | This window is very large
112 | @endif
113 | ```
114 |
115 | ## Helpers
116 | Same name as Blade directives
117 | ```php
118 | //Mobile device detection based on request header.
119 | mobileDevice()
120 |
121 | //Browser width, with example values
122 | windowWidthLessThan(400)
123 | windowWidthGreaterThan(399)
124 | windowWidthBetween(400, 1500)
125 |
126 | //Browser height, with example values
127 | windowHeightLessThan(500)
128 | windowHeightGreaterThan(499)
129 | windowHeightBetween(400, 900)
130 |
131 | //Breakpoints based on config values
132 | windowXs()
133 | windowSm()
134 | windowMd()
135 | windowLg()
136 | windowXl()
137 | window2xl()
138 | ```
139 |
140 | Example php
141 | ```php
142 | if(windowXs()) {
143 | //execute a tiny Eloquent query and return a minimalistic view
144 | }
145 | if(window2xl()) {
146 | //execute a huge Eloquent query and return a gigantic view
147 | }
148 | ```
149 |
150 | ## Blade directives test component
151 | Add this to any blade view to test the blade directives
152 | ```blade
153 |
154 | ```
155 |
156 | ## 💬 Let's connect
157 | * [🔗 **Twitter**](https://twitter.com/TinaHammar)
158 | * 🔗 Please 💗 [sponsor me](https://github.com/sponsors/tanthammar) if you like my work.
159 |
160 | ## Credits
161 | * [Martin Krisell](https://github.com/Krisell)
162 |
163 |
164 | ## Changelog
165 | Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently.
166 |
167 | ## Contributing
168 | Please see [CONTRIBUTING](CONTRIBUTING.md) for details.
169 |
170 | ## License
171 | The MIT License (MIT). Please see [License File](/LICENSE.md) for more information.
172 |
--------------------------------------------------------------------------------
/resources/components/save-to-session.blade.php:
--------------------------------------------------------------------------------
1 |
52 |
--------------------------------------------------------------------------------
/resources/components/test-windowsize.blade.php:
--------------------------------------------------------------------------------
1 | {{-- dev test :) --}}
2 |
3 |
4 |
---WIDTH---
5 |
6 |
session width: {{session('windowW')}}
7 |
8 | @windowWidthLessThan(400)
9 |
windowWIDTHLessThan 400
10 | @endif
11 |
12 | @windowWidthGreaterThan(399)
13 |
windowWIDTHGreaterThan 399
14 | @endif
15 |
16 | @windowWidthBetween(400, 1500)
17 |
windowWIDTHBetween 400, 1500
18 | @endif
19 |
20 |
---HEIGHT---
21 |
22 |
session height: {{session('windowH')}}
23 |
24 | @windowHeightLessThan(500)
25 |
windowHEIGHTLessThan 500
26 | @endif
27 |
28 | @windowHeightGreaterThan(499)
29 |
windowHEIGHTGreaterThan 499
30 | @endif
31 |
32 | @windowHeightBetween(400, 1500)
33 |
windowHEIGHTBetween 400, 1500
34 | @endif
35 |
36 |
---BREAKPOINTS---
37 |
38 | @windowXs()
39 |
Xs window
40 | @endif
41 |
42 | @windowSm()
43 |
Sm window
44 | @endif
45 |
46 | @windowMd()
47 |
Md window
48 | @endif
49 |
50 | @windowLg()
51 |
Lg window
52 | @endif
53 |
54 | @windowXl()
55 |
Xl window
56 | @endif
57 |
58 | @window2xl()
59 |
2xl window
60 | @endif
61 |
62 |
---END---
63 |
64 |
--------------------------------------------------------------------------------
/routes/web.php:
--------------------------------------------------------------------------------
1 | middleware('web', 'throttle:15,1');
7 |
--------------------------------------------------------------------------------
/src/Helpers.php:
--------------------------------------------------------------------------------
1 | header('User-Agent')
11 | );
12 | }
13 | }
14 |
15 | if (!function_exists('windowWidthLessThan')) {
16 | function windowWidthLessThan(int $value): bool
17 | {
18 | return session('windowW') < $value;
19 | }
20 | }
21 |
22 | if (!function_exists('windowWidthGreaterThan')) {
23 | function windowWidthGreaterThan(int $value): bool
24 | {
25 | return session('windowW') > $value;
26 | }
27 | }
28 |
29 | if (!function_exists('windowWidthBetween')) {
30 | function windowWidthBetween(mixed ...$expression): bool
31 | {
32 | $between = collect(Arr::flatten($expression));
33 | $w = session('windowW');
34 | return ($w > $between->first() && $w < $between->last());
35 | }
36 | }
37 |
38 | if (!function_exists('windowHeightLessThan')) {
39 | function windowHeightLessThan(int $value): bool
40 | {
41 | return session('windowH') < $value;
42 | }
43 | }
44 |
45 | if (!function_exists('windowHeightGreaterThan')) {
46 | function windowHeightGreaterThan(int $value): bool
47 | {
48 | return session('windowH') > $value;
49 | }
50 | }
51 |
52 | if (!function_exists('windowHeightBetween')) {
53 | function windowHeightBetween(mixed ...$expression): bool
54 | {
55 | $between = collect(Arr::flatten($expression));
56 | $h = session('windowH');
57 | return ($h > $between->first() && $h < $between->last());
58 | }
59 | }
60 |
61 | if (!function_exists('windowXs')) {
62 | function windowXs(): bool
63 | {
64 | $w = session('windowW');
65 | return (
66 | $w > 0
67 | && $w < config('breakpoints.window-width.Xs', 640)
68 | );
69 | }
70 | }
71 |
72 | if (!function_exists('windowSm')) {
73 | function windowSm(): bool
74 | {
75 | $w = session('windowW');
76 | return (
77 | $w >= config('breakpoints.window-width.Sm', 640)
78 | && $w < config('breakpoints.window-width.Md', 768)
79 | );
80 | }
81 | }
82 |
83 | if (!function_exists('windowMd')) {
84 | function windowMd(): bool
85 | {
86 | $w = session('windowW');
87 | return (
88 | $w >= config('breakpoints.window-width.Md', 768)
89 | && $w < config('breakpoints.window-width.Lg', 1024)
90 | );
91 | }
92 | }
93 |
94 | if (!function_exists('windowLg')) {
95 | function windowLg(): bool
96 | {
97 | $w = session('windowW');
98 | return (
99 | $w >= config('breakpoints.window-width.Lg', 1024)
100 | && $w < config('breakpoints.window-width.Xl', 1280)
101 | );
102 | }
103 | }
104 |
105 | if (!function_exists('windowXl')) {
106 | function windowXl(): bool
107 | {
108 | $w = session('windowW');
109 | return (
110 | $w >= config('breakpoints.window-width.Xl', 1280)
111 | && $w < config('breakpoints.window-width.2xl', 1536)
112 | );
113 | }
114 | }
115 |
116 | if (!function_exists('window2xl')) {
117 | function window2xl(): bool
118 | {
119 | return session('windowW') >= config('breakpoints.window-width.2xl', 1536);
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/src/LaravelWindowSizeController.php:
--------------------------------------------------------------------------------
1 | input('width');
19 | $h = (int)$request->input('height');
20 |
21 | if ($w > 0) {
22 | session(['windowW' => $w]);
23 | }
24 | if ($h > 0) {
25 | session(['windowH' => $h]);
26 | }
27 |
28 | return response()->json();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/LaravelWindowSizeServiceProvider.php:
--------------------------------------------------------------------------------
1 | mergeConfigFrom(__DIR__ . '/../config/breakpoints.php', 'breakpoints');
19 | }
20 |
21 | public function boot(): void
22 | {
23 | $this->publishes([__DIR__ . '/../config/breakpoints.php' => config_path('breakpoints.php')], 'laravel-window-size');
24 | $this->loadRoutesFrom(__DIR__ . '/../routes/web.php');
25 | $this->loadViewsFrom(__DIR__ . '/../resources/', 'window-size');
26 | $this->bladeDirectives();
27 | }
28 |
29 | protected function bladeDirectives(): void
30 | {
31 | Blade::if('windowWidthLessThan', static function ($value) {
32 | return windowWidthLessThan($value);
33 | });
34 |
35 | Blade::if('windowWidthGreaterThan', static function ($value) {
36 | return windowWidthGreaterThan($value);
37 | });
38 |
39 | Blade::if('windowWidthBetween', static function (...$expression) {
40 | return windowWidthBetween($expression);
41 | });
42 |
43 | Blade::if('windowHeightLessThan', static function ($value) {
44 | return windowHeightLessThan($value);
45 | });
46 |
47 | Blade::if('windowHeightGreaterThan', static function ($value) {
48 | return windowHeightGreaterThan($value);
49 | });
50 |
51 | Blade::if('windowHeightBetween', static function (...$expression) {
52 | return windowHeightBetween($expression);
53 | });
54 |
55 | Blade::if('windowXs', static fn () => windowXs());
56 |
57 | Blade::if('windowSm', static fn () => windowSm());
58 |
59 | Blade::if('windowMd', static fn () => windowMd());
60 |
61 | Blade::if('windowLg', static fn () => windowLg());
62 |
63 | Blade::if('windowXl', static fn () => windowXl());
64 |
65 | Blade::if('window2xl', static fn () => window2xl());
66 |
67 | Blade::if('mobileDevice', static fn () => mobileDevice());
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 |