Skip to content

Commit b6699fd

Browse files
author
Thomas Hauschild
committed
feat: add ThemeWatchCommand
1 parent baa7d4b commit b6699fd

File tree

6 files changed

+144
-0
lines changed

6 files changed

+144
-0
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenForgeProject\MageForge\Console\Command;
6+
7+
use Laravel\Prompts\SelectPrompt;
8+
use OpenForgeProject\MageForge\Model\ThemeList;
9+
use OpenForgeProject\MageForge\Service\ThemeBuilder\BuilderPool;
10+
use Symfony\Component\Console\Command\Command;
11+
use Symfony\Component\Console\Input\InputInterface;
12+
use Symfony\Component\Console\Input\InputOption;
13+
use Symfony\Component\Console\Output\OutputInterface;
14+
use Symfony\Component\Console\Style\SymfonyStyle;
15+
use OpenForgeProject\MageForge\Model\ThemePath;
16+
17+
class ThemeWatchCommand extends Command
18+
{
19+
public function __construct(
20+
private readonly BuilderPool $builderPool,
21+
private readonly ThemeList $themeList,
22+
private readonly ThemePath $themePath,
23+
) {
24+
parent::__construct();
25+
}
26+
27+
protected function configure()
28+
{
29+
$this->setName('mageforge:theme:watch')
30+
->setDescription('Watches theme files for changes and rebuilds them automatically')
31+
->addOption(
32+
'theme',
33+
't',
34+
InputOption::VALUE_OPTIONAL,
35+
'Theme to watch (format: Vendor/theme)'
36+
)
37+
->setAliases(['frontend:watch']);
38+
}
39+
40+
protected function execute(InputInterface $input, OutputInterface $output): int
41+
{
42+
$io = new SymfonyStyle($input, $output);
43+
$themeCode = $input->getOption('theme');
44+
45+
if (empty($themeCode)) {
46+
$themes = $this->themeList->getAllThemes();
47+
$options = array_map(fn($theme) => $theme->getCode(), $themes);
48+
49+
50+
$themeCodePrompt = new SelectPrompt(
51+
label: 'Select theme to build',
52+
options: $options,
53+
scroll: 10,
54+
hint: 'Arrow keys to navigate, Space to select, Enter to confirm',
55+
);
56+
57+
$themeCode = $themeCodePrompt->prompt();
58+
}
59+
60+
try {
61+
$themePath = $this->themePath->getPath($themeCode);
62+
if ($themePath === null) {
63+
$io->error("Theme $themeCode is not installed.");
64+
return Command::FAILURE;
65+
}
66+
67+
$builder = $this->builderPool->getBuilder($themePath);
68+
return $builder->watch($themePath, $io, $output, true) ? Command::SUCCESS : Command::FAILURE;
69+
} catch (\Exception $e) {
70+
$io->error('Error: ' . $e->getMessage());
71+
return Command::FAILURE;
72+
}
73+
}
74+
}

src/Service/ThemeBuilder/BuilderInterface.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ public function detect(string $themePath): bool;
1313
public function build(string $themePath, SymfonyStyle $io, OutputInterface $output, bool $isVerbose): bool;
1414
public function getName(): string;
1515
public function autoRepair(string $themePath, SymfonyStyle $io, OutputInterface $output, bool $isVerbose): bool;
16+
public function watch(string $themePath, SymfonyStyle $io, OutputInterface $output, bool $isVerbose): bool;
1617
}

src/Service/ThemeBuilder/HyvaThemes/Builder.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,29 @@ public function autoRepair(string $themePath, SymfonyStyle $io, OutputInterface
165165
return true;
166166
}
167167

168+
public function watch(string $themePath, SymfonyStyle $io, OutputInterface $output, bool $isVerbose): bool
169+
{
170+
if (!$this->detect($themePath)) {
171+
return false;
172+
}
173+
174+
$tailwindPath = rtrim($themePath, '/') . '/web/tailwind';
175+
if (!$this->fileDriver->isDirectory($tailwindPath)) {
176+
$io->error("Tailwind directory not found in: $tailwindPath");
177+
return false;
178+
}
179+
180+
try {
181+
chdir($tailwindPath);
182+
exec('npm run watch');
183+
} catch (\Exception $e) {
184+
$io->error('Failed to start watch mode: ' . $e->getMessage());
185+
return false;
186+
}
187+
188+
return true;
189+
}
190+
168191
public function getName(): string
169192
{
170193
return self::THEME_NAME;

src/Service/ThemeBuilder/MagentoStandard/Builder.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,26 @@ public function autoRepair(string $themePath, SymfonyStyle $io, OutputInterface
131131
return true;
132132
}
133133

134+
public function watch(string $themePath, SymfonyStyle $io, OutputInterface $output, bool $isVerbose): bool
135+
{
136+
if (!$this->detect($themePath)) {
137+
return false;
138+
}
139+
140+
if (!$this->autoRepair($themePath, $io, $output, $isVerbose)) {
141+
return false;
142+
}
143+
144+
try {
145+
exec('node_modules/.bin/grunt watch');
146+
} catch (\Exception $e) {
147+
$io->error('Failed to start watch mode: ' . $e->getMessage());
148+
return false;
149+
}
150+
151+
return true;
152+
}
153+
134154
public function getName(): string
135155
{
136156
return self::THEME_NAME;

src/Service/ThemeBuilder/TailwindCSS/Builder.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,4 +159,27 @@ public function getName(): string
159159
{
160160
return self::THEME_NAME;
161161
}
162+
163+
public function watch(string $themePath, SymfonyStyle $io, OutputInterface $output, bool $isVerbose): bool
164+
{
165+
if (!$this->detect($themePath)) {
166+
return false;
167+
}
168+
169+
$tailwindPath = rtrim($themePath, '/') . '/web/tailwind';
170+
if (!$this->fileDriver->isDirectory($tailwindPath)) {
171+
$io->error("Tailwind directory not found in: $tailwindPath");
172+
return false;
173+
}
174+
175+
try {
176+
chdir($tailwindPath);
177+
exec('npx tailwind -i ./src/css/input.css -o ./web/css/styles.css --watch');
178+
} catch (\Exception $e) {
179+
$io->error('Failed to start watch mode: ' . $e->getMessage());
180+
return false;
181+
}
182+
183+
return true;
184+
}
162185
}

src/etc/di.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
name="mageforge_theme_build"
2626
xsi:type="object"
2727
>OpenForgeProject\MageForge\Console\Command\BuildThemeCommand</item>
28+
<item name="mageforge_theme_watch"
29+
xsi:type="object"
30+
>OpenForgeProject\MageForge\Console\Command\ThemeWatchCommand</item>
2831
</argument>
2932
</arguments>
3033
</type>

0 commit comments

Comments
 (0)