Skip to content

Commit

Permalink
Add Nova 4 Support (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
milewski committed Sep 19, 2023
1 parent 703271c commit a4f201b
Show file tree
Hide file tree
Showing 30 changed files with 6,351 additions and 763 deletions.
120 changes: 56 additions & 64 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,55 @@
[![Total Downloads](https://img.shields.io/packagist/dt/digital-creative/nova-filepond)](https://packagist.org/packages/digital-creative/nova-filepond)
[![License](https://img.shields.io/packagist/l/digital-creative/nova-filepond)](https://github.com/dcasia/nova-filepond/blob/master/LICENSE)

![Laravel Nova Filepond in action](https://raw.githubusercontent.com/dcasia/nova-filepond/master/screenshots/demo-1.gif)
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/dcasia/nova-filepond/main/screenshots/dark.png">
<img alt="Laravel Nova Filepond in action" src="https://raw.githubusercontent.com/dcasia/nova-filepond/main/screenshots/light.png">
</picture>

A Nova field for uploading File, Image and Video using [Filepond](https://github.com/pqina/filepond).

# Installation

You can install the package via composer:

```
```shell
composer require digital-creative/nova-filepond
```

# Features

- Single/Multiple files upload
- Sortable files
- Preview images, videos and audio
- Enable / Disable preview
- Extends the original Laravel Nova File field giving you access to all the methods/functionality of the default file upload.
- Drag and drop files
- Paste files directly from the clipboard
- Store custom attributes (original file name, size, etc)
- Prunable files (Auto delete files when the model is deleted)
- Dark mode support

# Usage

The field extends the original Laravel Nova File field, so you can use all the methods available in the original field.

Basic usage:

```php
use DigitalCreative\Filepond\Filepond;

class Post extends Resource
{
public function fields(Request $request)
public function fields(NovaRequest $request): array
{
return [
// ...
Filepond::make('Audio Example')
->multiple() // the default is single upload, use this method to allow multiple uploads
->limit(4) // limit the number of attached files
->rules('required') // every validation rule works!!
->mimesTypes([ 'audio/mp3', 'audio/ogg', 'audio/vnd.wav' ]) // if opmited, accepts anything
->disk('public', '/optional/location') // the second argument instruct the file to be stored into a subfolder
->storeAs(function (Illuminate\Http\File $file) { // this is optional, use in case you need generate custom file names
return Str::random(20) . '.' . $file->getExtension();
})

Filepond::make('Images', 'images')
->rules('required')
->prunable()
->disablePreview()
->multiple()
->limit(4),
];

}
}
```
Expand All @@ -47,68 +61,46 @@ When uploading multiple files you will need to cast the attribute to an array in

```php
class Post extends Model {

/**
* The attributes that should be cast to native types.
*
* @var array
*/

protected $casts = [
'images' => 'array'
];

}
```


# Adding an Image Editor

To enable image editing for your users you have to add the [Doka Image Editor](https://pqina.nl/doka/?ref=nova-filepond).

1. Get a license for the editor and download the Doka library files.

2. Publish the configuration file:

```bash
php artisan vendor:publish --provider="DigitalCreative\Filepond\FilepondServiceProvider" --tag="config"
```

3. Set `doka.enabled` to `true` and update the path to the `doka.min.js` and `doka.min.css` library files.
You can also store original file name / size by using `storeOriginalName` and `storeOriginalSize` methods.

```php
'doka' => [
'enabled' => true,
'js_path' => public_path('doka.min.js'), // this assumes you places theses files within your public directory
'css_path' => public_path('doka.min.css'),
]
```

4. Two options are available to enable/disable Doka on a given field, `->withDoka($options)` accepts a list of options,
you can find the documentation of all possible options here: https://pqina.nl/doka/docs/patterns/api/doka-instance/#properties
use DigitalCreative\Filepond\Filepond;

```php
public function fields(Request $request)
class Post extends Resource
{
return [
//...

Filepond::make('Avatar')->withDoka([
'cropShowSize' => true
]),

/**
* This will disable Doka for this specific field
*/
Filepond::make('Simple Image')->withoutDoka(),

];
public function fields(NovaRequest $request): array
{
return [
Filepond::make('Images', 'images')
->storeOriginalName('name')
->storeSize('size')
->multiple(),

// or you can manually decide how to store the data
// Note: the store method will be called for each file uploaded and the output will be stored into a single json column
Filepond::make('Images', 'images')
->multiple()
->store(function (NovaRequest $request, Model $model, string $attribute): array {
return [
$attribute => $request->images->store('/', 's3'),
'name' => $request->images->getClientOriginalName(),
'size' => $request->images->getSize(),
'metadata' => '...'
];
})
];
}
}
```

If you've setup everything correctly you should see the edit icon on top of FilePond images.

![Laravel Nova Filepond with Doka in action](https://raw.githubusercontent.com/dcasia/nova-filepond/master/screenshots/demo-2.png)

> Note when using `storeOriginalName` and `storeSize` methods, you will need to add the columns to your database table if you are in "single" file mode.
## License

Expand Down
7 changes: 4 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"video",
"laravel",
"nova",
"field",
"doka"
"nova4",
"field"
],
"authors": [
{
Expand All @@ -17,7 +17,8 @@
],
"license": "MIT",
"require": {
"php": ">=7.1.0"
"php": ">=8.1",
"laravel/nova": "^4.0"
},
"autoload": {
"psr-4": {
Expand Down
60 changes: 8 additions & 52 deletions config/nova-filepond.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
<?php

declare(strict_types = 1);

return [

'temp_disk' => 'local',
'temp_path' => 'nova-filepond/temp',

/**
* All the values will pass through the trans() function
* All the values will pass through the Nova::__() function
*/
'labels' => [
'decimalSeparator' => 'auto',
Expand All @@ -28,56 +34,6 @@
'buttonAbortItemProcessing' => 'Cancel',
'buttonUndoItemProcessing' => 'Undo',
'buttonRetryItemProcessing' => 'Retry',
'buttonProcessItem' => 'Upload'
'buttonProcessItem' => 'Upload',
],
'doka' => [

/**
* Only enable if you have setup doka.min.js correctly, you can find more details how to obtain these files here: https://pqina.nl/doka/?ref=nova-filepond#pricing
* Please use the browser version of doka.min.js.js
*/
'enabled' => false,
'js_path' => public_path('doka.min.js'),
'css_path' => public_path('doka.min.css'),

/**
* Global options, every options contained in here will be merged with every instance of Filepond you create
*/
'options' => [
/**
* Uncomment this to use a circular mask instead of a rectangular one
*/
// 'cropMask' => <<<JAVASCRIPT
// (root, setInnerHTML) => {
// setInnerHTML(root, `
// <mask id="circular-mask">
// <rect x="0" y="0" width="100%" height="100%" fill="white"/>
// <circle cx="50%" cy="50%" r="50%" fill="black"/>
// </mask>
// <rect fill="rgba(255,255,255,.3125)" x="0" y="0" width="100%" height="100%" mask="url(#circular-mask)"/>
// <circle cx="50%" cy="50%" r="50%" fill="transparent" stroke-width="1" stroke="#fff"/>
// `);
// }
// JAVASCRIPT,
'cropShowSize' => true,
'cropAspectRatioOptions' => [
[
'label' => 'Free',
'value' => null
],
[
'label' => 'Portrait',
'value' => 1.25
],
[
'label' => 'Square',
'value' => 1
],
[
'label' => 'Landscape',
'value' => .75
]
]
]
]
];
3 changes: 2 additions & 1 deletion dist/js/field.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/mix-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"/js/field.js": "/js/field.js"
}
}
33 changes: 33 additions & 0 deletions nova.mix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const mix = require('laravel-mix')
const webpack = require('webpack')
const path = require('path')

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

register(name) {
this.name = name
}

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())
40 changes: 16 additions & 24 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,31 +1,23 @@
{
"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"
"watch": "mix watch",
"production": "mix --production",
"nova:install": "npm --prefix='../../vendor/laravel/nova' ci"
},
"devDependencies": {
"cross-env": "^5.0.0",
"laravel-mix": "^1.0",
"laravel-nova": "^1.0"
},
"dependencies": {
"filepond": "^4.7.2",
"filepond-plugin-file-validate-type": "^1.2.4",
"filepond-plugin-image-crop": "^2.0.3",
"filepond-plugin-image-edit": "^1.4.0",
"filepond-plugin-image-exif-orientation": "^1.0.6",
"filepond-plugin-image-overlay": "^1.0.4",
"filepond-plugin-image-preview": "^4.4.0",
"filepond-plugin-image-resize": "^2.0.4",
"filepond-plugin-image-transform": "^3.4.3",
"filepond-plugin-media-preview": "^1.0.3",
"vue": "^2.5.0",
"vue-filepond": "^5.1.3"
"@vue/compiler-sfc": "^3.3.4",
"filepond": "^4.30.4",
"filepond-plugin-file-validate-size": "^2.2.8",
"filepond-plugin-file-validate-type": "^1.2.8",
"filepond-plugin-image-exif-orientation": "^1.0.11",
"filepond-plugin-image-preview": "^4.6.11",
"filepond-plugin-media-preview": "^1.0.11",
"laravel-mix": "^6.0.49",
"postcss": "^8.4.29",
"sass": "^1.67.0",
"sass-loader": "^13.3.2",
"vue-filepond": "^7.0.4",
"vue-loader": "^17.2.2"
}
}
25 changes: 25 additions & 0 deletions resources/js/components-original/DetailField.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<template>

<panel-item :field="field">

<file-pond-wrapper
slot="value"
:disabled="true"
:allow-image-preview="!field.multiple"
:limit="field.value.length"
:field="field"/>

</panel-item>

</template>

<script>
import FilePondWrapper from './FilePondWrapper'
export default {
components: {FilePondWrapper},
props: ['resource', 'resourceName', 'resourceId', 'field']
}
</script>
Loading

0 comments on commit a4f201b

Please sign in to comment.