Coder Social home page Coder Social logo

arkounay / ux-media Goto Github PK

View Code? Open in Web Editor NEW
19.0 5.0 6.0 2.97 MB

Symfony UX async document upload form type using ArtgrisFileManager

License: MIT License

PHP 25.75% JavaScript 35.06% Twig 38.41% CSS 0.78%
symfony symfony-bundle symfony-ux fileupload form symfony-form

ux-media's Introduction

Ux Media

Symfony UX async document upload form type using ArtgrisFileManager, a MediaBundle version that works without having to use most of its dependecies like jQuery / jQuery UI / Font awesome etc (but still requires bootstrap 5)

Installation

Before you start, make sure you have StimulusBundle configured in your app.

Install the bundle using Composer and Symfony Flex:

composer require arkounay/ux-media

If you're using WebpackEncore, install your assets and restart Encore (not needed if you're using AssetMapper):

npm install --force
npm run watch

# or use yarn
yarn install --force
yarn watch

Configuration prerequisites

This bundles uses FileManagerBundle. Make sure its routing is enabled, as well as UxMedia routes :

routing.yaml:

artgris_file_manager:
    resource: "@ArtgrisFileManagerBundle/Controller"
    type:     attribute
    prefix:   /admin/manager

ux_media:
    resource: "@ArkounayUxMediaBundle/Controller"
    type:     attribute
    prefix:   /admin/ux-media

Also, make sure you have a conf that is defined :

packages/artgris_file_manager.yaml:

artgris_file_manager:
    conf:
        default:
            dir: '%kernel.project_dir%/public/uploads'

If your project is NOT using bootstrap, you need to enable the bootstrap_modal controller and enable scss :

  • Add Encore.enableSassLoader() to your webpack.config.js file
  • Install sass yarn add sass-loader@^12.0.0 sass --dev

And import the propoer bootstrap scss class :

{
    "controllers": {
        "@arkounay/ux-collection": {
            "collection": {
                "enabled": true,
                "fetch": "eager",
                "autoimport": {
                    "@arkounay/ux-collection/src/style.css": true,
                    "@arkounay/ux-collection/src/style-when-not-using-bootstrap-5.css": false
                }
            }
        },
        "@arkounay/ux-media": {
            "media": {
                "enabled": true,
                "fetch": "eager",
                "autoimport": {
                    "@arkounay/ux-media/src/style.css": true
                }
            },
            "upload": {
                "enabled": true,
                "fetch": "eager"
            },
            "crop": {
                "enabled": true,
                "fetch": "eager",
                "autoimport": {
                    "cropperjs/dist/cropper.min.css": true,
                    "@arkounay/ux-media/src/crop_style.css": true
                }
            },
            "bootstrap_modal": {
                "enabled": true,
                "fetch": "eager",
                "autoimport": {
                    "@arkounay/ux-media/src/bootstrap_modal.scss": true
                }
            }
        }
    },
    "entrypoints": []
}

Usage

Works like Artgris/MediaBundle except you have to use UxMediaType and UxMediaCollectionType

$builder->add('Media', UxMediaType::class, [
    'conf' => 'default',
    'display_file_manager' => true,
    'display_clear_button' => true,
    'allow_crop' => true,
    'crop_options' => [
        'display_crop_data' => true,
        'allow_flip' => true,
        'allow_rotation' => true,
        'ratio' => false,
    ]
])

EasyAdmin integration

For easyadmin 3+ you need to manually specify the form theme by overriding configureCrud in your DashboardController to add the themes s@ArkounayUxCollection/ux_collection_form_theme.html.twig and @ArkounayUxMedia/ux_media_form_theme.html.twig

public function configureCrud(): Crud
{
    return Crud::new()
        ->addFormTheme('@ArkounayUxCollection/ux_collection_form_theme.html.twig')
        ->addFormTheme('@ArkounayUxMedia/ux_media_form_theme.html.twig')
    ;
}

If you're using WebpackEncore, you will need to configure your admin to use it so Symfony UX is taken into account, for example:

public function configureAssets(Assets $assets): Assets
{
    return parent::configureAssets($assets)
        ->addWebpackEncoreEntry('app');
}

ux-media's People

Contributors

arkounay avatar artgris avatar comtrast-remi avatar devcut avatar xdeswa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

ux-media's Issues

Integration with easyadmin

Hello,
I am having troubles using the formtype in easyadmin...
File manager does not appear...

Symfony 6.1
Easyadmin 4.3.5

I created a Field for easyadmin :

<?php

namespace App\Admin\Field;

use Arkounay\Bundle\UxMediaBundle\Form\UxMediaType;
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface;
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait;

final class MediaField implements FieldInterface
{
    use FieldTrait;

    public static function new(string $propertyName, ?string $label = null): self
    {
        return (new self())
            ->setProperty($propertyName)
            ->setLabel($label)
            ->setFormType(UxMediaType::class)
            ->setFormTypeOptions([
                'conf' => 'default',
                'display_file_manager' => true,
                'allow_crop' => false,
            ])
            ;
    }
}

Then I use it in my CrudController (it was a vich uploader form type) :

...
MediaField::new('imageFile')->hideOnIndex(),

I also added the webpack encore files to the easyadmin layout (overriding default layout.html.twig)

{% block head_stylesheets %}
        <link rel="stylesheet" href="{{ asset('app.css', ea.assets.defaultAssetPackageName) }}">
    {% endblock %}

    {% block configured_stylesheets %}
        {{ include('@EasyAdmin/includes/_css_assets.html.twig', { assets: ea.assets.cssAssets ?? [] }, with_context = false) }}
        {{ include('@EasyAdmin/includes/_encore_link_tags.html.twig', { assets: ea.assets.webpackEncoreAssets ?? [] }, with_context = false) }}
    {% endblock %}

    {% block head_favicon %}
        <link rel="shortcut icon" href="{{ asset(ea.dashboardFaviconPath) }}">
    {% endblock %}

    {% block head_javascript %}
        <script src="{{ asset('app.js', ea.assets.defaultAssetPackageName) }}"></script>
    {% endblock head_javascript %}

    {% block configured_javascripts %}
        {{ include('@EasyAdmin/includes/_js_assets.html.twig', { assets: ea.assets.jsAssets ?? [] }, with_context = false) }}
        {{ include('@EasyAdmin/includes/_encore_script_tags.html.twig', { assets: ea.assets.webpackEncoreAssets ?? [] }, with_context = false) }}
    {% endblock %}

    {% block javascripts %}
        {{ encore_entry_script_tags('app') }}
    {% endblock %}

image

If you have any idea....
Thank you

Form View

using, Bootstrap 5;

Screenshot 2023-11-27 at 18-23-55 Yazı Ekle _ Yönetim Paneli

UxMediaCollectionType seems correctly. (div got row and mb3 class)

changed block ux_media_row in ux_media_form_theme.html.twig

like this;

{% block ux_media_row %}
    {%- if 'ux_media_collection_entry' in block_prefixes -%}
        {%- set row_attr = row_attr|merge({'data-arkounay--ux-collection--collection-target': 'collectionElement'}) -%}
    {%- endif -%}

    {%- if 'ux_media_collection_entry' in block_prefixes -%}
        <div {% for k, v in row_attr|default %}{{ k }}="{{ v }}"{% endfor %}>
        {{ form_label(form) }}
        <div {% for k, v in attr|default %}{{ k }}="{{ v }}"{% endfor %}>
        {{ form_widget(form) }}
        {{ form_errors(form) }}
        {{ form_rest(form) }}
        </div>
        </div>
    {%- else %}
        {{ form_row(form) }}
        {{ form_errors(form) }}
        {{- form_rest(form) -}}
    {% endif %}
{% endblock %}

and final;
i tried this way (UxMediaType and UxMediaCollectionType seems working correctly now)

Screenshot 2023-11-27 at 18-32-36 Yazı Ekle _ Yönetim Paneli

I'm not sure if this method is the best way, I think you can solve it with a better method. thanks

auto crop ?

Hello, is there a way to autocrop image ( modal crop selected and selection squre showing) on a selection (upload or filemenager)

Thank!

deprecation

Do you plan to remove deprecation ?
...
Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface::prepend()" might add "void" as a native return type declaration in the future. Do the same in implementation "Arkounay\Bundle\UxMediaBundle\DependencyInjection\ArkounayUxMediaExtension" now to avoid errors or add an explicit @return annotation to suppress this message
...
Symfony\Component\DependencyInjection\Extension\ExtensionInterface::load()" might add "void" as a native return type declaration in the future. Do the same in implementation "Arkounay\Bundle\UxMediaBundle\DependencyInjection\ArkounayUxMediaExtension" now to avoid errors or add an explicit @return annotation to suppress this message.
...

Add Clear Button

To add clear button;

_ux_media_widget.html.twig (vendor/arkounay/ux-media/templates/) / add button near to other buttons

<button type="button" class="btn btn-light btn-upload" data-action="arkounay--ux-media--media#clear" data-arkounay--ux-media--media-target="clearButton">
  <span>
    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"  class="bi bi-trash" viewBox="0 0 16 16">
    <path  d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/> 
    <path  fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/> </svg>
  </span>
 </button>

Modification node_modules/@arkounay/ux-media/src/media_controller.js (stimilius included media_conroller.js in dist directory)

static targets = ['inputPath', 'filePreview', 'fileManagerModal', 'progress',  'cropModal', 'cropButton', 'fileError', 'fileErrorMessage'];

replace:

static targets = ['inputPath', 'filePreview', 'fileManagerModal', 'progress', 'clearButton' , 'cropModal', 'cropButton', 'fileError', 'fileErrorMessage'];

const hasValue = this.pathValue !== '';
        this.#disableCropButton();
        if (hasValue) {

replace with;

const hasValue = this.pathValue !== '';
        this.#disableCropButton();
        this.#hideClearButton();
        if (hasValue) {

img.addEventListener('error', () => {
                    this.imageLoaded = false;
                    this.#disableCropButton();

});

replace with;

img.addEventListener('error', () => {
                    this.imageLoaded = false;
                    this.#disableCropButton();
                    this.#hideClearButton();
});

img.addEventListener('load', () => {
                    this.imageLoaded = true;
                    this.#disableCropButton(!img.getAttribute('src').match(/^\/.+(jpg|jpeg|png|gif)$/i));
});

replace with;

img.addEventListener('load', () => {
                    this.imageLoaded = true;
                    this.#disableCropButton(!img.getAttribute('src').match(/^\/.+(jpg|jpeg|png|gif)$/i));
                    this.#hideClearButton(!img.getAttribute('src'));
});

this.filePreviewTarget.innerHTML = `<div class="border p-2 text-secondary bg-light rounded">${icon}</div>`;
                    this.#disableCropButton();
                } else {

replace with;

this.filePreviewTarget.innerHTML = `<div class="border p-2 text-secondary bg-light rounded">${icon}</div>`;
                    this.#disableCropButton();
                    this.#hideClearButton();
                } else {

add function (node_modules/@arkounay/ux-media/src/media_controller.js)

#hideClearButton(hidden = true) {
        if (this.hasClearButtonTarget) {
            this.clearButtonTarget.style.display = hidden ? 'none' : '';
        }
    }

1

2

Media upload

After upload image, input value is not set. Please take look on following code the input value is empty.

<div class="flex-grow-1"><input type="text" class="form-control" data-action="arkounay--ux-media--media#updatePathValue" data-arkounay--ux-media--media-target="inputPath" id="zone_Media" name="zone[Media]" value="" placeholder="ux_media.path.placeholder"><div class="progress d-none" data-arkounay--ux-media--media-target="progress"><div class="progress-bar progress-bar-striped" role="progressbar" aria-valuenow="10" aria-valuemin="0" aria-valuemax="100" style="width: 100%;"></div></div></div>

no crop with service

I use config dir (for user path) with service in config :
`artgris_file_manager:
conf:
default:
service: App\Service\MediaService
#dir: '%kernel.project_dir%/public/upload'
perso:
#service: App\Service\MediaService
dir: '%kernel.project_dir%/public/media'

arkounay_ux_media:
cropped_path: crops/`

default not have crop button
perso have crop button

LiveForm -> Invalid model name

hi,
i using Live Form components

Example 1 (this giving error 'Uncaught Error: Invalid model name' in console. but everything working well )

  • ux v2.13.0
    • Throwing an error when setting an invalid model name.
->add('images', UxMediaCollectionType::class, [
                'conf' => 'default',
                'entry_options' => ['readonly' => false]
            ])

Example 2 (no error, working well too)

->add(child: 'images', type: LiveCollectionType::class, options: [
     'entry_type' => UxMediaType::class,
     'entry_options' => ['label' => false,'conf' => 'default',],
     'label' => false,
     'allow_add' => true,
      'allow_delete' => true,
      'by_reference' => false,
])

Even though it worked perfectly, I wanted to solve the error but I couldn't find it. Do you have any ideas about this?

Problem when destroying the cropper

this.cropper.destroy();

Hello,
First, Thank you for your work on this adaptation for SF UX and on the Media bundle in general :D
I have a little problem and I can't solve it.

An error that is triggered each time the crop is saved (this.cropper.parentNode is null) at the time of the destroy, but everything works fine whether it's the flip, the rotate or the crop it still works, there really isn't than the alert that goes off.

an idea ?
Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.