diff --git a/README.md b/README.md index 724cf8d..0254738 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,13 @@ +## This package logic and structure based on great [laravel/breeze](https://github.com/laravel/breeze) package + ## Basic components for small sites on [LARAVEL](https://github.com/laravel/laravel) framework -Components for speed creating sites.\ +> **Note** +> +> Mainly developed for laravel/breeze package + + +Components for fast creating sites.\ Copying basic kit for some tagged entities in right places. Do not write it! Only install =) diff --git a/app/Http/Controllers/NewsController.php b/app/Http/Controllers/NewsController.php deleted file mode 100644 index e40a5fe..0000000 --- a/app/Http/Controllers/NewsController.php +++ /dev/null @@ -1,17 +0,0 @@ -get(); - - return response()->json([ - 'news' => $news, - ]); - } -} \ No newline at end of file diff --git a/app/Models/News.php b/app/Models/News.php deleted file mode 100644 index 7244123..0000000 --- a/app/Models/News.php +++ /dev/null @@ -1,10 +0,0 @@ -id(); - $table->string('title'); - $table->tinyInteger('active')->default(1); - $table->timestamp('active_from')->nullable(); - $table->timestamp('active_to')->nullable(); - $table->timestamps(); - $table->softDeletes(); - }); - } - - public function down() - { - Schema::dropIfExists('news'); - } -} \ No newline at end of file diff --git a/routes/web.php b/routes/web.php deleted file mode 100644 index 397d6f5..0000000 --- a/routes/web.php +++ /dev/null @@ -1,6 +0,0 @@ -app->runningInConsole()) { + return; + } + + $this->commands([ + Console\InstallCommand::class, + ]); + } + + /** + * Get the services provided by the provider. + * + * @return array + */ + public function provides() + { + return [Console\InstallCommand::class]; + } +} \ No newline at end of file diff --git a/src/Console/InstallCommand.php b/src/Console/InstallCommand.php new file mode 100644 index 0000000..fe3f88c --- /dev/null +++ b/src/Console/InstallCommand.php @@ -0,0 +1,302 @@ + + */ + protected $stacks = ['blade', 'vue']; + + /** + * Execute the console command. + * + * @return int|null + */ + public function handle() + { + if ($this->argument('stack') === 'vue') { + return $this->installInertiaVueStack(); + } elseif ($this->argument('stack') === 'blade') { + return $this->installBladeStack(); + } + + $this->components->error('Invalid stack. Supported stacks are [blade] or [vue].'); + + return 1; + } + + /** + * Interact with the user to prompt them when the stack argument is missing. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface $output + * @return void + */ + protected function interact(InputInterface $input, OutputInterface $output) + { + if ($this->argument('stack') === null && $this->option('inertia')) { + $input->setArgument('stack', 'vue'); + } + + if ($this->argument('stack')) { + return; + } + + $input->setArgument( + 'stack', + $this->components->choice('Which stack would you like to install?', $this->stacks) + ); + + //TODO add darkmode support +// $input->setOption('dark', $this->components->confirm('Would you like to install dark mode support?')); + + if (in_array($input->getArgument('stack'), ['vue'])) { + // not now =) + } + } + +// /** +// * Install tests. +// * +// * @return bool +// */ +// protected function installTests() +// { +// //TODO need test on future +// +// return true; +// } + + /** + * Install the middleware to a group in the application Http Kernel. + * + * @param string $after + * @param string $name + * @param string $group + * @return void + */ + protected function installMiddlewareAfter($after, $name, $group = 'web') + { +// $httpKernel = file_get_contents(app_path('Http/Kernel.php')); +// +// $middlewareGroups = Str::before(Str::after($httpKernel, '$middlewareGroups = ['), '];'); +// $middlewareGroup = Str::before(Str::after($middlewareGroups, "'$group' => ["), '],'); +// +// if (!Str::contains($middlewareGroup, $name)) { +// $modifiedMiddlewareGroup = str_replace( +// $after . ',', +// $after . ',' . PHP_EOL . ' ' . $name . ',', +// $middlewareGroup, +// ); +// +// file_put_contents( +// app_path('Http/Kernel.php'), +// str_replace( +// $middlewareGroups, +// str_replace($middlewareGroup, $modifiedMiddlewareGroup, $middlewareGroups), +// $httpKernel +// ) +// ); +// } + } + + /** + * Installs the given Composer Packages into the application. + * + * @param array $packages + * @param bool $asDev + * @return bool + */ + protected function requireComposerPackages(array $packages, $asDev = false) + { +// $composer = $this->option('composer'); +// +// if ($composer !== 'global') { +// $command = ['php', $composer, 'require']; +// } +// +// $command = array_merge( +// $command ?? ['composer', 'require'], +// $packages, +// $asDev ? ['--dev'] : [], +// ); +// +// return (new Process($command, base_path(), ['COMPOSER_MEMORY_LIMIT' => '-1'])) +// ->setTimeout(null) +// ->run(function ($type, $output) { +// $this->output->write($output); +// }) === 0; + } + + /** + * Removes the given Composer Packages from the application. + * + * @param array $packages + * @param bool $asDev + * @return bool + */ + protected function removeComposerPackages(array $packages, $asDev = false) + { +// $composer = $this->option('composer'); +// +// if ($composer !== 'global') { +// $command = ['php', $composer, 'remove']; +// } +// +// $command = array_merge( +// $command ?? ['composer', 'remove'], +// $packages, +// $asDev ? ['--dev'] : [], +// ); +// +// return (new Process($command, base_path(), ['COMPOSER_MEMORY_LIMIT' => '-1'])) +// ->setTimeout(null) +// ->run(function ($type, $output) { +// $this->output->write($output); +// }) === 0; + } + + /** + * Update the "package.json" file. + * + * @param callable $callback + * @param bool $dev + * @return void + */ + protected static function updateNodePackages(callable $callback, $dev = true) + { +// if (!file_exists(base_path('package.json'))) { +// return; +// } +// +// $configurationKey = $dev ? 'devDependencies' : 'dependencies'; +// +// $packages = json_decode(file_get_contents(base_path('package.json')), true); +// +// $packages[$configurationKey] = $callback( +// array_key_exists($configurationKey, $packages) ? $packages[$configurationKey] : [], +// $configurationKey +// ); +// +// ksort($packages[$configurationKey]); +// +// file_put_contents( +// base_path('package.json'), +// json_encode($packages, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT) . PHP_EOL +// ); + } + + /** + * Delete the "node_modules" directory and remove the associated lock files. + * + * @return void + */ + protected static function flushNodeModules() + { +// tap(new Filesystem, function ($files) { +// $files->deleteDirectory(base_path('node_modules')); +// +// $files->delete(base_path('yarn.lock')); +// $files->delete(base_path('package-lock.json')); +// }); + } + + /** + * Replace a given string within a given file. + * + * @param string $search + * @param string $replace + * @param string $path + * @return void + */ + protected function replaceInFile($search, $replace, $path) + { + file_put_contents($path, str_replace($search, $replace, file_get_contents($path))); + } + + /** + * Add a given string into a given file. + * + * @param string $string + * @param string $path + * @return void + */ + protected function addInFile(string $string, string $path) + { + file_put_contents($path, "\n" . $string); + } + + /** + * Get the path to the appropriate PHP binary. + * + * @return string + */ + protected function phpBinary() + { + return (new PhpExecutableFinder())->find(false) ?: 'php'; + } + + /** + * Run the given commands. + * + * @param array $commands + * @return void + */ + protected function runCommands($commands) + { + $process = Process::fromShellCommandline(implode(' && ', $commands), null, null, null, null); + + if ('\\' !== DIRECTORY_SEPARATOR && file_exists('/dev/tty') && is_readable('/dev/tty')) { + try { + $process->setTty(true); + } catch (RuntimeException $e) { + $this->output->writeln(' WARN ' . $e->getMessage() . PHP_EOL); + } + } + + $process->run(function ($type, $line) { + $this->output->write(' ' . $line); + }); + } + + /** + * Remove Tailwind dark classes from the given files. + * + * @param \Symfony\Component\Finder\Finder $finder + * @return void + */ + protected function removeDarkClasses(Finder $finder) + { + foreach ($finder as $file) { + file_put_contents($file->getPathname(), preg_replace('/\sdark:[^\s"\']+/', '', $file->getContents())); + } + } +} diff --git a/src/Console/InstallsBladeStack.php b/src/Console/InstallsBladeStack.php new file mode 100644 index 0000000..8bcc7d0 --- /dev/null +++ b/src/Console/InstallsBladeStack.php @@ -0,0 +1,80 @@ +ensureDirectoryExists(app_path('Http/Controllers')); + (new Filesystem)->copyDirectory( + __DIR__ . '/../../stubs/default/app/Http/Controllers', + app_path('Http/Controllers') + ); + + // Requests... + (new Filesystem)->ensureDirectoryExists(app_path('Http/Requests')); + (new Filesystem)->copyDirectory(__DIR__ . '/../../stubs/default/app/Http/Requests', app_path('Http/Requests')); + + // Views... + (new Filesystem)->ensureDirectoryExists(resource_path('views')); + (new Filesystem)->copyDirectory( + __DIR__ . '/../../stubs/default/resources/views', + resource_path('views') + ); + + //TODO darkmode +// if (! $this->option('dark')) { +// $this->removeDarkClasses((new Finder) +// ->in(resource_path('views')) +// ->name('*.blade.php') +// ->notName('welcome.blade.php') +// ); +// } + + // Components... + (new Filesystem)->ensureDirectoryExists(app_path('View/Components')); + (new Filesystem)->copyDirectory( + __DIR__ . '/../../stubs/default/app/View/Components', + app_path('View/Components') + ); + + //TODO Tests... +// if (! $this->installTests()) { +// return 1; +// } + + // Routes... +// copy(__DIR__ . '/../../stubs/default/routes/web.php', base_path('routes/web.php')); +// copy(__DIR__ . '/../../stubs/default/routes/auth.php', base_path('routes/auth.php')); + + + + $this->addInFile( + "Route::get('news/', [NewsController::class, 'index'])->name('index');", + base_path('routes/web.php') + ); + $this->addInFile( + "Route::post('news/json', [NewsController::class, 'getIndexJsonPage'])->name('index.json.page');", + base_path('routes/web.php') + ); + $this->addInFile( + "Route::get('news/{slug}', [NewsController::class, 'show'])->name('show');", + base_path('routes/web.php') + ); + + $this->line(''); + $this->components->info('Basic components installed successfully.'); + + return 1; + } +} diff --git a/src/Console/InstallsInertiaStacks.php b/src/Console/InstallsInertiaStacks.php new file mode 100644 index 0000000..9d4cdcf --- /dev/null +++ b/src/Console/InstallsInertiaStacks.php @@ -0,0 +1,254 @@ +publishes([ + __DIR__ . '/../../database/migrations/0000_00_00_000000_create_news_table.php' => database_path( + '/migrations/0000_00_00_000000_create_news_table.php' + ), + __DIR__ . '/../../app/Http/Controllers/NewsController.php' => app_path('Http/Controllers/NewsController.php'), + __DIR__ . '/../../app/Models/News.php' => app_path('Models/News.php'), + ], 'news'); + + $this->publishes([ + __DIR__ . '/../../resources/js/Components/Elements/SelectFilterable.vue' => resource_path( + '/js/Components/Elements/SelectFilterable.vue' + ), + ], 'vue-SelectFilterable'); + + $this->loadRoutesFrom(__DIR__ . '/../../routes/web.php'); + + + $this->line(''); + $this->components->info('Basic components installed successfully.'); + + return 1; + } + + /** + * Install the Inertia React Breeze stack. + * + * @return int|null + */ + protected function installInertiaReactStack() + { + // Install Inertia... + if (!$this->requireComposerPackages( + ['inertiajs/inertia-laravel:^0.6.3', 'laravel/sanctum:^3.2', 'tightenco/ziggy:^1.0'] + )) { + return 1; + } + + // NPM Packages... + $this->updateNodePackages(function ($packages) { + return [ + '@headlessui/react' => '^1.4.2', + '@inertiajs/react' => '^1.0.0', + '@tailwindcss/forms' => '^0.5.3', + '@vitejs/plugin-react' => '^3.0.0', + 'autoprefixer' => '^10.4.12', + 'postcss' => '^8.4.18', + 'tailwindcss' => '^3.2.1', + 'react' => '^18.2.0', + 'react-dom' => '^18.2.0', + ] + $packages; + }); + + if ($this->option('typescript')) { + $this->updateNodePackages(function ($packages) { + return [ + '@types/node' => '^18.13.0', + '@types/react' => '^18.0.28', + '@types/react-dom' => '^18.0.10', + '@types/ziggy-js' => '^1.3.2', + 'typescript' => '^5.0.2', + ] + $packages; + }); + } + + // Controllers... + (new Filesystem)->ensureDirectoryExists(app_path('Http/Controllers')); + (new Filesystem)->copyDirectory( + __DIR__ . '/../../stubs/inertia-common/app/Http/Controllers', + app_path('Http/Controllers') + ); + + // Requests... + (new Filesystem)->ensureDirectoryExists(app_path('Http/Requests')); + (new Filesystem)->copyDirectory(__DIR__ . '/../../stubs/default/app/Http/Requests', app_path('Http/Requests')); + + // Middleware... + $this->installMiddlewareAfter('SubstituteBindings::class', '\App\Http\Middleware\HandleInertiaRequests::class'); + $this->installMiddlewareAfter( + '\App\Http\Middleware\HandleInertiaRequests::class', + '\Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets::class' + ); + + copy( + __DIR__ . '/../../stubs/inertia-common/app/Http/Middleware/HandleInertiaRequests.php', + app_path('Http/Middleware/HandleInertiaRequests.php') + ); + + // Views... + copy( + __DIR__ . '/../../stubs/inertia-react/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')); + + if ($this->option('typescript')) { + (new Filesystem)->copyDirectory( + __DIR__ . '/../../stubs/inertia-react-ts/resources/js/Components', + resource_path('js/Components') + ); + (new Filesystem)->copyDirectory( + __DIR__ . '/../../stubs/inertia-react-ts/resources/js/Layouts', + resource_path('js/Layouts') + ); + (new Filesystem)->copyDirectory( + __DIR__ . '/../../stubs/inertia-react-ts/resources/js/Pages', + resource_path('js/Pages') + ); + (new Filesystem)->copyDirectory( + __DIR__ . '/../../stubs/inertia-react-ts/resources/js/types', + resource_path('js/types') + ); + } else { + (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') + ); + } + + if (!$this->option('dark')) { + $this->removeDarkClasses( + (new Finder) + ->in(resource_path('js')) + ->name(['*.jsx', '*.tsx']) + ->notName(['Welcome.jsx', 'Welcome.tsx']) + ); + } + + // Tests... + if (!$this->installTests()) { + return 1; + } + + if ($this->option('pest')) { + (new Filesystem)->copyDirectory( + __DIR__ . '/../../stubs/inertia-common/pest-tests/Feature', + base_path('tests/Feature') + ); + } else { + (new Filesystem)->copyDirectory( + __DIR__ . '/../../stubs/inertia-common/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', app_path('Providers/RouteServiceProvider.php')); + + // Tailwind / Vite... + copy(__DIR__ . '/../../stubs/default/resources/css/app.css', resource_path('css/app.css')); + copy(__DIR__ . '/../../stubs/default/postcss.config.js', base_path('postcss.config.js')); + copy(__DIR__ . '/../../stubs/inertia-common/tailwind.config.js', base_path('tailwind.config.js')); + copy(__DIR__ . '/../../stubs/inertia-react/vite.config.js', base_path('vite.config.js')); + + if ($this->option('typescript')) { + copy(__DIR__ . '/../../stubs/inertia-react-ts/tsconfig.json', base_path('tsconfig.json')); + copy(__DIR__ . '/../../stubs/inertia-react-ts/resources/js/app.tsx', resource_path('js/app.tsx')); + + if (file_exists(resource_path('js/bootstrap.js'))) { + rename(resource_path('js/bootstrap.js'), resource_path('js/bootstrap.ts')); + } + + $this->replaceInFile('"vite build', '"tsc && vite build', base_path('package.json')); + $this->replaceInFile('.jsx', '.tsx', base_path('vite.config.js')); + $this->replaceInFile('.jsx', '.tsx', resource_path('views/app.blade.php')); + $this->replaceInFile('.vue', '.tsx', base_path('tailwind.config.js')); + } else { + copy(__DIR__ . '/../../stubs/inertia-common/jsconfig.json', base_path('jsconfig.json')); + copy(__DIR__ . '/../../stubs/inertia-react/resources/js/app.jsx', resource_path('js/app.jsx')); + + $this->replaceInFile('.vue', '.jsx', base_path('tailwind.config.js')); + } + + if (file_exists(resource_path('js/app.js'))) { + unlink(resource_path('js/app.js')); + } + + if ($this->option('ssr')) { + $this->installInertiaReactSsrStack(); + } + + $this->components->info('Installing and building Node dependencies.'); + + if (file_exists(base_path('pnpm-lock.yaml'))) { + $this->runCommands(['pnpm install', 'pnpm run build']); + } elseif (file_exists(base_path('yarn.lock'))) { + $this->runCommands(['yarn install', 'yarn run build']); + } else { + $this->runCommands(['npm install', 'npm run build']); + } + + $this->line(''); + $this->components->info('Breeze scaffolding installed successfully.'); + } + + /** + * Install the Inertia React SSR stack into the application. + * + * @return void + */ + protected function installInertiaReactSsrStack() + { + if ($this->option('typescript')) { + copy(__DIR__ . '/../../stubs/inertia-react-ts/resources/js/ssr.tsx', resource_path('js/ssr.tsx')); + $this->replaceInFile( + "input: 'resources/js/app.tsx',", + "input: 'resources/js/app.tsx'," . PHP_EOL . " ssr: 'resources/js/ssr.tsx',", + base_path('vite.config.js') + ); + } else { + copy(__DIR__ . '/../../stubs/inertia-react/resources/js/ssr.jsx', resource_path('js/ssr.jsx')); + $this->replaceInFile( + "input: 'resources/js/app.jsx',", + "input: 'resources/js/app.jsx'," . PHP_EOL . " ssr: 'resources/js/ssr.jsx',", + base_path('vite.config.js') + ); + } + + $this->replaceInFile('vite build', 'vite build && vite build --ssr', base_path('package.json')); + $this->replaceInFile('/node_modules', '/bootstrap/ssr' . PHP_EOL . '/node_modules', base_path('.gitignore')); + } +} diff --git a/src/Providers/BasicComponentsServiceProvider.php b/src/Providers/BasicComponentsServiceProvider.php deleted file mode 100644 index b292553..0000000 --- a/src/Providers/BasicComponentsServiceProvider.php +++ /dev/null @@ -1,30 +0,0 @@ -app->runningInConsole()) { - //php artisan vendor:publish --tag=news - $this->publishes([ - __DIR__ . '/../../database/migrations/0000_00_00_000000_create_news_table.php' => database_path( - '/migrations/0000_00_00_000000_create_news_table.php' - ), - __DIR__ . '/../../app/Http/Controllers/NewsController.php' => app_path('Http/Controllers/NewsController.php'), - __DIR__ . '/../../app/Models/News.php' => app_path('Models/News.php'), - ], 'news'); - - $this->publishes([ - __DIR__ . '/../../resources/js/Components/Elements/SelectFilterable.vue' => resource_path( - '/js/Components/Elements/SelectFilterable.vue' - ), - ], 'vue-SelectFilterable'); - - $this->loadRoutesFrom(__DIR__ . '/../../routes/web.php'); - } - } -} \ No newline at end of file diff --git a/stubs/database/migrations/0000_00_00_000000_create_news_table.php b/stubs/database/migrations/0000_00_00_000000_create_news_table.php new file mode 100644 index 0000000..546d5de --- /dev/null +++ b/stubs/database/migrations/0000_00_00_000000_create_news_table.php @@ -0,0 +1,34 @@ +id(); + $table->tinyInteger('active')->default(1)->nullable(); + $table->tinyInteger('is_action')->default(0)->nullable(); + $table->integer('sort')->default(500)->nullable(false); + $table->string('name', 255)->nullable(false)->unique(); + $table->string('slug', 255)->nullable(false)->unique(); + $table->string('text')->nullable(false); + $table->text('photos')->nullable(false); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('news'); + } +}; diff --git a/stubs/default/app/Http/Controllers/ContactsController.php b/stubs/default/app/Http/Controllers/ContactsController.php new file mode 100644 index 0000000..354462c --- /dev/null +++ b/stubs/default/app/Http/Controllers/ContactsController.php @@ -0,0 +1,26 @@ + '/', + __('Контакты') => '' + ]; + + $settings = Settings::whereIn('name', ['CONTACTS_ADDRESS', 'CONTACTS_EMAIL', 'CONTACTS_PHONE']) + ->select('name', 'value') + ->get() + ->mapWithKeys(function ($cpr, $key) { + return [$cpr->name => $cpr->value]; + }); + + return view('pages.contacts', compact('settings', 'breadcrumbs')); + } +} diff --git a/stubs/default/app/Http/Controllers/NewsController.php b/stubs/default/app/Http/Controllers/NewsController.php new file mode 100644 index 0000000..350d5ea --- /dev/null +++ b/stubs/default/app/Http/Controllers/NewsController.php @@ -0,0 +1,63 @@ + '/', + __('Новости и акции') => '' + ]; + + //flag to show only actions (not news) + $is_action = $request->get('actions') ?? null; + + $news = (new News()) + ->active() + ->when($is_action != null, function ($query) use ($is_action) { + $query->where('is_action', $is_action); + }) + ->paginate($this->itemsOnPage); + + return view('pages.news', compact('news', 'breadcrumbs', 'is_action')); + } + + public function getIndexJsonPage(Request $request) + { + //flag to show only actions (not news) + $is_action = $request->get('actions') ?? null; + + $news = (new News()) + ->active() + ->when($is_action != null, function ($query) use ($is_action) { + $query->where('is_action', $is_action); + }) + ->paginate($this->itemsOnPage); + + return view('components.news-paginate-items', compact('news')); + } + + public function show(string $slug) + { + $news_item = (new News()) + ->active() //scope active + ->where('slug', $slug) + ->firstOrFail(); + + $breadcrumbs = [ + __('Главная') => '/', + __('Новости и акции') => route('news.index'), + $news_item->name => '' //TODO may be do it translatable + ]; + + return view('pages.news-detail', compact('news_item', 'breadcrumbs')); + } +} \ No newline at end of file diff --git a/stubs/default/app/Http/Requests/NewsIndexRequest.php b/stubs/default/app/Http/Requests/NewsIndexRequest.php new file mode 100644 index 0000000..ae42e89 --- /dev/null +++ b/stubs/default/app/Http/Requests/NewsIndexRequest.php @@ -0,0 +1,21 @@ + + */ + public function rules(): array + { + return [ + 'actions' => ['nullable', Rule::in(['1', '0', null])] + ]; + } +} diff --git a/stubs/default/app/Models/News.php b/stubs/default/app/Models/News.php new file mode 100644 index 0000000..6f34d7a --- /dev/null +++ b/stubs/default/app/Models/News.php @@ -0,0 +1,19 @@ +where('active', 1); + } +} diff --git a/stubs/default/app/Models/Settings.php b/stubs/default/app/Models/Settings.php new file mode 100644 index 0000000..0971397 --- /dev/null +++ b/stubs/default/app/Models/Settings.php @@ -0,0 +1,11 @@ + +
    + @foreach($breadcrumbs as $name => $link) + @if($link) +
  1. {{ $name }}
  2. + @else +
  3. {{ $name }}
  4. + @endif + @endforeach +
+ +@endif diff --git a/stubs/default/resources/views/components/common/h2.blade.php b/stubs/default/resources/views/components/common/h2.blade.php new file mode 100644 index 0000000..655660d --- /dev/null +++ b/stubs/default/resources/views/components/common/h2.blade.php @@ -0,0 +1,11 @@ +@props(['h2']) + +
+
+
+

+ {{ $h2 ?? 'не выставлен заголовок' }} +

+
+
+
diff --git a/stubs/default/resources/views/components/common/phone.blade.php b/stubs/default/resources/views/components/common/phone.blade.php new file mode 100644 index 0000000..d82734a --- /dev/null +++ b/stubs/default/resources/views/components/common/phone.blade.php @@ -0,0 +1,10 @@ +@props(['phone']) + + + + + + {{$phone ?? ''}} + diff --git a/stubs/default/resources/views/components/forms/feedback.blade.php b/stubs/default/resources/views/components/forms/feedback.blade.php new file mode 100644 index 0000000..9a962e2 --- /dev/null +++ b/stubs/default/resources/views/components/forms/feedback.blade.php @@ -0,0 +1,118 @@ +
+ +
diff --git a/stubs/default/resources/views/components/news-card.blade.php b/stubs/default/resources/views/components/news-card.blade.php new file mode 100644 index 0000000..216a5ec --- /dev/null +++ b/stubs/default/resources/views/components/news-card.blade.php @@ -0,0 +1,31 @@ +@props(['item']) + + + @if($item?->getFirstMediaUrl('photos')) +
+ +
+ @else +
+ +
+ @endif + +
+ {{ $item->name }} +
+ +
+ +
+ +
+ diff --git a/stubs/default/resources/views/components/news-detail-card.blade.php b/stubs/default/resources/views/components/news-detail-card.blade.php new file mode 100644 index 0000000..3342882 --- /dev/null +++ b/stubs/default/resources/views/components/news-detail-card.blade.php @@ -0,0 +1,29 @@ +@props(['news_item']) + +
+
+
+
+ {{-- //TODO media for slider need fix --}} + {{--@foreach($news_item->getMedia('photos') as $photo)--}} + {{--
--}} + {{-- --}} + {{--
--}} + {{--@endforeach--}} +
+
+ + {{-- news inner text --}} +
+
+ {!! $news_item->text !!} +
+
+
+ +
+ Больше акций +
+
diff --git a/stubs/default/resources/views/components/news-filter.blade.php b/stubs/default/resources/views/components/news-filter.blade.php new file mode 100644 index 0000000..a7b6ffd --- /dev/null +++ b/stubs/default/resources/views/components/news-filter.blade.php @@ -0,0 +1,24 @@ +@props(['is_action']) + +
+ +
+ показать все +
+ +
+ Акции +
+ +
diff --git a/stubs/default/resources/views/components/news-paginate-items.blade.php b/stubs/default/resources/views/components/news-paginate-items.blade.php new file mode 100644 index 0000000..127714e --- /dev/null +++ b/stubs/default/resources/views/components/news-paginate-items.blade.php @@ -0,0 +1,5 @@ +@props(['news']) + +@foreach($news as $item) + @include('components.news-card', ['item' => $item]) +@endforeach diff --git a/stubs/default/resources/views/pages/contacts.blade.php b/stubs/default/resources/views/pages/contacts.blade.php new file mode 100644 index 0000000..ac43fc0 --- /dev/null +++ b/stubs/default/resources/views/pages/contacts.blade.php @@ -0,0 +1,17 @@ +@extends('layouts.guest') + +@props(['breadcrumbs', 'settings']) + +@section('content') + @include('components.common.breadcrumbs', ['breadcrumbs' => $breadcrumbs]) + + @include('components.common.h2', ['h2' => 'Контакты']) + + @include('components.common.contacts', ['settings' => $settings]) + +
+ @include('components.forms.feedback') +
+ +@endsection + diff --git a/stubs/default/resources/views/pages/news-detail.blade.php b/stubs/default/resources/views/pages/news-detail.blade.php new file mode 100644 index 0000000..83393af --- /dev/null +++ b/stubs/default/resources/views/pages/news-detail.blade.php @@ -0,0 +1,13 @@ +@extends('layouts.guest') + +@props(['breadcrumbs', 'news_item']) + +@section('content') + + @include('components.common.breadcrumbs', ['breadcrumbs' => $breadcrumbs]) + + @include('components.common.h2', [ 'h2' => $news_item?->name ]) + + @include('components.news-detail-card', ['news_item' => $news_item]) + +@endsection diff --git a/stubs/default/resources/views/pages/news.blade.php b/stubs/default/resources/views/pages/news.blade.php new file mode 100644 index 0000000..9ce4ac6 --- /dev/null +++ b/stubs/default/resources/views/pages/news.blade.php @@ -0,0 +1,23 @@ +@extends('layouts.guest') + +@props(['news', 'breadcrumbs', 'is_action']) + +@section('content') +
+ @include('components.common.breadcrumbs', ['breadcrumbs' => $breadcrumbs]) + + @include('components.common.h2', ['h2' => 'Новости и акции']) + + @include('components.news-filter', ['is_action' => $is_action]) + +
+ @if($news) + @include('components.news-paginate-items', ['news' => $news]) + @endif +
+ +
+ показать больше +
+
+@endsection diff --git a/resources/js/Components/Elements/SelectFilterable.vue b/stubs/inertia-vue/resources/js/Components/Elements/SelectFilterable.vue similarity index 100% rename from resources/js/Components/Elements/SelectFilterable.vue rename to stubs/inertia-vue/resources/js/Components/Elements/SelectFilterable.vue