Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React installation option #73

Merged
merged 19 commits into from
May 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 105 additions & 23 deletions src/Console/InstallCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ class InstallCommand extends Command
*
* @var string
*/
protected $signature = 'breeze:install
{--inertia : Indicates that the Inertia stack should be installed}
protected $signature = 'breeze:install {stack=blade : The development stack that should be installed}
{--composer=global : Absolute path to the Composer binary which should be used to install packages}';

/**
Expand All @@ -32,8 +31,12 @@ class InstallCommand extends Command
*/
public function handle()
{
if ($this->option('inertia')) {
return $this->installInertiaStack();
if ($this->argument('stack') === 'vue') {
return $this->installInertiaVueStack();
}

if ($this->argument('stack') === 'react') {
return $this->installInertiaReactStack();
}

// NPM Packages...
Expand Down Expand Up @@ -94,11 +97,11 @@ public function handle()
}

/**
* Install the Inertia Breeze stack.
* Install the Inertia Vue Breeze stack.
*
* @return void
*/
protected function installInertiaStack()
protected function installInertiaVueStack()
{
// Install Inertia...
$this->requireComposerPackages('inertiajs/inertia-laravel:^0.4.1', 'laravel/sanctum:^2.6', 'tightenco/ziggy:^1.0');
Expand All @@ -112,17 +115,17 @@ protected function installInertiaStack()
'@tailwindcss/forms' => '^0.2.1',
'@vue/compiler-sfc' => '^3.0.5',
'autoprefixer' => '^10.2.4',
'postcss' => '^8.2.1',
'postcss-import' => '^12.0.1',
'tailwindcss' => '^2.0.3',
'postcss' => '^8.2.13',
'postcss-import' => '^14.0.1',
'tailwindcss' => '^2.1.2',
'vue' => '^3.0.5',
'vue-loader' => '^16.1.2',
] + $packages;
});

// Controllers...
(new Filesystem)->ensureDirectoryExists(app_path('Http/Controllers/Auth'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/inertia/app/Http/Controllers/Auth', app_path('Http/Controllers/Auth'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/inertia-common/app/Http/Controllers/Auth', app_path('Http/Controllers/Auth'));

// Requests...
(new Filesystem)->ensureDirectoryExists(app_path('Http/Requests/Auth'));
Expand All @@ -131,39 +134,118 @@ protected function installInertiaStack()
// Middleware...
$this->installMiddlewareAfter('SubstituteBindings::class', '\App\Http\Middleware\HandleInertiaRequests::class');

copy(__DIR__.'/../../stubs/inertia/app/Http/Middleware/HandleInertiaRequests.php', app_path('Http/Middleware/HandleInertiaRequests.php'));
copy(__DIR__.'/../../stubs/inertia-common/app/Http/Middleware/HandleInertiaRequests.php', app_path('Http/Middleware/HandleInertiaRequests.php'));

// Views...
copy(__DIR__.'/../../stubs/inertia/resources/views/app.blade.php', resource_path('views/app.blade.php'));
copy(__DIR__.'/../../stubs/inertia-common/resources/views/app.blade.php', resource_path('views/app.blade.php'));

// Components + Pages...
(new Filesystem)->ensureDirectoryExists(resource_path('js/Components'));
(new Filesystem)->ensureDirectoryExists(resource_path('js/Layouts'));
(new Filesystem)->ensureDirectoryExists(resource_path('js/Pages'));

(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/inertia/resources/js/Components', resource_path('js/Components'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/inertia/resources/js/Layouts', resource_path('js/Layouts'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/inertia/resources/js/Pages', resource_path('js/Pages'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/inertia-vue/resources/js/Components', resource_path('js/Components'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/inertia-vue/resources/js/Layouts', resource_path('js/Layouts'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/inertia-vue/resources/js/Pages', resource_path('js/Pages'));

// Tests...
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/default/tests/Feature', base_path('tests/Feature'));

// Routes...
copy(__DIR__.'/../../stubs/inertia/routes/web.php', base_path('routes/web.php'));
copy(__DIR__.'/../../stubs/inertia/routes/auth.php', base_path('routes/auth.php'));
copy(__DIR__.'/../../stubs/inertia-common/routes/web.php', base_path('routes/web.php'));
copy(__DIR__.'/../../stubs/inertia-common/routes/auth.php', base_path('routes/auth.php'));

// "Dashboard" Route...
$this->replaceInFile('/home', '/dashboard', resource_path('js/Pages/Welcome.vue'));
$this->replaceInFile('Home', 'Dashboard', resource_path('js/Pages/Welcome.vue'));
$this->replaceInFile('/home', '/dashboard', app_path('Providers/RouteServiceProvider.php'));

// Tailwind / Webpack...
copy(__DIR__.'/../../stubs/inertia/tailwind.config.js', base_path('tailwind.config.js'));
copy(__DIR__.'/../../stubs/inertia/webpack.mix.js', base_path('webpack.mix.js'));
copy(__DIR__.'/../../stubs/inertia/webpack.config.js', base_path('webpack.config.js'));
copy(__DIR__.'/../../stubs/inertia/jsconfig.json', base_path('jsconfig.json'));
copy(__DIR__.'/../../stubs/inertia/resources/css/app.css', resource_path('css/app.css'));
copy(__DIR__.'/../../stubs/inertia/resources/js/app.js', resource_path('js/app.js'));
copy(__DIR__.'/../../stubs/inertia-common/tailwind.config.js', base_path('tailwind.config.js'));
copy(__DIR__.'/../../stubs/inertia-common/webpack.mix.js', base_path('webpack.mix.js'));
copy(__DIR__.'/../../stubs/inertia-common/webpack.config.js', base_path('webpack.config.js'));
copy(__DIR__.'/../../stubs/inertia-common/jsconfig.json', base_path('jsconfig.json'));
copy(__DIR__.'/../../stubs/inertia-common/resources/css/app.css', resource_path('css/app.css'));
copy(__DIR__.'/../../stubs/inertia-vue/resources/js/app.js', resource_path('js/app.js'));

$this->info('Breeze scaffolding installed successfully.');
$this->comment('Please execute the "npm install && npm run dev" command to build your assets.');
}

/**
* Install the Inertia React Breeze stack.
*
* @return void
*/
protected function installInertiaReactStack()
{
// Install Inertia...
$this->requireComposerPackages('inertiajs/inertia-laravel:^0.3.5', 'laravel/sanctum:^2.6', 'tightenco/ziggy:^1.0');

// NPM Packages...
$this->updateNodePackages(function ($packages) {
return [
'@headlessui/react' => '^1.2.0',
'@inertiajs/inertia' => '^0.8.4',
'@inertiajs/inertia-react' => '^0.5.12',
'@inertiajs/progress' => '^0.2.4',
'@tailwindcss/forms' => '^0.3.2',
'autoprefixer' => '^10.2.4',
'postcss' => '^8.2.13',
'postcss-import' => '^14.0.1',
'tailwindcss' => '^2.1.2',
'react' => '^17.0.2',
'react-dom' => '^17.0.2',
'@babel/preset-react' => '^7.13.13',
] + $packages;
});

// Controllers...
(new Filesystem)->ensureDirectoryExists(app_path('Http/Controllers/Auth'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/inertia-common/app/Http/Controllers/Auth', app_path('Http/Controllers/Auth'));

// Requests...
(new Filesystem)->ensureDirectoryExists(app_path('Http/Requests/Auth'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/default/App/Http/Requests/Auth', app_path('Http/Requests/Auth'));

// Middleware...
$this->installMiddlewareAfter('SubstituteBindings::class', '\App\Http\Middleware\HandleInertiaRequests::class');

copy(__DIR__.'/../../stubs/inertia-common/app/Http/Middleware/HandleInertiaRequests.php', app_path('Http/Middleware/HandleInertiaRequests.php'));

// Views...
copy(__DIR__.'/../../stubs/inertia-common/resources/views/app.blade.php', resource_path('views/app.blade.php'));

// Components + Pages...
(new Filesystem)->ensureDirectoryExists(resource_path('js/Components'));
(new Filesystem)->ensureDirectoryExists(resource_path('js/Layouts'));
(new Filesystem)->ensureDirectoryExists(resource_path('js/Pages'));

(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/inertia-react/resources/js/Components', resource_path('js/Components'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/inertia-react/resources/js/Layouts', resource_path('js/Layouts'));
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/inertia-react/resources/js/Pages', resource_path('js/Pages'));

// Tests...
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/default/tests/Feature', base_path('tests/Feature'));

// Routes...
copy(__DIR__.'/../../stubs/inertia-common/routes/web.php', base_path('routes/web.php'));
copy(__DIR__.'/../../stubs/inertia-common/routes/auth.php', base_path('routes/auth.php'));

// "Dashboard" Route...
$this->replaceInFile('/home', '/dashboard', resource_path('js/Pages/Welcome.js'));
$this->replaceInFile('Home', 'Dashboard', resource_path('js/Pages/Welcome.js'));
$this->replaceInFile('/home', '/dashboard', app_path('Providers/RouteServiceProvider.php'));

// Tailwind / Webpack...
copy(__DIR__.'/../../stubs/inertia-common/tailwind.config.js', base_path('tailwind.config.js'));
copy(__DIR__.'/../../stubs/inertia-common/webpack.mix.js', base_path('webpack.mix.js'));
copy(__DIR__.'/../../stubs/inertia-common/webpack.config.js', base_path('webpack.config.js'));
copy(__DIR__.'/../../stubs/inertia-common/jsconfig.json', base_path('jsconfig.json'));
copy(__DIR__.'/../../stubs/inertia-common/resources/css/app.css', resource_path('css/app.css'));
copy(__DIR__.'/../../stubs/inertia-react/resources/js/app.js', resource_path('js/app.js'));

$this->replaceInFile('.vue()', '.react()', base_path('webpack.mix.js'));

$this->info('Breeze scaffolding installed successfully.');
$this->comment('Please execute the "npm install && npm run dev" command to build your assets.');
Expand Down
2 changes: 1 addition & 1 deletion stubs/default/resources/views/auth/verify-email.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
@csrf

<button type="submit" class="underline text-sm text-gray-600 hover:text-gray-900">
{{ __('Log out') }}
{{ __('Log Out') }}
</button>
</form>
</div>
Expand Down
4 changes: 2 additions & 2 deletions stubs/default/resources/views/layouts/navigation.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
<x-dropdown-link :href="route('logout')"
onclick="event.preventDefault();
this.closest('form').submit();">
{{ __('Log out') }}
{{ __('Log Out') }}
</x-dropdown-link>
</form>
</x-slot>
Expand Down Expand Up @@ -91,7 +91,7 @@
<x-responsive-nav-link :href="route('logout')"
onclick="event.preventDefault();
this.closest('form').submit();">
{{ __('Log out') }}
{{ __('Log Out') }}
</x-responsive-nav-link>
</form>
</div>
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions stubs/inertia-react/resources/js/Components/Button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';

export default function Button({ type = 'submit', className = '', processing, children }) {
return (
<button
type={type}
className={
`inline-flex items-center px-4 py-2 bg-gray-900 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest active:bg-gray-900 transition ease-in-out duration-150 ${
processing && 'opacity-25'
} ` + className
}
disabled={processing}
>
{children}
</button>
);
}
13 changes: 13 additions & 0 deletions stubs/inertia-react/resources/js/Components/Checkbox.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';

export default function Checkbox({ name, value, handleChange }) {
return (
<input
type="checkbox"
name={name}
value={value}
className="rounded border-gray-300 text-indigo-600 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
onChange={(e) => handleChange(e)}
/>
);
}
93 changes: 93 additions & 0 deletions stubs/inertia-react/resources/js/Components/Dropdown.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import React, { useState, useContext } from 'react';
import { InertiaLink } from '@inertiajs/inertia-react';
import { Transition } from '@headlessui/react';

const DropDownContext = React.createContext();

const Dropdown = ({ children }) => {
const [open, setOpen] = useState(false);

const toggleOpen = () => {
setOpen((previousState) => !previousState);
};

return (
<DropDownContext.Provider value={{ open, setOpen, toggleOpen }}>
<div className="relative">{children}</div>
</DropDownContext.Provider>
);
};

const Trigger = ({ children }) => {
const { open, setOpen, toggleOpen } = useContext(DropDownContext);

return (
<>
<div onClick={toggleOpen}>{children}</div>

{open && <div className="fixed inset-0 z-40" onClick={() => setOpen(false)}></div>}
</>
);
};

const Content = ({ align = 'right', width = '48', contentClasses = 'py-1 bg-white', children }) => {
const { open, setOpen } = useContext(DropDownContext);

let alignmentClasses = 'origin-top';

if (align === 'left') {
alignmentClasses = 'origin-top-left left-0';
} else if (align === 'right') {
alignmentClasses = 'origin-top-right right-0';
}

let widthClasses = '';

if (width === '48') {
widthClasses = 'w-48';
}

return (
<>
<Transition
show={open}
enter="transition ease-out duration-200"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
{open && (
<div
className={`absolute z-50 mt-2 rounded-md shadow-lg ${alignmentClasses} ${widthClasses}`}
onClick={() => setOpen(false)}
>
<div className={`rounded-md ring-1 ring-black ring-opacity-5 ` + contentClasses}>
{children}
</div>
</div>
)}
</Transition>
</>
);
};

const Link = ({ href, method = 'post', as = 'a', children }) => {
return (
<InertiaLink
href={href}
method={method}
as={as}
className="block w-full px-4 py-2 text-left text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out"
>
{children}
</InertiaLink>
);
};

Dropdown.Trigger = Trigger;
Dropdown.Content = Content;
Dropdown.Link = Link;

export default Dropdown;
9 changes: 9 additions & 0 deletions stubs/inertia-react/resources/js/Components/Label.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react';

export default function Label({ forInput, value, className, children }) {
return (
<label htmlFor={forInput} className={`block font-medium text-sm text-gray-700 ` + className}>
{value ? value : { children }}
</label>
);
}
17 changes: 17 additions & 0 deletions stubs/inertia-react/resources/js/Components/NavLink.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { InertiaLink } from '@inertiajs/inertia-react';
import React from 'react';

export default function NavLink({ href, active, children }) {
return (
<InertiaLink
href={href}
className={
active
? 'inline-flex items-center px-1 pt-1 border-b-2 border-indigo-400 text-sm font-medium leading-5 text-gray-900 focus:outline-none focus:border-indigo-700 transition duration-150 ease-in-out'
: 'inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out'
}
>
{children}
</InertiaLink>
);
}
Loading