Skip to content

Commit

Permalink
Add laravel/nova:~4.0 support
Browse files Browse the repository at this point in the history
Update the package to support laravel/nova:~4.0. The javascript package `momentjs` is no longer
used by Laravel Nova. The way to format times has therefore been updated. It now uses the PHP
datetime format.

Support for older versions of Laravel Nova has been dropped.
  • Loading branch information
michielfb committed Feb 8, 2023
1 parent 97a80a1 commit c12bf39
Show file tree
Hide file tree
Showing 19 changed files with 356 additions and 116 deletions.
49 changes: 40 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

This package adds a basic HTML5 time field to Laravel Nova.

## Requirements

This package require laravel/nova:~4.0.

## Installation
Use composer to install the package.
Expand All @@ -10,25 +13,44 @@ Use composer to install the package.
composer require michielfb/laravel-nova-time-field
```


## Usage
The display format of the `Time` field can be customized using the `format` method.
The format must be a format supported by `Moment.js`.

The example below shows how to create a Time field where users can enter hours, minutes, and
seconds. The time is show in the "h:i A" format (For example 11:15 PM). When no value is
entered the value "n/a" is shown.

```php
<?php
```php
use Michielfb\Time\Time;

Time::make('Time')
->withSeconds()
->format('h:i A', 'n/a');
```

For documentation on how to add fields to a resource see the
[Laravel Nova documentation](https://nova.laravel.com/docs/4.0/resources/fields.html).

### Format

Use the `format` method to customize how to date is shown to users. The format must be a
[PHP date format](https://www.php.net/manual/en/datetime.format.php).

A default value can be passed to the `format` method. This determines the value shown to users if there is no
value entered.

```php
use Michielfb\Time\Time;

Time::make('Time')->format('HH:mm');
Time::make('Time')
->format('h:i A', '-');
```

### Steps

The [step attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/time#Using_the_step_attribute)
can be configured by using the `withSteps` method.

```php
```php
<?php
use Michielfb\Time\Time;

Expand All @@ -37,9 +59,18 @@ Time::make('Time')->withSteps(1);

The `withSeconds` method sets a step of 1 which allows users to enter seconds.

```php
```php
<?php
use Michielfb\Time\Time;

Time::make('Time')->withSeconds();
```
```

The `withMilliseconds` method sets a step of 0.001 which allows users to enter milliseconds.

```php
<?php
use Michielfb\Time\Time;

Time::make('Time')->withMilliseconds();
```
14 changes: 11 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
{
"name": "michielfb/laravel-nova-time-field",
"description": "A HTML5 time field for Laravel Nova.",
"name": "michielfb/time",
"description": "A Laravel Nova field.",
"keywords": [
"laravel",
"nova"
],
"license": "MIT",
"require": {
"php": ">=7.1.0"
"php": "^7.3|^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.5.10"
},
"autoload": {
"psr-4": {
"Michielfb\\Time\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Michielfb\\Time\\Tests\\": "tests/"
}
},
"extra": {
"laravel": {
"providers": [
Expand Down
1 change: 1 addition & 0 deletions dist/css/field.css
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

3 changes: 2 additions & 1 deletion dist/js/field.js

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions dist/js/field.js.LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/*!
* vuex v4.0.2
* (c) 2021 Evan You
* @license MIT
*/
2 changes: 1 addition & 1 deletion dist/mix-manifest.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"/js/field.js": "/js/field.js",
"/css/field.css": "/css/field.css"
}
}
40 changes: 40 additions & 0 deletions nova.mix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const mix = require('laravel-mix')
const webpack = require('webpack')
const path = require('path')

class NovaExtension {
name() {
return 'nova-extension'
}

register(name) {
this.name = name
}

webpackPlugins() {
return new webpack.ProvidePlugin({
_: 'lodash',
Errors: 'form-backend-validation',
})
}

webpackConfig(webpackConfig) {
webpackConfig.externals = {
vue: 'Vue',
}

webpackConfig.resolve.alias = {
...(webpackConfig.resolve.alias || {}),
'laravel-nova': path.join(
__dirname,
'../../vendor/laravel/nova/resources/js/mixins/packages.js'
),
}

webpackConfig.output = {
uniqueName: this.name,
}
}
}

mix.extend('nova', new NovaExtension())
38 changes: 20 additions & 18 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
{
"private": true,
"scripts": {
"dev": "npm run development",
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch-poll": "npm run watch -- --watch-poll",
"hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
"prod": "npm run production",
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
},
"devDependencies": {
"cross-env": "^5.0.0",
"laravel-mix": "^1.0",
"laravel-nova": "^1.0"
},
"dependencies": {
"vue": "^2.5.0"
}
"private": true,
"scripts": {
"dev": "npm run development",
"development": "mix",
"watch": "mix watch",
"watch-poll": "mix watch -- --watch-options-poll=1000",
"hot": "mix watch --hot",
"prod": "npm run production",
"production": "mix --production",
"nova:install": "npm --prefix='../../vendor/laravel/nova' ci"
},
"devDependencies": {
"@vue/compiler-sfc": "^3.2.22",
"form-backend-validation": "^2.3.3",
"laravel-mix": "^6.0.41",
"lodash": "^4.17.21",
"postcss": "^8.3.11",
"vue-loader": "^16.8.3"
},
"dependencies": {}
}
1 change: 1 addition & 0 deletions postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = {}
1 change: 1 addition & 0 deletions resources/css/field.css
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/* Nova Field CSS */
27 changes: 2 additions & 25 deletions resources/js/components/DetailField.vue
Original file line number Diff line number Diff line change
@@ -1,32 +1,9 @@
<template>
<panel-item :field="field" />
<PanelItem :index="index" :field="field" />
</template>

<script>
export default {
props: ['field'],
}
</script>

<template>
<panel-item :field="field">
<template slot="value">
<p v-if="field.value" class="text-90">{{ formattedDate }}</p>
<p v-else>&mdash;</p>
</template>
</panel-item>
</template>

<script>
export default {
props: ['field'],
computed: {
formattedDate() {
return this.field.value
? moment(this.field.value, this.field.format).format(this.field.format)
: '-';
}
}
props: ['index', 'resource', 'resourceName', 'resourceId', 'field'],
}
</script>
70 changes: 34 additions & 36 deletions resources/js/components/FormField.vue
Original file line number Diff line number Diff line change
@@ -1,48 +1,46 @@
<template>
<default-field :field="field" :errors="errors" :show-help-text="showHelpText">
<template slot="field">
<input :id="field.name"
type="time"
class="w-full form-control form-input form-input-bordered"
:class="errorClasses"
:placeholder="field.name"
:disabled="isReadonly"
:step="field.step !== undefined ? field.step : false"
v-model="value"
/>
</template>
</default-field>
<DefaultField
:field="field"
:errors="errors"
:show-help-text="showHelpText"
:full-width-content="fullWidthContent"
>
<template #field>
<input
:id="field.attribute"
type="time"
class="w-full form-control form-input form-input-bordered"
:class="errorClasses"
:placeholder="field.name"
:step="field.step !== undefined ? field.step : false"
v-model="value"
/>
</template>
</DefaultField>
</template>

<script>
import { FormField, HandlesValidationErrors } from 'laravel-nova'
export default {
mixins: [FormField, HandlesValidationErrors],
mixins: [FormField, HandlesValidationErrors],
props: ['resourceName', 'resourceId', 'field'],
props: ['resourceName', 'resourceId', 'field'],
methods: {
/*
* Set the initial, internal value for the field.
*/
setInitialValue() {
this.value = this.field.value || ''
},
methods: {
/*
* Set the initial, internal value for the field.
*/
setInitialValue() {
this.value = this.field.value || ''
},
/**
* Fill the given FormData object with the field's internal value.
*/
fill(formData) {
formData.append(this.field.attribute, this.value || '')
},
/**
* Update the field's internal value.
*/
handleChange(value) {
this.value = value
}
}
/**
* Fill the given FormData object with the field's internal value.
*/
fill(formData) {
formData.append(this.field.attribute, this.value || '')
},
},
}
</script>
16 changes: 7 additions & 9 deletions resources/js/components/IndexField.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
<template>
<span class="whitespace-no-wrap">{{ formattedDate }}</span>
<span>{{ fieldValue }}</span>
</template>

<script>
export default {
props: ['field'],
props: ['resourceName', 'field'],
computed: {
formattedDate() {
return this.field.value
? moment(this.field.value, this.field.format).format(this.field.format)
: '-';
}
}
computed: {
fieldValue() {
return this.field.displayedAs || this.field.value
},
}
}
</script>
12 changes: 8 additions & 4 deletions resources/js/field.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
Nova.booting((Vue, router) => {
Vue.component('index-time', require('./components/IndexField'));
Vue.component('detail-time', require('./components/DetailField'));
Vue.component('form-time', require('./components/FormField'));
import IndexField from './components/IndexField'
import DetailField from './components/DetailField'
import FormField from './components/FormField'

Nova.booting((app, store) => {
app.component('index-time', IndexField)
app.component('detail-time', DetailField)
app.component('form-time', FormField)
})
1 change: 0 additions & 1 deletion resources/sass/field.scss

This file was deleted.

4 changes: 2 additions & 2 deletions src/FieldServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

namespace Michielfb\Time;

use Laravel\Nova\Nova;
use Laravel\Nova\Events\ServingNova;
use Illuminate\Support\ServiceProvider;
use Laravel\Nova\Events\ServingNova;
use Laravel\Nova\Nova;

class FieldServiceProvider extends ServiceProvider
{
Expand Down
Loading

0 comments on commit c12bf39

Please sign in to comment.