redbastie/swift

该软件包已被放弃,不再维护。未建议替代软件包。

基于 SwiftUI 的 Laravel Livewire 实现。

1.2.2 2020-11-24 12:22 UTC

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

链接

安装

此软件包旨在与干净的 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(),

方法:dismissablefadeprimarysecondarysuccessinfodangerwarninglightdark

徽章

S::badge('New')->primary(),

方法:primarysecondarysuccessinfodangerwarninglightdarkpill

引用

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'),

方法:submitprimarysecondarysuccessinfodangerwarninglightdarkoutlinePrimaryoutlineSecondaryoutlineSuccessoutlineInfooutlineDangeroutlineWarningoutlineLightoutlineDarklinkactivesmlgblockdisabled

按钮组

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'),

方法:headerimagebodyfooter

复选框

S::checkbox('agree')->label('Agree to TOS')->modelDefer(),

方法:labelcheckboxLabelhelpswitchinlinedisabledmodelmodelDebouncemodelDefermodelLazy

代码

S::code('$hello = $world;'),

方法:无

列(网格)

S::col('Be like water.')->md(2),

方法:xsautosmsmAutomdmdAutolglgAutoxlxlAutooffsetoffsetSmoffsetMdoffsetLgoffsetXl

容器

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(),
    ),

方法:toggleitemsrightsmRightmdRightlgRightxlRightleftsmLeftmdLeftlgLeftxlLeft

每个(循环)

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(),

方法:labelplaceholderhelpmodelmodelDebouncemodelDefermodelLazy

表单

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'),

方法:inlinesubmitsubmitPreventsubmitSelfsubmitStop

表单组

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'),

方法:solidregularlightduotonebrandfwxssmlgxspinpulse

条件判断(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.');
}),

方法:elseifelse

iframe

S::iframe('http://maps.google.com/maps?q=pizza+pizza+oshawa&z=10&output=embed')->width('100%')->height(300),

方法:widthheight

图片

S::image('https://i.imgur.com/zplGJnj.png')->alt('Time to kick it!'),

方法:altfluidthumbnail

输入框

S::input('email')->type('email')->label('Email Address')->modelDefer(),

方法:typelabelhelpplaceholdersmlgdisabledreadonlykeydownmodelmodelDebouncemodelDefermodelLazy

输入组合

S::inputGroup(
    S::input('first_name')->placeholder('First Name')->modelDefer(),
    S::input('last_name')->placeholder('First Name')->modelDefer(),
)->prepend(
    S::icon('user'),
),

方法:labelprependappendsmlg

标签

S::label('Email Address'),

方法:for

换行

S::linebreak(),

方法:无

链接

S::link('Go To Reddit')->href('https://reddit.com'),

方法:hreftargetactivedisabledstretched

列表

S::list(
    S::listItem('Broccoli'),
    S::listItem('Carrot'),
    S::listItem('Lettuce'),
), 

方法:orderedunstyledinline

列表项

S::listItem('Carrot'),

方法:无

列表组

S::listGroup(
    S::listGroupItem('Broccoli'),
    S::listGroupItem('Carrot'),
    S::listGroupItem('Lettuce'),
),

方法:flushhorizontal

列表组项

S::listGroupItem('Broccoli'),

方法:primarysecondarysuccessinfodangerwarninglightdarkactionactivedisabled

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')
    )

方法:headingbodyfooterfadesmlgxl

导航栏

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(),

方法:expandexpandSmexpandMdexpandLgexpandXllightdark

导航栏品牌

S::navbarBrand(config('app.name'))->href('/'),

方法:hrefactivedisabledstretched

导航栏折叠

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(),

方法:tabspillsfilljustified

导航下拉菜单

S::navDropdown()
    ->toggle(
        S::navLink(auth()->user()->name)->dropdownToggle(),
    )
    ->items(
        S::link('Profile')->dropdownItem()->href('/profile'),
        S::button('Logout')->dropdownItem()->click('logout'),
    ),

方法:toggleitemsrightsmRightmdRightlgRightxlRightleftsmLeftmdLeftlgLeftxlLeft

导航链接

S::navLink('Home')->href('/'),

方法:hrefactivedisabledstretched

分页

// $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'),

方法:labelstripedanimated

单选框

S::radio('gender')->options(['Male', 'Female'])->modelDefer(),

方法:optionslabelhelpinlinedisabledmodelmodelDebouncemodelDefermodelLazy

行(网格)

S::row(
    S::col('Hello')->xs(),
    S::col('World')->xs(),
),

方法:noGutters

选择框

S::select('gender')->options(['Male', 'Female'])->modelDefer(),

方法:optionslabelplaceholderhelpsmlgdisabledmodelmodelDebouncemodelDefermodelLazy

占位符

S::span('Do your work, then step back.'),

方法:无

表格

S::table(
    S::tableBody(
        S::tableRow(
            S::tableData('Name'),
            S::tableData('Email'),
        ),
    ),
),

方法:responsivedarkstripedborderedborderlesshoversm

表格体

S::tableBody(
    S::tableRow(
        S::tableData('Name'),
        S::tableData('Email'),
    ),
),

方法:无

表格数据

S::tableData('Name'),

方法:activeprimarysecondarysuccessinfodangerwarninglightdark

表格头

S::tableHead(
    S::tableRow(
        S::tableHeader('Name'),
        S::tableHeader('Email'),
    ),
),

方法:lightdark

表格标题

S::tableHeader('Name'),

方法:activeprimarysecondarysuccessinfodangerwarninglightdark

表格行

S::tableRow(
    S::tableHeader('Name'),
    S::tableHeader('Email'),
),

方法:activeprimarysecondarysuccessinfodangerwarninglightdark

文本域

S::textarea('bio')->label('Biography')->modelDefer(),

方法:rowslabelhelpplaceholdersmlgdisabledreadonlykeydownmodelmodelDebouncemodelDefermodelLazy

视图

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']

loadingpolling

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命令发布配置、视图和翻译文件。