freemancontingent / laravel-themes
主题可以帮助您轻松地在Laravel项目中组织主题,并维护主题相关的资产、布局和部分,统一存储在单个目录中。(基于teepluss/theme)
Requires
- php: ^7.3|^8.0
- opis/closure: ^3.6
Requires (Dev)
- illuminate/support: ^7.0
This package is not auto-updated.
Last update: 2024-09-19 09:59:53 UTC
README
Laravel-Theme是Laravel 6+的主题管理工具,它是最简单的方式组织您的皮肤、布局和资产。
本包基于 teepluss\theme
与teepluss版本的区别
- 兼容Laravel 6+。
- 移除了twig兼容性(减少了包体积94%)。
- Blade指令
- 更好的基础模板。
- 简化配置。
- 更多命令和辅助函数。
- 更好的README文件。
- 清单文件(获取和设置主题信息)
- 中间件定义主题和布局
用法
主题具有许多功能,可以帮助您轻松开始使用Laravel。
安装
要获取laravel-themes的最新版本,只需在您的composer.json
文件中引入它。
"freemancontingent/laravel-themes": "^4.0"
然后您需要运行composer install
来下载它,并更新自动加载器。
一旦安装了主题,您需要将服务提供者注册到应用程序中。打开config/app.php
文件,找到providers
键。
'providers' => [ ... Fcl\Theme\ThemeServiceProvider::class, ]
主题还提供了一个门面,它提供了创建集合的静态语法。您可以在config/app.php
文件的aliases
键中注册门面。
'aliases' => [ ... 'Theme' => Fcl\Theme\Facades\Theme::class, ]
使用artisan CLI发布配置。
php artisan vendor:publish --provider="Fcl\Theme\ThemeServiceProvider"
建议将我们要使用的主题添加到.env
文件中
APP_THEME=default
创建新主题
第一次使用时,需要使用artisan命令创建“default”主题结构
php artisan theme:create default
如果您更改了门面名称,可以添加一个选项
--facade="别名"
。
这将创建以下目录结构
├── public/
└── themes/
└── default/
├── assets
| ├── css/
| ├── img/
| └── js/
├── layouts/
├── partials/
| └── sections/
├── views/
└── widgets/
要删除现有的主题,使用以下命令
php artisan theme:destroy default
如果您想列出所有已安装的主题,使用以下命令
php artisan theme:list
您还可以复制现有的主题
php artisan theme:duplicate name new-theme
不使用CLI从应用程序创建
Artisan::call('theme:create', ['name' => 'foo']);
基本用法
从控制器中显示视图
namespace App\Http\Controllers; use Theme; class HomeController extends Controller { public function getIndex() { return Theme::view('index'); } ... }
这将使用默认在
.env
中设置的主题和布局
您可以添加数据或定义主题和布局
... Theme::uses('themename'); $data['info'] = 'Hello World'; return Theme::view('index', $data); ...
或者您可以这样做
$cookie = Cookie::make('name', 'Tee'); return Theme::view([ 'view' => 'index', 'theme' => 'default', 'layout' => 'layout', 'statusCode' => 200, 'cookie' => $cookie, 'args' => $data ]);
除了
'view'
之外的所有值都是可选的
要检查主题是否存在。
Theme::exists('themename');
每个主题都必须提供存储在主题根目录下的清单文件theme.json
,该文件定义了关于主题的补充信息。
{ "slug": "default", "name": "Default", "author": "John Doe", "email": "johndoe@example.com", "description": "This is an example theme.", "web": "www.example.com", "license": "MIT", "version": "1.0" }
清单文件可以存储您想要的任何属性。您可以通过几个辅助方法检索甚至设置这些值
// Get all: (array) Theme::info(); // Get: Theme::info("property"); // Set: Theme::info("property", "new data");
其他显示视图的方式
$theme = Theme::uses('default')->layout('mobile'); $data = ['info' => 'Hello World'];
// It will look up the path 'resources/views/home/index.php': return $theme->of('home.index', $data)->render();
// Specific status code with render: return $theme->of('home.index', $data)->render(200);
// It will look up the path 'resources/views/mobile/home/index.php': return $theme->ofWithLayout('home.index', $data)->render();
// It will look up the path 'public/themes/default/views/home/index.php': return $theme->scope('home.index', $data)->render();
// It will look up the path 'public/themes/default/views/mobile/home/index.php': return $theme->scopeWithLayout('home.index', $data)->render();
// Looking for a custom path: return $theme->load('app.somewhere.viewfile', $data)->render();
// Working with cookie: $cookie = Cookie::make('name', 'Tee'); return $theme->of('home.index', $data)->withCookie($cookie)->render();
// Get only content: return $theme->of('home.index')->content();
从主题的视图和应用程序的视图中查找
$theme = Theme::uses('default')->layout('default'); return $theme->watch('home.index')->render();
要查找视图的位置
$which = $theme->scope('home.index')->location(); echo $which; // theme::views.home.index $which = $theme->scope('home.index')->location(true); echo $which; // ./public/themes/name/views/home/index.blade.php
从字符串渲染
return $theme->string('<h1>{{ $name }}</h1>', ['name' => 'Teepluss'], 'blade')->render();
编译字符串
$template = `<h1>Name: {{ $name }}</h1> <p> {{ Theme::widget("WidgetIntro", ["title" => "Demo Widget"])->render() }} </p>`; echo Theme::blader($template, ['name' => 'Teepluss']);
从另一个视图创建符号链接
当您有多个文件具有相同的名称,但需要作为单独的文件定位时,这是一个很好的功能。
// Theme A : /public/themes/a/views/welcome.blade.php // Theme B : /public/themes/b/views/welcome.blade.php // File welcome.blade.php at Theme B is the same as Theme A, so you can do link below: Theme::symlink('a'); // Location: public/themes/b/views/welcome.blade.php
配置
配置发布后,您将看到一个全局配置文件/config/theme.php
,所有配置都可以替换为主题内部配置文件/public/themes/[theme]/config.php
中的配置文件
配置方便设置基本的CSS/JS、部分composer、面包屑模板以及元数据。
'events' => [ /* * Before event inherit from package config and the theme that call * before, you can use this event to set meta, breadcrumb * template or anything you want inheriting. */ 'before' => function($theme) { // You can remove this lines anytime. $theme->setTitle('Title Example'); $theme->setAuthor('John Doe'); $theme->setKeywords('Example, Web'); // Breadcrumb template. $theme->breadcrumb()->setTemplate(` <ul class="breadcrumb"> @foreach($crumbs as $i => $crumb) @if($i != (count($crumbs) - 1)) <li> <a href="{{ $crumb["url"] }}">{{ $crumb["label"] }}</a> <span class="divider">/</span> </li> @else <li class="active">{{ $crumb["label"] }}</li> @endif @endforeach </ul> `); }, /* * Listen on event before render a theme, this * event should call to assign some assets. */ 'asset' => function($asset) { $asset->themePath()->add([ ['style', 'css/style.css'], ['script', 'js/script.js'] ]); // You may use elixir to concat styles and scripts. $asset->themePath()->add([ ['styles', 'dist/css/styles.css'], ['scripts', 'dist/js/scripts.js'] ]); // Or you may use this event to set up your assets. $asset->themePath()->add('core', 'core.js'); $asset->add([ ['jquery', 'vendor/jquery/jquery.min.js'], ['jquery-ui', 'vendor/jqueryui/jquery-ui.min.js', ['jquery']] ]); }, /* * Listen on event before render a theme, this event should * call to assign some partials or breadcrumb template. */ 'beforeRenderTheme' => function($theme) { $theme->partialComposer('header', function($view){ $view->with('auth', Auth::user()); }); }, /* * Listen on event before render a layout, this should * call to assign style, script for a layout. */ 'beforeRenderLayout' => [ 'mobile' => function($theme){ $theme->asset()->usePath()->add('ipad', 'css/layouts/ipad.css'); } ] ];
资产的基本用法
您可以在配置文件的 asset
方法中添加资产。如果您想在路由中添加资产,可以通过从 $theme->asset()
获取 $asset
变量来实现。
$asset->add('core-style', 'css/style.css'); // path: public/css/style.css $asset->container('footer')->add('core-script', 'js/script.js'); // path: public/js/script.css $asset->themePath()->add('custom', 'css/custom.css', ['core-style']); // path: public/themes/[current-theme]/assets/css/custom.css // This case has dependency with "core-style". $asset->container('footer')->themePath()->add('custom', 'js/custom.js', ['core-script']); // path: public/themes/[current theme]/assets/js/custom.js // This case has dependency with "core-script".
通过向方法传递参数,您可以强制使用主题来查找现有主题:
$asset->themePath('default')
编写内联样式或脚本
// Dependency with. $dependencies = []; // Writing an in-line script. $asset->writeScript('inline-script', ' $(function() { console.log("Running"); })', $dependencies); // Writing an in-line style. $asset->writeStyle('inline-style', 'h1{ font-size: 0.9em; }', $dependencies); // Writing an in-line script, style without tag wrapper. $asset->writeContent('custom-inline-script', ' <script> $(function() { console.log("Running"); }); </script>', $dependencies);
在您的 blade 布局中渲染样式和脚本
// Without container @styles() // With "footer" container @scripts('footer') // Get a specific path from the asset folder @asset('img/image.png')
脚本和样式可以带容器或不带容器使用
或者更复杂的方法
{!! Theme::asset()->styles() !!} {!! Theme::asset()->container('footer')->scripts() !!}
直接路径到主题资产
{!! Theme::asset()->url('img/image.png') !!}
准备资产组
有些资产您现在不想添加到页面上,但有时您仍然需要它们,所以 cook
和 serve
是您的魔法。
烹饪您的资产。
Theme::asset()->cook('backbone', function($asset) { $asset->add('backbone', '//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone-min.js'); $asset->add('underscorejs', '//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js'); });
您可以在包的配置文件中全局准备
// Location: config/theme/config.php .... 'events' => [ .... // This event will fire as a global you can add any assets you want here. 'asset' => function($asset) { // Preparing asset you need to serve after. $asset->cook('backbone', function($asset) { $asset->add('backbone', '//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone-min.js'); $asset->add('underscorejs', '//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js'); }); } ] ....
当需要时提供主题
// At the controller. Theme::asset()->serve('backbone');
然后您可以得到输出
<html> <head> @styles() @styles('your-container') </head> <body> ... @scripts() @scripts('your-container') </body> <html>
部分
在布局或视图中渲染部分
@partial('header', ['title' => 'Header']);
这将查找
/public/themes/[theme]/partials/header.php
,并将添加一个变量$title
(可选)
与当前布局特定的部分
Theme::partialWithLayout('header', ['title' => 'Header']);
这将查找
/public/themes/[theme]/partials/[CURRENT_LAYOUT]/header.php
从主题的部分和应用程序的部分中查找
Theme::watchPartial('header', ['title' => 'Header']);
部分组件
$theme->partialComposer('header', function($view) { $view->with('key', 'value'); }); // Working with partialWithLayout. $theme->partialComposer('header', function($view) { $view->with('key', 'value'); }, 'layout-name');
部分
@sections
blade 指令简化了对 /partials/sections/
路径的访问
@sections('main')
它与以下相同
@partial('sections.main')
魔法方法
魔法方法允许您设置、预置和附加任何内容。
$theme->setTitle('Your title'); $theme->appendTitle('Your appended title'); $theme->prependTitle('Hello: ....'); $theme->setAnything('anything'); $theme->setFoo('foo'); $theme->set('foo', 'foo');
在 blade 布局或视图中渲染
@get('foo') @get('foo', 'Default msj') Theme::getAnything(); Theme::getFoo(); Theme::get('foo', 'Default msj');
检查位置是否存在
@getIfHas('title')
它与以下相同
@if(Theme::has('title')) {{ Theme::get('title') }} @endif
@if(Theme::hasTitle()) {{ Theme::getTitle() }} @endif
获取在布局或区域中分配给内容的参数
Theme::getContentArguments(); Theme::getContentArgument('name');
以检查它是否存在
Theme::hasContentArgument('name');
Theme::place('content') 是一个预留区域,用于渲染子视图。
准备数据供视图使用
有时您不需要执行繁重的处理,因此您可以在需要时准备和使用它。
$theme->bind('something', function() { return 'This is bound parameter.'; });
在视图中使用绑定数据
echo Theme::bind('something');
面包屑
为了使用面包屑,请按照以下说明操作
$theme->breadcrumb()->add('label', 'http://...')->add('label2', 'http:...'); // or $theme->breadcrumb()->add([[ 'label' => 'label1', 'url' => 'http://...' ],[ 'label' => 'label2', 'url' => 'http://...' ]]);
以渲染面包屑
{!! $theme->breadcrumb()->render() !!}
或者
{!! Theme::breadcrumb()->render() !!}
您可以使用 blade 模板在任何您想要的地方设置面包屑模板。
$theme->breadcrumb()->setTemplate(' <ul class="breadcrumb"> @foreach ($crumbs as $i => $crumb) @if ($i != (count($crumbs) - 1)) <li><a href="{{ $crumb["url"] }}">{{ $crumb["label"] }}</a><span class="divider">/</span></li> @else <li class="active">{{ $crumb["label"] }}</li> @endif @endforeach </ul> ');
小部件
主题有许多称为“小部件”的有用功能,可以是任何东西。您可以使用 artisan 命令创建一个全局小部件类
php artisan theme:widget demo --global
小部件模板位于 "resources/views/widgets/{widget-tpl}.blade.php"
创建特定的主题名称。
php artisan theme:widget demo default
小部件模板位于 "public/themes/[theme]/widgets/{widget-tpl}.blade.php"
现在您将在 /app/Widgets/WidgetDemo.php 中看到一个小部件类
<h1>User Id: {{ $label }}</h1>
在布局或视图中调用您的部件
@widget('demo', ['label' => 'Hi!'])
或者
{!! Theme::widget('demo', ['label' => 'Hi!'])->render() !!}
使用全局主题
use Fcl\Theme\Contracts\Theme; use App\Http\Controllers\Controller; class BaseController extends Controller { /** * Theme instance. * * @var \Fcl\Theme\Theme */ protected $theme; /** * Construct * * @return void */ public function __construct(Theme $theme) { // Using theme as a global. $this->theme = $theme->uses('default')->layout('ipad'); } }
以覆盖主题或布局。
public function getIndex() { $this->theme->uses('newone'); // or just override layout $this->theme->layout('desktop'); $this->theme->of('somewhere.index')->render(); }
中间件
如果想要为每个路由定义一个主题或布局,那么默认情况下包含了一个中间件。对于 Laravel 6+,中间件默认安装。
在 Laravel 5.4 之前安装它
仅在 app\Http\Kernel.php
中注册它
protected $routeMiddleware = [ ... 'setTheme' => \Fcl\Theme\Middleware\ThemeLoader::class, ];
用法
您可以使用字符串 'theme:[theme],[layout]'
将中间件应用于路由或路由组
Route::get('/', function () { ... return Theme::view('index'); })->middleware('theme:default,layout');
或者使用组
Route::group(['middleware'=>'theme:default,layout'], function() { ... });
辅助函数
保护电子邮件
保护电子邮件地址,防止机器人或蜘蛛索引或收集地址以向您发送垃圾邮件。
{!! protectEmail('email@example.com') !!}
或更短
@protect('email@example.com')
元数据初始化
打印常见的元标签。
{!! meta_init() !!}
返回:
<meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1">