diff --git a/composer.json b/composer.json index 5ae5967..95701b8 100644 --- a/composer.json +++ b/composer.json @@ -21,6 +21,7 @@ "illuminate/contracts": "^10.0||^11.0", "laravel/folio": "^v1.0", "laravel/prompts": "^0.1", + "laravel/scout": "^v10.9", "tempest/highlight": "2.0" }, "require-dev": { diff --git a/config/docsidian.php.stub b/config/docsidian.php.stub index 709ae4f..11d15e9 100644 --- a/config/docsidian.php.stub +++ b/config/docsidian.php.stub @@ -2,17 +2,11 @@ return [ 'installed' => true, - // You can define as many documentation sites as you want below. Just make sure that each has unique paths and uri. - 'sites' => [ - 'default' => [ - 'default_visibility' => '{{ default_visibility }}', - 'folio_middleware' => ['web'], - 'folio_path' => resource_path('{{ folio_path }}'), - 'folio_uri' => '{{ folio_uri }}', - 'layout' => 'docsidian', - 'md_path' => base_path('{{ md_path }}'), - 'md_repo' => 'artisan-build/docsidian-docs', // Only applies to hosted docs - ], - ], - + 'default_visibility' => '{{ default_visibility }}', + 'folio_middleware' => ['web'], + 'folio_path' => resource_path('{{ folio_path }}'), + 'folio_uri' => '{{ folio_uri }}', + 'layout' => 'docsidian', + 'md_path' => base_path('{{ md_path }}'), + 'obsidian_config' => base_path('{{ md_path }}/.obsidian') ]; diff --git a/database/factories/ModelFactory.php b/database/factories/DocsidianPageFactory.php similarity index 58% rename from database/factories/ModelFactory.php rename to database/factories/DocsidianPageFactory.php index 4556512..0224898 100644 --- a/database/factories/ModelFactory.php +++ b/database/factories/DocsidianPageFactory.php @@ -2,12 +2,13 @@ namespace ArtisanBuild\Docsidian\Database\Factories; +use ArtisanBuild\Docsidian\Models\DocsidianPage; use Illuminate\Database\Eloquent\Factories\Factory; -/* -class ModelFactory extends Factory + +class DocsidianPageFactory extends Factory { - protected $model = YourModel::class; + protected $model = DocsidianPage::class; public function definition() { @@ -16,4 +17,3 @@ public function definition() ]; } } -*/ diff --git a/database/factories/DocsidianSiteFactory.php b/database/factories/DocsidianSiteFactory.php new file mode 100644 index 0000000..6c6b8e5 --- /dev/null +++ b/database/factories/DocsidianSiteFactory.php @@ -0,0 +1,19 @@ +id(); + $table->string('name'); + $table->string('description')->nullable(); + $table->string('image')->nullable(); + $table->unsignedInteger('weight')->nullable(); + $table->string('status')->default(SiteStatus::Hidden->name); + $table->string('default_visibility')->default('public'); + $table->json('folio_middleware'); + $table->string('folio_path'); + $table->string('folio_uri'); + $table->string('layout'); + $table->string('md_path'); + $table->string('obsidian_config'); - // add fields + /* + * 'folio_middleware' => ['web'], + 'folio_path' => resource_path('views/docs'), + 'folio_uri' => 'docs', + 'layout' => 'docsidian', + 'md_path' => base_path('documentation'), + 'md_repo' => 'artisan-build/docsidian-docs', + */ + $table->timestamps(); + }); + Schema::create('docsidian_pages', function (Blueprint $table) { + $table->id(); + $table->foreignIdFor(DocsidianSite::class); + $table->string('uri'); + $table->text('public')->nullable(); + $table->text('protected')->nullable(); + $table->text('private')->nullable(); $table->timestamps(); }); } diff --git a/src/Commands/DiscoverCommand.php b/src/Commands/DiscoverCommand.php new file mode 100644 index 0000000..224ec6a --- /dev/null +++ b/src/Commands/DiscoverCommand.php @@ -0,0 +1,56 @@ +argument('directory') ?? config('docsidian.md_path')); + + foreach ($directories as $directory) { + if (DocsidianSite::where('md_path', $directory)->exists()) { + continue; + } + $key = last(explode(DIRECTORY_SEPARATOR, $directory)); + $site = DocsidianSite::create([ + 'name' => $this->generateName($key), + 'description' => null, + 'image' => null, + 'weight' => (DocsidianSite::max('weight') ?? 0) + 100, + 'status' => SiteStatus::Hidden, + 'default_visibility' => config('docsidian.default_visibility'), + 'folio_middleware' => config('docsidian.folio_middleware'), + 'folio_path' => implode(DIRECTORY_SEPARATOR, [config('docsidian.folio_path'), $key]), + 'folio_uri' => implode('/', [config('docsidian.folio_uri'), $key]), + 'layout' => config('docsidian.layout'), + 'md_path' => $directory, + 'obsidian_config' => config('docsidian.obsidian_config'), + + ]); + + File::ensureDirectoryExists($site->folio_path); + + $this->info("Created record for {$key}"); + } + return self::SUCCESS; + } + + public function generateName(string $key): string + { + if (str_contains('.', $key)) { + return $key; + } + + return Str::headline($key); + } +} diff --git a/src/Commands/GenerateCommand.php b/src/Commands/GenerateCommand.php index 12f7dde..84ab230 100644 --- a/src/Commands/GenerateCommand.php +++ b/src/Commands/GenerateCommand.php @@ -19,6 +19,7 @@ use ArtisanBuild\Docsidian\Contracts\IndexesSiteForSearch; use ArtisanBuild\Docsidian\DocumentationSite; use ArtisanBuild\Docsidian\EmbeddedMedia; +use ArtisanBuild\Docsidian\Models\DocsidianSite; use Illuminate\Console\Command; use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\Pipeline; @@ -31,8 +32,10 @@ class GenerateCommand extends Command public function handle(): int { - foreach (config('docsidian.sites') as $key => $site) { - $this->info("Generating {$key}"); + foreach (DocsidianSite::all() as $site) { + $this->info("Generating {$site->name}"); + + $site = $site->toArray(); File::deleteDirectory($site['folio_path']); File::ensureDirectoryExists($site['folio_path']); diff --git a/src/Commands/InstallCommand.php b/src/Commands/InstallCommand.php index 9d07c97..eba9050 100644 --- a/src/Commands/InstallCommand.php +++ b/src/Commands/InstallCommand.php @@ -48,12 +48,18 @@ public function handle(): int $configContents = File::get(__DIR__.'/../../config/docsidian.php.stub'); - foreach (['md_path', 'folio_uri', 'folio_path'] as $key) { + foreach (['default_visibility', 'md_path', 'folio_uri', 'folio_path'] as $key) { $configContents = str_replace("{{ $key }}", $config[$key], $configContents); } File::put(config_path('docsidian.php'), $configContents); + $this->callSilently("vendor:publish", [ + '--tag' => "docsidian-migrations", + ]); + + $this->call('migrate'); + return self::SUCCESS; } } diff --git a/src/DocsidianServiceProvider.php b/src/DocsidianServiceProvider.php index 98cc2eb..c15cd97 100644 --- a/src/DocsidianServiceProvider.php +++ b/src/DocsidianServiceProvider.php @@ -5,13 +5,18 @@ use ArtisanBuild\Docsidian\Actions\DoNotIndexForSearch; use ArtisanBuild\Docsidian\Actions\GetDefinedAbilities; use ArtisanBuild\Docsidian\Actions\HighlightCodeWithTempest; +use ArtisanBuild\Docsidian\Commands\DiscoverCommand; use ArtisanBuild\Docsidian\Commands\GenerateCommand; use ArtisanBuild\Docsidian\Commands\InstallCommand; use ArtisanBuild\Docsidian\Contracts\HighlightsCodeBlocks; use ArtisanBuild\Docsidian\Contracts\IndexesSiteForSearch; +use ArtisanBuild\Docsidian\Models\DocsidianSite; +use Filament\Facades\Filament; use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Support\Facades\Blade; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Gate; +use Illuminate\Support\Facades\Schema; use Laravel\Folio\Folio; use Spatie\LaravelPackageTools\Package; use Spatie\LaravelPackageTools\PackageServiceProvider; @@ -30,14 +35,22 @@ public function configurePackage(Package $package): void ->hasConfigFile() ->hasViews() ->hasMigration('create_docsidian_table') - ->hasCommand(InstallCommand::class) - ->hasCommand(GenerateCommand::class); + ->hasCommands([ + InstallCommand::class, + GenerateCommand::class, + DiscoverCommand::class, + ]); } public function registeringPackage() { $this->app->bind(IndexesSiteForSearch::class, DoNotIndexForSearch::class); $this->app->bind(HighlightsCodeBlocks::class, HighlightCodeWithTempest::class); + + if (class_exists(Filament::class)) { + $this->app->register(\ArtisanBuild\Docsidian\DocumentationPanelProvider::class); + } + } public function packageBooted(): void @@ -46,12 +59,16 @@ public function packageBooted(): void return; } + if (! Schema::hasTable('docsidian_sites')) { + return; + } + Blade::component(DocsidianLayoutComponent::class, 'docsidian'); - foreach (config('docsidian.sites') as $site) { - Folio::path($site['folio_path']) - ->uri($site['folio_uri']) - ->middleware($site['folio_middleware']); + foreach (DocsidianSite::all() as $site) { + Folio::path($site->folio_path) + ->uri($site->folio_uri) + ->middleware($site->folio_middleware); } if (app(GetDefinedAbilities::class)()->isEmpty()) { @@ -59,6 +76,5 @@ public function packageBooted(): void Gate::define('docsidian-protected', fn (?Authenticatable $user) => $user instanceof Authenticatable); Gate::define('docsidian-private', fn (?Authenticatable $user) => false); } - } } diff --git a/src/DocumentationPanelProvider.php b/src/DocumentationPanelProvider.php new file mode 100644 index 0000000..61442b5 --- /dev/null +++ b/src/DocumentationPanelProvider.php @@ -0,0 +1,60 @@ +default() + ->id('docsidian') + ->path('docsidian') + ->login() + ->colors([ + 'primary' => Color::Amber, + ]) + ->discoverResources(in: __DIR__.'/Filament', for: 'ArtisanBuild\\Docsidian\\Filament') + ->discoverPages(in: __DIR__.'Filament/Pages', for: 'ArtisanBuild\\Docsidian\\Filament\\Pages') + ->pages([ + Pages\Dashboard::class, + Pages\Dashboard::class, + ]) + ->discoverWidgets(in: __DIR__.'Filament/Widgets', for: 'ArtisanBuild\\Docsidian\\Filament\\Widgets') + ->widgets([ + Widgets\AccountWidget::class, + Widgets\FilamentInfoWidget::class, + ]) + ->middleware([ + EncryptCookies::class, + AddQueuedCookiesToResponse::class, + StartSession::class, + AuthenticateSession::class, + ShareErrorsFromSession::class, + VerifyCsrfToken::class, + SubstituteBindings::class, + DisableBladeIconComponents::class, + DispatchServingFilamentEvent::class, + ]) + ->authMiddleware([ + Authenticate::class, + ]); + + } +} diff --git a/src/Filament/Resources/DocsidianSiteResource.php b/src/Filament/Resources/DocsidianSiteResource.php new file mode 100644 index 0000000..c7f1642 --- /dev/null +++ b/src/Filament/Resources/DocsidianSiteResource.php @@ -0,0 +1,74 @@ +schema([ + Forms\Components\TextInput::make('name'), + Forms\Components\TextInput::make('weight')->numeric(), + Forms\Components\TextInput::make('description'), + Forms\Components\FileUpload::make('image')->image(), + + Forms\Components\Select::make('status')->options(SiteStatus::class), + + Forms\Components\TextInput::make('folio_uri')->columnSpanFull(), + Forms\Components\TextInput::make('folio_path')->columnSpanFull(), + Forms\Components\TextInput::make('md_path')->columnSpanFull(), + + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('weight'), + Tables\Columns\TextColumn::make('name'), + // TODO: I shouldn't have to do this. The casting should work. + Tables\Columns\TextColumn::make('status')->getStateUsing(fn($record) => $record->status->name), + ]) + ->filters([ + // + ]) + ->actions([ + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ])->defaultSort('weight'); + } + + public static function getRelations(): array + { + return [ + // + ]; + } + + public static function getPages(): array + { + return [ + 'index' => \ArtisanBuild\Docsidian\Filament\Resources\DocsidianSiteResource\Pages\ListDocsidianSites::route('/'), + 'create' => \ArtisanBuild\Docsidian\Filament\Resources\DocsidianSiteResource\Pages\CreateDocsidianSite::route('/create'), + 'edit' => \ArtisanBuild\Docsidian\Filament\Resources\DocsidianSiteResource\Pages\EditDocsidianSite::route('/{record}/edit'), + ]; + } +} diff --git a/src/Filament/Resources/DocsidianSiteResource/Pages/CreateDocsidianSite.php b/src/Filament/Resources/DocsidianSiteResource/Pages/CreateDocsidianSite.php new file mode 100644 index 0000000..93fd6ed --- /dev/null +++ b/src/Filament/Resources/DocsidianSiteResource/Pages/CreateDocsidianSite.php @@ -0,0 +1,11 @@ + 'array', + 'status' => SiteStatus::class, + ]; +} diff --git a/src/SiteStatus.php b/src/SiteStatus.php new file mode 100644 index 0000000..9d34c66 --- /dev/null +++ b/src/SiteStatus.php @@ -0,0 +1,10 @@ +