Skip to content

Commit 620459c

Browse files
committed
init
0 parents  commit 620459c

14 files changed

+723
-0
lines changed

.editorconfig

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
end_of_line = lf
6+
insert_final_newline = true
7+
indent_style = space
8+
indent_size = 4
9+
trim_trailing_whitespace = true
10+
11+
[*.md]
12+
trim_trailing_whitespace = false
13+
14+
[*.{yml,yaml}]
15+
indent_size = 2

.gitattributes

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
* text=auto
2+
3+
*.blade.php diff=html
4+
*.css diff=css
5+
*.html diff=html
6+
*.md diff=markdown
7+
*.php diff=php
8+
9+
/.github export-ignore
10+
/art export-ignore
11+
/tests export-ignore
12+
.editorconfig export-ignore
13+
.gitattributes export-ignore
14+
.gitignore export-ignore
15+
.styleci.yml export-ignore
16+
CHANGELOG.md export-ignore
17+
phpstan.neon.dist export-ignore
18+
phpunit.xml.dist export-ignore
19+
UPGRADE.md export-ignore

.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/vendor
2+
composer.lock
3+
/phpunit.xml
4+
.phpunit.result.cache
5+
node_modules/**
6+
test-results/**

LICENSE.md

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
Copyright © Wireable, LLC.
2+
3+
Permission is hereby granted to any person obtaining a copy of this software (the “Software”) to use, copy, modify, merge, publish and/or distribute copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4+
5+
Do not plagiarize. The above copyright notice and this license shall be included in all copies or substantial portions of the Software.
6+
7+
Do not use the same license on more than one project. Each licensed copy of the Software shall be actively installed in no more than one production environment at a time.
8+
9+
Do not alter the licensing features. Software features related to licensing shall not be altered or circumvented in any way, including (but not limited to) license validation, feature or edition restrictions, and update eligibility.
10+
11+
Not for reuse. The Software and the proprietary code therein, not limited to but including designs, components, classes, and patterns, may not be reused in other projects without the express written consent of Wireable, LLC.
12+
13+
Follow the law. All use of the Software shall not violate any applicable law or regulation, nor infringe the rights of any other person or entity.
14+
15+
Failure to comply with the foregoing conditions will automatically and immediately result in termination of the permission granted hereby. This license does not include any right to receive updates to the Software or technical support. Licensees bear all risk related to the quality and performance of the Software and any modifications made or obtained to it, including liability for actual and consequential harm, such as loss or corruption of data, and any necessary service, repair, or correction.
16+
17+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, INCLUDING SPECIAL, INCIDENTAL AND CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Flux
2+
---
3+
The official UI component library for Livewire.

composer.json

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"name": "livewire/flux",
3+
"description": "The official UI component library for Livewire.",
4+
"keywords": ["flux", "laravel", "livewire", "components", "ui"],
5+
"license": "proprietary",
6+
"authors": [
7+
{
8+
"name": "Caleb Porzio",
9+
"email": "[email protected]"
10+
}
11+
],
12+
"require": {
13+
"php": "^8.1",
14+
"illuminate/console": "^11.9",
15+
"illuminate/support": "^11.9",
16+
"illuminate/view": "^11.9",
17+
"symfony/console": "^7.0",
18+
"livewire/livewire": "^3.5",
19+
"laravel/prompts": "^0.1.24"
20+
},
21+
"autoload": {
22+
"psr-4": {
23+
"Flux\\": "src/"
24+
}
25+
},
26+
"extra": {
27+
"laravel": {
28+
"providers": [
29+
"Flux\\FluxServiceProvider"
30+
],
31+
"aliases": {
32+
"Flux": "Flux\\Flux"
33+
}
34+
}
35+
}
36+
}

src/AssetManager.php

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
<?php
2+
3+
namespace Flux;
4+
5+
use Illuminate\Support\Facades\Route;
6+
use Illuminate\Support\Facades\Blade;
7+
use Illuminate\Http\Request;
8+
9+
class AssetManager
10+
{
11+
static function boot()
12+
{
13+
$instance = new static;
14+
15+
$instance->registerAssetDirective();
16+
$instance->registerAssetRoutes();
17+
}
18+
19+
public function registerAssetDirective()
20+
{
21+
Blade::directive('fluxStyles', function ($expression) {
22+
return <<<'PHP'
23+
{!! app('flux')->styles() !!}
24+
PHP;
25+
});
26+
27+
Blade::directive('fluxScripts', function ($expression) {
28+
return <<<'PHP'
29+
{!! app('flux')->scripts() !!}
30+
PHP;
31+
});
32+
}
33+
34+
public function registerAssetRoutes()
35+
{
36+
Route::get('/flux/flux.css', function () {
37+
return $this->pretendResponseIsFile(
38+
__DIR__.'/../../flux-pro/dist/flux.css', 'text/css'
39+
);
40+
});
41+
42+
Route::get('/flux/flux.js', function () {
43+
return $this->pretendResponseIsFile(
44+
__DIR__.'/../../flux-pro/dist/flux.js'
45+
);
46+
});
47+
48+
Route::get('/flux/flux.min.js', function () {
49+
return $this->pretendResponseIsFile(
50+
__DIR__.'/../../flux-pro/dist/flux.min.js'
51+
);
52+
});
53+
}
54+
55+
public static function scripts()
56+
{
57+
Flux::ensurePro();
58+
59+
$manifest = json_decode(file_get_contents(__DIR__.'/../../flux-pro/dist/manifest.json'), true);
60+
61+
$versionHash = $manifest['/flux.js'];
62+
63+
if (config('app.debug')) {
64+
return '<script src="/flux/flux.js?id='. $versionHash . '" data-navigate-once></script>';
65+
} else {
66+
return '<script src="/flux/flux.min.js?id='. $versionHash . '" data-navigate-once></script>';
67+
}
68+
}
69+
70+
public static function styles()
71+
{
72+
Flux::ensurePro();
73+
74+
$manifest = json_decode(file_get_contents(__DIR__.'/../../flux-pro/dist/manifest.json'), true);
75+
76+
$versionHash = $manifest['/flux.js'];
77+
78+
return '<link rel="stylesheet" href="/flux/flux.css?id='. $versionHash . '">';
79+
}
80+
81+
public function pretendResponseIsFile($file, $contentType = 'application/javascript; charset=utf-8')
82+
{
83+
$lastModified = filemtime($file);
84+
85+
return $this->cachedFileResponse($file, $contentType, $lastModified,
86+
fn ($headers) => response()->file($file, $headers));
87+
}
88+
89+
protected function cachedFileResponse($filename, $contentType, $lastModified, $downloadCallback)
90+
{
91+
$expires = strtotime('+1 year');
92+
$cacheControl = 'public, max-age=31536000';
93+
94+
if ($this->matchesCache($lastModified)) {
95+
return response('', 304, [
96+
'Expires' => $this->httpDate($expires),
97+
'Cache-Control' => $cacheControl,
98+
]);
99+
}
100+
101+
$headers = [
102+
'Content-Type' => $contentType,
103+
'Expires' => $this->httpDate($expires),
104+
'Cache-Control' => $cacheControl,
105+
'Last-Modified' => $this->httpDate($lastModified),
106+
];
107+
108+
if (str($filename)->endsWith('.br')) {
109+
$headers['Content-Encoding'] = 'br';
110+
}
111+
112+
return $downloadCallback($headers);
113+
}
114+
115+
protected function matchesCache($lastModified)
116+
{
117+
$ifModifiedSince = app(Request::class)->header('if-modified-since');
118+
119+
return $ifModifiedSince !== null && @strtotime($ifModifiedSince) === $lastModified;
120+
}
121+
122+
protected function httpDate($timestamp)
123+
{
124+
return sprintf('%s GMT', gmdate('D, d M Y H:i:s', $timestamp));
125+
}
126+
}

src/ClassBuilder.php

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace Flux;
4+
5+
use Illuminate\Support\Arr;
6+
use Stringable;
7+
8+
class ClassBuilder implements Stringable
9+
{
10+
protected $pending = [];
11+
12+
public function add($classes)
13+
{
14+
$this->pending[] = Arr::toCssClasses($classes);
15+
16+
return $this;
17+
}
18+
19+
public function __toString()
20+
{
21+
return (string) collect($this->pending)->join(' ');
22+
}
23+
}

src/Console/ActivateCommand.php

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<?php
2+
3+
namespace Flux\Console;
4+
5+
use function Laravel\Prompts\{ info, text, note, spin, warning, error, alert, intro, outro, suggest };
6+
use Symfony\Component\Console\Attribute\AsCommand;
7+
use Symfony\Component\Process\Process;
8+
use Illuminate\Support\Facades\Http;
9+
use Illuminate\Console\Command;
10+
use Illuminate\Support\Carbon;
11+
12+
#[AsCommand(name: 'flux:activate')]
13+
class ActivateCommand extends Command
14+
{
15+
protected $signature = 'flux:activate {key?}';
16+
17+
protected $description = 'Activate Flux, the official UI component library for Livewire';
18+
19+
public function handle()
20+
{
21+
$key = $this->argument('key');
22+
23+
if ($key) {
24+
$this->installFluxPro($key);
25+
} else {
26+
$key = text(
27+
label: 'Enter your license key',
28+
hint: 'Purchase a license key: https://fluxui.dev/pricing',
29+
required: true,
30+
);
31+
32+
$this->installFluxPro($key);
33+
}
34+
}
35+
36+
public function installFluxPro($key)
37+
{
38+
$hashKey = app('encrypter')->getKey();
39+
40+
$fingerprint = hash_hmac('sha256', json_encode($key), $hashKey);
41+
42+
$response = spin(
43+
message: 'Activating your license...',
44+
callback: fn () => Http::post('https://fluxui.dev/api/activate', [ 'key' => $key, 'fingerprint' => $fingerprint ]),
45+
);
46+
47+
if ($response->failed() && $response->json('error') === 'not-found') {
48+
warning('Invalid license key');
49+
note('Contact [email protected] for help');
50+
return;
51+
} elseif ($response->failed()) {
52+
$response->throw();
53+
alert('Failed to activate license');
54+
note('Contact [email protected] for help');
55+
return;
56+
}
57+
58+
$key = (string) $response->json('key');
59+
$email = (string) $response->json('email');
60+
$expiresAt = Carbon::parse($response->json('expires_at'));
61+
62+
if ($key === '' || $email === '') {
63+
error('Whoops, something went wrong. Either your license key or email is invalid.');
64+
note('Contact [email protected] for help');
65+
return;
66+
}
67+
68+
// Add creds to auth.json...
69+
$process = new Process([
70+
'composer', 'config', '-a',
71+
'http-basic.flux.composer.sh', $email, $key
72+
]);
73+
$process->run();
74+
75+
if (! $process->isSuccessful()) {
76+
echo "Failed to add license to auth.json. Console output: " . $process->getErrorOutput();
77+
note('Contact [email protected] for help');
78+
return;
79+
}
80+
81+
info('[√] License key added to auth.json');
82+
83+
// Add repository to composer.json...
84+
$process = new Process(['composer', 'config', 'repositories.flux', 'composer', 'https://flux.composer.sh']);
85+
$process->run();
86+
87+
if (! $process->isSuccessful()) {
88+
echo "Failed to add repository to composer.json. Console output: " . $process->getErrorOutput();
89+
note('Contact [email protected] for help');
90+
return;
91+
}
92+
93+
info('[√] Repository added to composer.json');
94+
95+
// Run composer require...
96+
note('Running: composer require livewire/flux...');
97+
98+
$process = new Process(['composer', 'require', 'livewire/flux']);
99+
$process->setTty(true);
100+
$process->setTimeout(null);
101+
102+
$process->run(function ($type, $buffer) {
103+
echo $buffer;
104+
});
105+
106+
if (! $process->isSuccessful()) {
107+
error("We are unable to install Flux automatically. Try running `composer require livewire/flux` manually.");
108+
note('Contact [email protected] for help');
109+
return;
110+
}
111+
112+
if ($expiresAt->isPast()) {
113+
note('');
114+
warning('This license has expired. You will need to purchase a new license to receive updates.');
115+
note('Extend your license here: https://fluxui.dev/licenses');
116+
}
117+
118+
note('');
119+
outro('Thanks for using Flux!');
120+
note('Your support is an investment in the future of Livewire ❤️');
121+
}
122+
}

src/Flux.php

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Flux;
4+
5+
use Illuminate\Support\Facades\Facade;
6+
7+
/**
8+
* @see \Livewire\FluxManager
9+
*/
10+
class Flux extends Facade
11+
{
12+
public static function getFacadeAccessor()
13+
{
14+
return 'flux';
15+
}
16+
}

0 commit comments

Comments
 (0)