Skip to content

Commit

Permalink
Merge pull request #656 from getformwork/feature/files-and-images-input
Browse files Browse the repository at this point in the history
Improve image input, add new type file and multiple value variants (images, files)
  • Loading branch information
giuscris authored Feb 22, 2025
2 parents 9384129 + fb154eb commit 291cc9f
Show file tree
Hide file tree
Showing 21 changed files with 424 additions and 93 deletions.
61 changes: 61 additions & 0 deletions formwork/fields/file.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

use Formwork\Cms\App;
use Formwork\Data\Exceptions\InvalidValueException;
use Formwork\Fields\Exceptions\ValidationException;
use Formwork\Fields\Field;
use Formwork\Files\File;
use Formwork\Files\FileCollection;
use Formwork\Images\Image;
use Formwork\Utils\Constraint;

return function (App $app) {
return [
'return' => function (Field $field): ?File {
return $field->value() !== null
? $field->getFiles()->get($field->value())
: null;
},

'getFiles' => function (Field $field): FileCollection {
if (!$field->has('options')) {
$model = $field->parent()?->model();

if ($model === null || !method_exists($model, 'files')) {
throw new InvalidValueException(sprintf('Field "%s" of type "%s" must have a model with files', $field->name(), $field->type()));
}

return $model->files();
}

return $field->get('options');
},

'validate' => function (Field $field, $value): ?string {
if (Constraint::isEmpty($value)) {
return null;
}

if (!is_string($value)) {
throw new ValidationException(sprintf('Invalid value for field "%s" of type "%s"', $field->name(), $field->type()));
}

return $value;
},

'options' => function (Field $field): array {
$collection = $field->getFiles();

if ($field->has('fileType')) {
$collection = $collection->filter(static fn(File $file) => in_array($file->type(), (array) $field->get('fileType'), true));
}

return $collection
->map(static fn(File $file) => [
'value' => $file->name(),
'icon' => 'file-' . $file->type(),
'thumb' => $file instanceof Image ? $file->square(300, 'contain')->uri() : null,
])->toArray();
},
];
};
83 changes: 83 additions & 0 deletions formwork/fields/files.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

use Formwork\Cms\App;
use Formwork\Data\Exceptions\InvalidValueException;
use Formwork\Fields\Exceptions\ValidationException;
use Formwork\Fields\Field;
use Formwork\Files\File;
use Formwork\Files\FileCollection;
use Formwork\Images\Image;
use Formwork\Utils\Constraint;

return function (App $app) {
return [
'getFiles' => function (Field $field): FileCollection {
if (!$field->has('options')) {
$model = $field->parent()?->model();

if ($model === null || !method_exists($model, 'files')) {
throw new InvalidValueException(sprintf('Field "%s" of type "%s" must have a model with files', $field->name(), $field->type()));
}

return $model->files();
}

return $field->get('options');
},

'toString' => function ($field) {
return implode(', ', $field->value() ?? []);
},

'return' => function (Field $field): FileCollection {
return $field->getFiles()->filter(static fn(File $file) => in_array($file->name(), $field->value(), true));
},

'validate' => function (Field $field, $value): array {
if (Constraint::isEmpty($value)) {
return [];
}

if (is_string($value)) {
$value = array_map(trim(...), explode(',', $value));
}

if (!is_array($value)) {
throw new ValidationException(sprintf('Invalid value for field "%s" of type "%s"', $field->name(), $field->type()));
}

if ($field->has('pattern')) {
$value = array_filter($value, static fn($item): bool => Constraint::matchesRegex($item, $field->get('pattern')));
}

if ($field->limit() !== null && count($value) > $field->limit()) {
throw new ValidationException(sprintf('Field "%s" of type "%s" has a limit of %d items', $field->name(), $field->type(), $field->get('limit')));
}

return array_values(array_filter($value));
},

'options' => function (Field $field): array {
$collection = $field->getFiles();

if ($field->has('fileType')) {
$collection = $collection->filter(static fn(File $file) => in_array($file->type(), (array) $field->get('fileType'), true));
}

return $collection
->map(static fn(File $file) => [
'value' => $file->name(),
'icon' => 'file-' . $file->type(),
'thumb' => $file instanceof Image ? $file->square(300, 'contain')->uri() : null,
])->toArray();
},

'limit' => function (Field $field): ?int {
return $field->get('limit', null);
},

'isOrderable' => function ($field): bool {
return $field->is('orderable', true);
},
];
};
35 changes: 33 additions & 2 deletions formwork/fields/image.php
Original file line number Diff line number Diff line change
@@ -1,14 +1,36 @@
<?php

use Formwork\Cms\App;
use Formwork\Data\Exceptions\InvalidValueException;
use Formwork\Fields\Exceptions\ValidationException;
use Formwork\Fields\Field;
use Formwork\Files\File;
use Formwork\Files\FileCollection;
use Formwork\Images\Image;
use Formwork\Utils\Constraint;

return function (App $app) {
return [
'return' => function (Field $field): Field {
return $field;
'return' => function (Field $field): ?Image {
return $field->value() !== null
? $field->getImages()->get($field->value())
: null;
},

'getImages' => function (Field $field): FileCollection {
if (!$field->has('options')) {
$model = $field->parent()?->model();

if ($model === null || !method_exists($model, 'files')) {
throw new InvalidValueException(sprintf('Field "%s" of type "%s" must have a model with files', $field->name(), $field->type()));
}

$files = $model->files();
} else {
$files = $field->get('options');
}

return $files->filter(static fn(File $file) => $file instanceof Image);
},

'validate' => function (Field $field, $value): ?string {
Expand All @@ -22,5 +44,14 @@

return $value;
},

'options' => function (Field $field): array {
return $field->getImages()
->map(static fn(Image $image) => [
'value' => $image->name(),
'icon' => 'image',
'thumb' => $image->square(300, 'contain')->uri(),
])->toArray();
},
];
};
79 changes: 79 additions & 0 deletions formwork/fields/images.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php

use Formwork\Cms\App;
use Formwork\Data\Exceptions\InvalidValueException;
use Formwork\Fields\Exceptions\ValidationException;
use Formwork\Fields\Field;
use Formwork\Files\File;
use Formwork\Files\FileCollection;
use Formwork\Images\Image;
use Formwork\Utils\Constraint;

return function (App $app) {
return [
'getImages' => function (Field $field): FileCollection {
if (!$field->has('options')) {
$model = $field->parent()?->model();

if ($model === null || !method_exists($model, 'files')) {
throw new InvalidValueException(sprintf('Field "%s" of type "%s" must have a model with files', $field->name(), $field->type()));
}

$files = $model->files();
} else {
$files = $field->get('options');
}

return $files->filter(static fn(File $file) => $file instanceof Image);
},

'toString' => function ($field) {
return implode(', ', $field->value() ?? []);
},

'return' => function (Field $field): FileCollection {
return $field->getImages()->filter(static fn(File $file) => in_array($file->name(), $field->value(), true));
},

'validate' => function (Field $field, $value): array {
if (Constraint::isEmpty($value)) {
return [];
}

if (is_string($value)) {
$value = array_map(trim(...), explode(',', $value));
}

if (!is_array($value)) {
throw new ValidationException(sprintf('Invalid value for field "%s" of type "%s"', $field->name(), $field->type()));
}

if ($field->has('pattern')) {
$value = array_filter($value, static fn($item): bool => Constraint::matchesRegex($item, $field->get('pattern')));
}

if ($field->limit() !== null && count($value) > $field->limit()) {
throw new ValidationException(sprintf('Field "%s" of type "%s" has a limit of %d items', $field->name(), $field->type(), $field->get('limit')));
}

return array_values(array_filter($value));
},

'options' => function (Field $field): array {
return $field->getImages()
->map(static fn(Image $image) => [
'value' => $image->name(),
'icon' => 'image',
'thumb' => $image->square(300, 'contain')->uri(),
])->toArray();
},

'limit' => function (Field $field): ?int {
return $field->get('limit', null);
},

'isOrderable' => function ($field): bool {
return $field->is('orderable', true);
},
];
};
10 changes: 9 additions & 1 deletion formwork/fields/tags.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
$value = array_filter($value, static fn($item): bool => Constraint::matchesRegex($item, $field->get('pattern')));
}

if ($field->has('limit') && count($value) > $field->get('limit')) {
if ($field->limit() !== null && count($value) > $field->limit()) {
throw new ValidationException(sprintf('Field "%s" of type "%s" has a limit of %d items', $field->name(), $field->type(), $field->get('limit')));
}

Expand All @@ -47,8 +47,16 @@
return $options !== null ? Arr::from($options) : null;
},

'accept' => function ($field): string {
return $field->get('accept', 'options');
},

'limit' => function ($field): ?int {
return $field->get('limit', null);
},

'isOrderable' => function ($field): bool {
return $field->is('orderable', true);
},
];
};
3 changes: 3 additions & 0 deletions formwork/translations/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ date.weekdays.long: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Fr
date.weekdays.short: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
fields.array.add: Add
fields.array.remove: Remove
fields.file.none: (None)
fields.file.uploadLabel: <strong>Click</strong> to choose a file to upload or <strong>drag</strong> it here
fields.image.none: (None)
fields.select.empty: No matching options
file.metadata: Metadata
file.metadata.alternativeText: Alternative text
Expand All @@ -28,6 +30,7 @@ page.files: Files
page.image: Image
page.listed: Listed
page.listed.description: Listed pages are visible in the menu
page.noFiles: No files
page.noImage: No image
page.none: (None)
page.noTags: No tags
Expand Down
16 changes: 16 additions & 0 deletions panel/src/scss/components/_dropdowns.scss
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,19 @@
border-top: 1px solid var(--color-base-500);
margin: 0.25rem 0;
}

.dropdown-list .dropdown-item > .dropdown-thumb {
display: inline-block;
width: 1.5rem;
height: 1.5rem;
border-radius: $border-radius;
margin: -0.75rem 0.5rem -0.5rem 0;
background-color: var(--color-base-700);
object-fit: contain;
vertical-align: middle;
}

.dropdown-list .dropdown-item > .icon {
margin-right: 0.5rem;
margin-left: 0.25rem;
}
2 changes: 1 addition & 1 deletion panel/src/scss/components/_forms.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
@use "forms/forms-file";
@use "forms/forms-image";
@use "forms/forms-range";
@use "forms/forms-tag";
@use "forms/forms-tags";
@use "forms/forms-togglegroup";
4 changes: 0 additions & 4 deletions panel/src/scss/components/forms/_forms-image.scss
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
@use "../mixins" as *;
@use "../variables" as *;

.form-input-image {
cursor: default;
}

.image-picker-thumbnails {
display: flex;
overflow: auto;
Expand Down
Loading

0 comments on commit 291cc9f

Please sign in to comment.