diff --git a/src/Phaseolies/Console/Commands/FrontendInstallCommand.php b/src/Phaseolies/Console/Commands/FrontendInstallCommand.php index bed3439..e3959b1 100644 --- a/src/Phaseolies/Console/Commands/FrontendInstallCommand.php +++ b/src/Phaseolies/Console/Commands/FrontendInstallCommand.php @@ -46,7 +46,7 @@ public function handle(): int $framework = strtolower($this->choice( 'Which client framework do you want to use?', - ['Vanilla', 'React', 'Vue', 'Svelte'], + ['Vanilla', 'React', 'Vue', 'Svelte', 'htmx'], 0 )); @@ -148,7 +148,7 @@ protected function writeFrontendFiles(array $options, array &$state): void base_path('package.json') => $this->packageJson($framework, $cssStack, $typescript), base_path('vite.config.js') => $this->viteConfig($framework, $typescript), client_path('css/app.css') => $this->clientCss($cssStack), - client_path('js/' . $this->bootstrapFilename($typescript)) => $this->bootstrapFile($cssStack, $typescript), + client_path('js/' . $this->bootstrapFilename($typescript)) => $this->bootstrapFile($cssStack, $typescript, $framework), client_path('js/' . $this->entryFilename($framework, $typescript)) => $this->entryFile($framework, $cssStack, $typescript), base_path('resources/views/layouts/app.odo.php') => $this->appLayoutView($framework, $typescript), base_path('resources/views/welcome.odo.php') => $this->welcomeView($framework, $typescript), @@ -320,7 +320,7 @@ protected function entryFilename(string $framework, bool $typescript): string return $typescript ? 'main.tsx' : 'main.jsx'; } - if (in_array($framework, ['vue', 'svelte'], true)) { + if (in_array($framework, ['vue', 'svelte', 'htmx'], true)) { return $typescript ? 'main.ts' : 'main.js'; } @@ -362,6 +362,10 @@ protected function packageJson(string $framework, string $cssStack, bool $typesc $dependencies['bootstrap'] = '^5.3.3'; } + if ($framework === 'htmx') { + $dependencies['htmx.org'] = '^2.0.9'; + } + if ($cssStack === 'tailwind') { $devDependencies['postcss'] = '^8.4.49'; $devDependencies['tailwindcss'] = '^4.0.0'; @@ -475,18 +479,23 @@ protected function frameworkComponentFiles(string $framework, bool $typescript): * * @param string $cssStack * @param bool $typescript + * @param string $framework * @return string */ - protected function bootstrapFile(string $cssStack, bool $typescript): string + protected function bootstrapFile(string $cssStack, bool $typescript, string $framework = 'vanilla'): string { $bootstrapVendorImport = $cssStack === 'bootstrap' ? "import 'bootstrap/dist/js/bootstrap.bundle.min.js';\n" : ''; + $htmxVendorImport = $framework === 'htmx' + ? "import 'htmx.org';\n" + : ''; return $this->renderFrontendStub( 'entries/' . ($typescript ? 'bootstrap.ts.stub' : 'bootstrap.js.stub'), [ 'bootstrapVendorImport' => $bootstrapVendorImport, + 'htmxVendorImport' => $htmxVendorImport, ] ); } diff --git a/src/Phaseolies/Console/Commands/FrontendUninstallCommand.php b/src/Phaseolies/Console/Commands/FrontendUninstallCommand.php index b348549..8bf6878 100644 --- a/src/Phaseolies/Console/Commands/FrontendUninstallCommand.php +++ b/src/Phaseolies/Console/Commands/FrontendUninstallCommand.php @@ -319,6 +319,7 @@ protected function isGeneratedPackageJson(string $contents): bool 'react-dom', 'vue', 'svelte', + 'htmx.org', 'bootstrap', 'postcss', 'tailwindcss', @@ -399,4 +400,5 @@ protected function isGeneratedPostcssConfig(string $contents): bool return str_contains($contents, "export default") && str_contains($contents, "'@tailwindcss/postcss': {}"); } + } diff --git a/src/Phaseolies/Console/Commands/stubs/frontend/entries/bootstrap.js.stub b/src/Phaseolies/Console/Commands/stubs/frontend/entries/bootstrap.js.stub index df24346..e9f5ac7 100644 --- a/src/Phaseolies/Console/Commands/stubs/frontend/entries/bootstrap.js.stub +++ b/src/Phaseolies/Console/Commands/stubs/frontend/entries/bootstrap.js.stub @@ -7,3 +7,4 @@ window.__DOPPAR_FRONTEND__ = { csrfToken: csrfToken ?? null, headers: csrfToken ? { 'X-CSRF-TOKEN': csrfToken } : {}, }; +{{ htmxVendorImport }} diff --git a/src/Phaseolies/Console/Commands/stubs/frontend/entries/bootstrap.ts.stub b/src/Phaseolies/Console/Commands/stubs/frontend/entries/bootstrap.ts.stub index ab834fc..226c945 100644 --- a/src/Phaseolies/Console/Commands/stubs/frontend/entries/bootstrap.ts.stub +++ b/src/Phaseolies/Console/Commands/stubs/frontend/entries/bootstrap.ts.stub @@ -16,3 +16,4 @@ declare global { }; } } +{{ htmxVendorImport }} diff --git a/tests/Console/FrontendInstallCommandTest.php b/tests/Console/FrontendInstallCommandTest.php index e7ce21a..c67026d 100644 --- a/tests/Console/FrontendInstallCommandTest.php +++ b/tests/Console/FrontendInstallCommandTest.php @@ -97,7 +97,7 @@ public function testClientBootstrapExposesCsrfHeaderFromMetaToken(): void $command = new FrontendInstallCommand(); $method = new \ReflectionMethod($command, 'bootstrapFile'); - $bootstrap = $method->invoke($command, 'bootstrap', true); + $bootstrap = $method->invoke($command, 'bootstrap', 'vanilla', true); $this->assertStringContainsString("meta[name=\"csrf-token\"]", $bootstrap); $this->assertStringContainsString("headers: csrfToken ? { 'X-CSRF-TOKEN': csrfToken } : {}", $bootstrap);