redbastie / swift
基于 SwiftUI 的 Laravel Livewire 实现。
Requires
- doctrine/dbal: ^2.10
- laravel/framework: ^8.0
- livewire/livewire: ^2.0
README
请查看我的新软件包: https://github.com/bastinald/malzahar
这是一个更好的实现,比这个软件包尝试实现的功能更优秀。
Laravel Swift
告别 HTML、CSS 和 JavaScript!Laravel Swift 是基于 Laravel Livewire 的 SwiftUI 实现。它底层使用 Laravel、Livewire、Bootstrap、Font Awesome 等。
这是我对于 PHP 开发未来愿景的软件包。它是为后端/CRUD 应用而设计的,但适用于任何类型的应用。它还包含自动路由和迁移等实用功能,以加快您的工作速度并进一步降低代码抽象级别。
为了最好地使用 Swift,您应该熟悉以下内容
要求
- 能够运行 Laravel 8 的 Web 服务器
- NPM
链接
- 支持: GitHub Issues
- 贡献: GitHub Pulls
- 捐赠: PayPal
安装
此软件包旨在与干净的 Laravel 8 安装一起使用。所有 Swift 应用程序都默认包含基本身份验证框架和用户 CRUD。
安装 Laravel
laravel new app
在您的 .env
文件中配置数据库
DB_DATABASE=app
DB_USERNAME=root
DB_PASSWORD=
通过 composer 需求 Swift
composer require redbastie/swift
运行安装命令
php artisan install:swift
现在您可以访问您的应用程序 URL 并使用 user@example.com:password
登录,这是通过 DatabaseSeeder
类创建的。
创建组件
生成基本组件
php artisan make:swift ComponentName
这将创建在 app/Http/Livewire
目录中的组件。
生成基本全页组件
php artisan make:page PageName
这将创建在 app/Http/Livewire
目录中的全页组件。
为新的模型生成 CRUD 框架
php artisan make:crud ModelName
这将创建模型、工厂、导航项和 CRUD 组件。
为新的模型生成具有共享表单字段和规则的 CRUD
php artisan make:crudtrait ModelName
这将创建模型、工厂、导航项、CRUD 组件和特性。
生成新的 Swift 模型
php artisan make:swiftmodel ModelName
这将创建模型和工厂。
使用组件
全页组件应指定 $routeUri
和 $pageTitle
属性
public $routeUri = '/tao';
public $routeName = 'tao'; // optional
public $routeMiddleware = 'auth'; // optional
public $pageTitle = 'The Tao';
Swift 组件必须实现一个 view
方法
public function view()
{
return S::div(
S::livewire('layouts.navbar'),
S::container(
S::paragraph('Stop trying to control.')
)
);
}
在 view
中使用子组件
S::livewire('layouts.navbar'),
可用组件
警报
S::alert('Something happened!')->success(),
方法:dismissable
、fade
、primary
、secondary
、success
、info
、danger
、warning
、light
、dark
徽章
S::badge('New')->primary(),
方法:primary
、secondary
、success
、info
、danger
、warning
、light
、dark
、pill
引用
S::blockquote('Be like water.')->footer('The Tao'),
方法:footer
面包屑
S::breadcrumb(
S::breadcrumbItem('Home'),
S::breadcrumbItem('Page'),
),
方法:无
面包屑项
S::breadcrumbItem('Home')->active(Route::is('home')),
方法:active
按钮
S::button('Do Something')->primary()->click('doSomething'),
方法:submit
、primary
、secondary
、success
、info
、danger
、warning
、light
、dark
、outlinePrimary
、outlineSecondary
、outlineSuccess
、outlineInfo
、outlineDanger
、outlineWarning
、outlineLight
、outlineDark
、link
、active
、sm
、lg
、block
、disabled
按钮组
S::buttonGroup(
S::button('Do Something')->primary()->click('doSomething'),
S::button('Something Else')->secondary()->click('somethingElse'),
),
方法:无
按钮工具栏
S::buttonToolbar(
S::buttonGroup(
S::button('Do Something')->primary()->click('doSomething'),
S::button('Something Else')->secondary()->click('somethingElse'),
),
),
方法:无
卡片
S::card()
->header('Hello World')
->body('The whole world belongs to you')
->footer('The Tao'),
方法:header
、image
、body
、footer
复选框
S::checkbox('agree')->label('Agree to TOS')->modelDefer(),
方法:label
、checkboxLabel
、help
、switch
、inline
、disabled
、model
、modelDebounce
、modelDefer
、modelLazy
代码
S::code('$hello = $world;'),
方法:无
列(网格)
S::col('Be like water.')->md(2),
方法:xs
、auto
、sm
、smAuto
、md
、mdAuto
、lg
、lgAuto
、xl
、xlAuto
、offset
、offsetSm
、offsetMd
、offsetLg
、offsetXl
容器
S::container(
S::paragraph('In work, do what you enjoy.'),
),
方法:无
Div
S::div('The best athlete wants his opponent at his best.'),
方法:无
下拉菜单
S::dropdown()
->toggle(
S::button('Dropdown')->primary()->dropdownToggle()
)
->items(
S::button('Do Something')->dropdownItem(),
S::button('Something Else')->dropdownItem(),
),
方法:toggle
、items
、right
、smRight
、mdRight
、lgRight
、xlRight
、left
、smLeft
、mdLeft
、lgLeft
、xlLeft
每个(循环)
S::each(['Red', 'Green', 'Blue'], function ($color, $key) {
return S::div($key . ': ' . $color);
})->empty(
S::paragraph('No colors to display.')
),
方法:empty
文件
S::file('avatar')->label('Avatar')->placeholder('Choose avatar')->modelDefer(),
方法:label
、placeholder
、help
、model
、modelDebounce
、modelDefer
、modelLazy
表单
S::form(
S::input('first_name')->label('First Name')->modelDefer(),
S::input('last_name')->label('Last Name')->modelDefer(),
S::button('Submit')->submit()->primary(),
)->submitPrevent('submitForm'),
方法:inline
、submit
、submitPrevent
、submitSelf
、submitStop
表单组
S::formGroup(
S::label('First Name'),
S::input('first_name')->modelDefer(),
),
方法:label
表单行
S::formRow(
S::col(S::input('first')->placeholder('First')->model())->md(),
S::col(S::input('last')->placeholder('Last')->model())->md(),
),
方法:无
标题
S::heading('Laravel Swift')->size(2),
方法:size
水平线
S::horizontalRule(),
方法:无
图标(Font Awesome)
S::icon('pastafarianism'),
方法:solid
、regular
、light
、duotone
、brand
、fw
、xs
、sm
、lg
、x
、spin
、pulse
条件判断(If)
// $color = 'Green';
S::if($color == 'Red', function () {
return S::paragraph('The color is red.');
})->elseif($color == 'Green', function () {
return S::paragraph('The color is green.');
})->else(function () {
return S::paragraph('The color is blue.');
}),
方法:elseif
、else
iframe
S::iframe('http://maps.google.com/maps?q=pizza+pizza+oshawa&z=10&output=embed')->width('100%')->height(300),
方法:width
、height
图片
S::image('https://i.imgur.com/zplGJnj.png')->alt('Time to kick it!'),
方法:alt
、fluid
、thumbnail
输入框
S::input('email')->type('email')->label('Email Address')->modelDefer(),
方法:type
、label
、help
、placeholder
、sm
、lg
、disabled
、readonly
、keydown
、model
、modelDebounce
、modelDefer
、modelLazy
输入组合
S::inputGroup(
S::input('first_name')->placeholder('First Name')->modelDefer(),
S::input('last_name')->placeholder('First Name')->modelDefer(),
)->prepend(
S::icon('user'),
),
方法:label
、prepend
、append
、sm
、lg
标签
S::label('Email Address'),
方法:for
换行
S::linebreak(),
方法:无
链接
S::link('Go To Reddit')->href('https://reddit.com'),
方法:href
、target
、active
、disabled
、stretched
列表
S::list(
S::listItem('Broccoli'),
S::listItem('Carrot'),
S::listItem('Lettuce'),
),
方法:ordered
、unstyled
、inline
列表项
S::listItem('Carrot'),
方法:无
列表组
S::listGroup(
S::listGroupItem('Broccoli'),
S::listGroupItem('Carrot'),
S::listGroupItem('Lettuce'),
),
方法:flush
、horizontal
列表组项
S::listGroupItem('Broccoli'),
方法:primary
、secondary
、success
、info
、danger
、warning
、light
、dark
、action
、active
、disabled
Livewire(组件)
S::livewire('home', ['hello' => 'world']),
方法:无
模态框
S::modal('create-modal')->heading('Create Contact')
->body(
S::input('first_name')->label('First Name')->modelDefer(),
S::input('last_name')->label('Last Name')->modelDefer(),
)
->footer(
S::button('Cancel')->secondary()->click('$emit', 'hideModal', 'create-modal'),
S::button('Save')->primary()->click('save')
)
方法:heading
、body
、footer
、fade
、sm
、lg
、xl
导航栏
S::navbar(
S::navbarBrand(config('app.name'))->href('/'),
S::navbarToggler(),
S::navbarCollapse(
S::navbarNav(
S::navItem(S::navLink('Login')->href(route('login'))),
S::navItem(S::navLink('Register')->href(route('register'))),
),
),
)->expandMd()->light(),
方法:expand
、expandSm
、expandMd
、expandLg
、expandXl
、light
、dark
导航栏品牌
S::navbarBrand(config('app.name'))->href('/'),
方法:href
、active
、disabled
、stretched
导航栏折叠
S::navbarCollapse(
S::navbarNav(
S::navItem(S::navLink('Login')->href(route('login'))),
S::navItem(S::navLink('Register')->href(route('register'))),
),
),
方法:无
导航栏导航
S::navbarNav(
S::navItem(S::navLink('Login')->href(route('login'))),
S::navItem(S::navLink('Register')->href(route('register'))),
),
方法:无
导航栏切换器
S::navbarToggler(),
方法:无
导航
S::nav(
S::navItem(S::navLink('First Tab')->active()),
S::navItem(S::navLink('Second Tab')),
)->tabs(),
方法:tabs
、pills
、fill
、justified
导航下拉菜单
S::navDropdown()
->toggle(
S::navLink(auth()->user()->name)->dropdownToggle(),
)
->items(
S::link('Profile')->dropdownItem()->href('/profile'),
S::button('Logout')->dropdownItem()->click('logout'),
),
方法:toggle
、items
、right
、smRight
、mdRight
、lgRight
、xlRight
、left
、smLeft
、mdLeft
、lgLeft
、xlLeft
导航链接
S::navLink('Home')->href('/'),
方法:href
、active
、disabled
、stretched
分页
// $users = User::query()->paginate();
S::pagination($users),
方法:无
段落
S::paragraph('Close your eyes. Count to one. That is how long forever feels.'),
方法:无
预格式化文本
S::pre(json_encode(['Red', 'Green', 'Blue'], JSON_PRETTY_PRINT)),
方法:无
进度条
S::progressBar(25)->label('Completed'),
方法:label
、striped
、animated
单选框
S::radio('gender')->options(['Male', 'Female'])->modelDefer(),
方法:options
、label
、help
、inline
、disabled
、model
、modelDebounce
、modelDefer
、modelLazy
行(网格)
S::row(
S::col('Hello')->xs(),
S::col('World')->xs(),
),
方法:noGutters
选择框
S::select('gender')->options(['Male', 'Female'])->modelDefer(),
方法:options
、label
、placeholder
、help
、sm
、lg
、disabled
、model
、modelDebounce
、modelDefer
、modelLazy
占位符
S::span('Do your work, then step back.'),
方法:无
表格
S::table(
S::tableBody(
S::tableRow(
S::tableData('Name'),
S::tableData('Email'),
),
),
),
方法:responsive
、dark
、striped
、bordered
、borderless
、hover
、sm
表格体
S::tableBody(
S::tableRow(
S::tableData('Name'),
S::tableData('Email'),
),
),
方法:无
表格数据
S::tableData('Name'),
方法:active
、primary
、secondary
、success
、info
、danger
、warning
、light
、dark
表格头
S::tableHead(
S::tableRow(
S::tableHeader('Name'),
S::tableHeader('Email'),
),
),
方法:light
、dark
表格标题
S::tableHeader('Name'),
方法:active
、primary
、secondary
、success
、info
、danger
、warning
、light
、dark
表格行
S::tableRow(
S::tableHeader('Name'),
S::tableHeader('Email'),
),
方法:active
、primary
、secondary
、success
、info
、danger
、warning
、light
、dark
文本域
S::textarea('bio')->label('Biography')->modelDefer(),
方法:rows
、label
、help
、placeholder
、sm
、lg
、disabled
、readonly
、keydown
、model
、modelDebounce
、modelDefer
、modelLazy
视图
S::view('my-view-name', ['hello' => 'world']),
方法:无
组件工具
Bootstrap
所有组件都可以访问 Bootstrap 工具。它们的方法命名与相应的 Bootstrap CSS 类相似。
例如,设置背景颜色
S::div('Hello world!')->bgDanger(),
调整填充、边距等
S::div('Hello world!')->bgDanger()->p(2)->mb(3),
还有一些 Bootstrap JavaScript 工具也可用,如 collapse
S::button('Collapse Paragraph')->info()->collapseToggle('para'),
S::paragraph('In work, do what you enjoy.')->collapse('para'),
显示/隐藏模态框
S::button('Show Modal')->primary()->click('$emit', 'showModal', 'the-modal'),
S::modal('the-modal')->heading('The Modal')
->body(S::paragraph('Stop trying to control.'))
->footer(S::button('Close')->secondary()->click('$emit', 'hideModal', 'the-modal'),
显示通知
$this->emit('toastError', 'Oh no! There was a problem.');
Livewire
Livewire 动作使用相应的 wire:
规范进行映射。
例如,设置 click
动作
S::button('Delete')->danger()->click('deleteItem'),
在这种情况下,您组件中会有一个 deleteItem
函数。
带有一个或多个参数的 click
动作
S::link('Update')->clickPrevent('updateItem', $item->id),
S::button('Close')->secondary()->click('$emit', 'hideModal', 'the-modal'),
建模输入元素
S::input('name')->label('Name')->modelLazy(),
S::textarea('desc')->label('Description')->modelDefer(),
输入名称将自动通过指定的模型方法连接。您可以通过组件中的 $this->model
属性数组访问这些数据。例如,$this->model['name']
。
loading
和 polling
S::span('Loading...')->loading(),
S::span(now())->poll(),
深入挖掘
查看包 Traits 中所有实用方法的完整列表及其参数。
自动化
自动路由
创建全页面的Swift组件时,只需声明一个$routeUri
属性,即可实现自动路由组件
class Login extends SwiftComponent
{
public $routeUri = '/login';
您可以通过route:list
artisan命令查看您的路由列表。
自动迁移
为了使用自动迁移,只需在您的模型中指定一个migration
方法
class Lead extends Model
{
use SwiftModel;
public function migration(Blueprint $table)
{
$table->id();
$table->string('name');
$table->timestamps();
}
现在运行自动迁移命令
php artisan migrate:auto
该包使用Doctrine DBAL来对比现有模型表并对其进行必要的更改。如果表不存在,它将创建它。
您还可以向migrate:auto
命令传递--fresh
和/或--seed
,以获取新的迁移并在之后运行您的种子文件
php artisan migrate:auto --fresh --seed
如果您的应用在database/migrations
文件夹中包含传统迁移,它们将在自动迁移之前进行处理。
自动填充
包含SwiftModel
特质的模型具有自动填充功能,这意味着它们的$fillable
属性将通过模型表列名自动生成。
配置、视图和翻译
可以使用vendor:publish
命令发布配置、视图和翻译文件。