44
55namespace Hyde \Console \Commands ;
66
7+ use Closure ;
78use Hyde \Console \Concerns \Command ;
8- use Illuminate \Support \Facades \Artisan ;
9-
9+ use Hyde \Console \Helpers \ConsoleHelper ;
10+ use Hyde \Console \Helpers \InteractivePublishCommandHelper ;
11+ use Hyde \Console \Helpers \ViewPublishGroup ;
12+ use Illuminate \Support \Str ;
13+ use Laravel \Prompts \Key ;
14+ use Laravel \Prompts \MultiSelectPrompt ;
15+ use Laravel \Prompts \SelectPrompt ;
16+
17+ use function Laravel \Prompts \select ;
1018use function str_replace ;
1119use function sprintf ;
1220use function strstr ;
@@ -20,78 +28,131 @@ class PublishViewsCommand extends Command
2028 protected $ signature = 'publish:views {category? : The category to publish} ' ;
2129
2230 /** @var string */
23- protected $ description = 'Publish the hyde components for customization. Note that existing files will be overwritten ' ;
24-
25- /** @var array<string, array<string, string>> */
26- protected array $ options = [
27- 'layouts ' => [
28- 'name ' => 'Blade Layouts ' ,
29- 'description ' => 'Shared layout views, such as the app layout, navigation menu, and Markdown page templates ' ,
30- 'group ' => 'hyde-layouts ' ,
31- ],
32- 'components ' => [
33- 'name ' => 'Blade Components ' ,
34- 'description ' => 'More or less self contained components, extracted for customizability and DRY code ' ,
35- 'group ' => 'hyde-components ' ,
36- ],
37- 'page-404 ' => [
38- 'name ' => '404 Page ' ,
39- 'description ' => 'A beautiful 404 error page by the Laravel Collective ' ,
40- 'group ' => 'hyde-page-404 ' ,
41- ],
42- ];
31+ protected $ description = 'Publish the Hyde components for customization. Note that existing files will be overwritten ' ;
32+
33+ /** @var array<string, \Hyde\Console\Helpers\ViewPublishGroup> */
34+ protected array $ options ;
4335
4436 public function handle (): int
4537 {
46- $ selected = (string ) ($ this ->argument ('category ' ) ?? $ this ->promptForCategory ());
38+ $ this ->options = static ::mapToKeys ([
39+ ViewPublishGroup::fromGroup ('hyde-layouts ' , 'Blade Layouts ' , 'Shared layout views, such as the app layout, navigation menu, and Markdown page templates ' ),
40+ ViewPublishGroup::fromGroup ('hyde-components ' , 'Blade Components ' , 'More or less self contained components, extracted for customizability and DRY code ' ),
41+ ]);
4742
48- if ($ selected === 'all ' || $ selected === '' ) {
49- foreach ($ this ->options as $ key => $ _ignored ) {
50- $ this ->publishOption ($ key );
51- }
52- } else {
53- $ this ->publishOption ($ selected );
43+ $ selected = ($ this ->argument ('category ' ) ?? $ this ->promptForCategory ()) ?: 'all ' ;
44+
45+ if ($ selected !== 'all ' && (bool ) $ this ->argument ('category ' ) === false && ConsoleHelper::canUseLaravelPrompts ($ this ->input )) {
46+ $ this ->infoComment (sprintf ('Selected category [%s] ' , $ selected ));
5447 }
5548
56- return Command::SUCCESS ;
57- }
49+ if (! in_array ($ selected , $ allowed = array_merge (['all ' ], array_keys ($ this ->options )), true )) {
50+ $ this ->error ("Invalid selection: ' $ selected' " );
51+ $ this ->infoComment ('Allowed values are: [ ' .implode (', ' , $ allowed ).'] ' );
5852
59- protected function publishOption (string $ selected ): void
60- {
61- Artisan::call ('vendor:publish ' , [
62- '--tag ' => $ this ->options [$ selected ]['group ' ] ?? $ selected ,
63- '--force ' => true ,
64- ], $ this ->output );
53+ return Command::FAILURE ;
54+ }
55+
56+ $ files = $ selected === 'all '
57+ ? collect ($ this ->options )->flatMap (fn (ViewPublishGroup $ option ): array => $ option ->publishableFilesMap ())->all ()
58+ : $ this ->options [$ selected ]->publishableFilesMap ();
59+
60+ $ publisher = $ this ->publishSelectedFiles ($ files , $ selected === 'all ' );
61+
62+ $ this ->infoComment ($ publisher ->formatOutput ($ selected ));
63+
64+ return Command::SUCCESS ;
6565 }
6666
6767 protected function promptForCategory (): string
6868 {
69- /** @var string $choice */
70- $ choice = $ this ->choice (
71- 'Which category do you want to publish? ' ,
72- $ this ->formatPublishableChoices (),
73- 0
69+ SelectPrompt::fallbackUsing (function (SelectPrompt $ prompt ): string {
70+ return $ this ->choice ($ prompt ->label , $ prompt ->options , $ prompt ->default );
71+ });
72+
73+ return $ this ->parseChoiceIntoKey (
74+ select ('Which category do you want to publish? ' , $ this ->formatPublishableChoices (), 0 ) ?: 'all '
7475 );
76+ }
7577
76- $ selection = $ this ->parseChoiceIntoKey ($ choice );
78+ protected function formatPublishableChoices (): array
79+ {
80+ return collect ($ this ->options )
81+ ->map (fn (ViewPublishGroup $ option , string $ key ): string => sprintf ('<comment>%s</comment>: %s ' , $ key , $ option ->description ))
82+ ->prepend ('Publish all categories listed below ' )
83+ ->values ()
84+ ->all ();
85+ }
7786
78- $ this ->infoComment (sprintf ("Selected category [%s] \n" , $ selection ?: 'all ' ));
87+ protected function parseChoiceIntoKey (string $ choice ): string
88+ {
89+ return strstr (str_replace (['<comment> ' , '</comment> ' ], '' , $ choice ), ': ' , true ) ?: '' ;
90+ }
7991
80- return $ selection ;
92+ /**
93+ * @param array<string, \Hyde\Console\Helpers\ViewPublishGroup> $groups
94+ * @return array<string, \Hyde\Console\Helpers\ViewPublishGroup>
95+ */
96+ protected static function mapToKeys (array $ groups ): array
97+ {
98+ return collect ($ groups )->mapWithKeys (function (ViewPublishGroup $ group ): array {
99+ return [Str::after ($ group ->group , 'hyde- ' ) => $ group ];
100+ })->all ();
81101 }
82102
83- protected function formatPublishableChoices (): array
103+ /** @param array<string, string> $files */
104+ protected function publishSelectedFiles (array $ files , bool $ isPublishingAll ): InteractivePublishCommandHelper
84105 {
85- $ keys = ['Publish all categories listed below ' ];
86- foreach ($ this ->options as $ key => $ option ) {
87- $ keys [] = "<comment> $ key</comment>: {$ option ['description ' ]}" ;
106+ $ publisher = new InteractivePublishCommandHelper ($ files );
107+
108+ if (! $ isPublishingAll && ConsoleHelper::canUseLaravelPrompts ($ this ->input )) {
109+ $ publisher ->only ($ this ->promptUserForWhichFilesToPublish ($ publisher ->getFileChoices ()));
88110 }
89111
90- return $ keys ;
112+ $ publisher ->publishFiles ();
113+
114+ return $ publisher ;
91115 }
92116
93- protected function parseChoiceIntoKey (string $ choice ): string
117+ /**
118+ * @param array<string, string> $files
119+ * @return array<string>
120+ */
121+ protected function promptUserForWhichFilesToPublish (array $ files ): array
94122 {
95- return strstr (str_replace (['<comment> ' , '</comment> ' ], '' , $ choice ), ': ' , true ) ?: '' ;
123+ $ choices = array_merge (['all ' => '<comment>All files</comment> ' ], $ files );
124+
125+ $ prompt = new MultiSelectPrompt ('Select the files you want to publish ' , $ choices , [], 10 , 'required ' , hint: 'Navigate with arrow keys, space to select, enter to confirm. ' );
126+
127+ $ prompt ->on ('key ' , static ::supportTogglingAll ($ prompt ));
128+
129+ return (array ) $ prompt ->prompt ();
130+ }
131+
132+ protected static function supportTogglingAll (MultiSelectPrompt $ prompt ): Closure
133+ {
134+ return function (string $ key ) use ($ prompt ): void {
135+ static $ isToggled = false ;
136+
137+ if ($ prompt ->isHighlighted ('all ' )) {
138+ if ($ key === Key::SPACE ) {
139+ $ prompt ->emit ('key ' , Key::CTRL_A );
140+
141+ if ($ isToggled ) {
142+ // We need to emit CTRL+A twice to deselect all for some reason
143+ $ prompt ->emit ('key ' , Key::CTRL_A );
144+ $ isToggled = false ;
145+ } else {
146+ $ isToggled = true ;
147+ }
148+ } elseif ($ key === Key::ENTER ) {
149+ if (! $ isToggled ) {
150+ $ prompt ->emit ('key ' , Key::CTRL_A );
151+ }
152+
153+ $ prompt ->state = 'submit ' ;
154+ }
155+ }
156+ };
96157 }
97158}
0 commit comments