Commit 94872f23 authored by Yassine Doghri's avatar Yassine Doghri
Browse files

feat(ui): create ViewComponents library to enable building class and view files components

- replace some helper components and forms with class components in the ui
- create viewcomponents
service and load the component function to be used in views
parent fcecbe1c
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ class Autoload extends AutoloadConfig
        'Config' => APPPATH . 'Config',
        'ActivityPub' => APPPATH . 'Libraries/ActivityPub',
        'Analytics' => APPPATH . 'Libraries/Analytics',
        'ViewComponents' => APPPATH . 'Libraries/ViewComponents',
    ];

    /**
@@ -84,5 +85,5 @@ class Autoload extends AutoloadConfig
     * ```
     * @var array<int, string>
     */
    public $files = [];
    public $files = [APPPATH . 'Libraries/ViewComponents/Helpers/view_components_helper.php'];
}
+9 −22
Original line number Diff line number Diff line
@@ -110,7 +110,9 @@ if (! function_exists('button')) {
        CODE_SAMPLE;
    }
}

// ------------------------------------------------------------------------

if (! function_exists('icon_button')) {
    /**
     * Icon Button component
@@ -145,6 +147,7 @@ if (! function_exists('icon_button')) {
    }
}
// ------------------------------------------------------------------------

if (! function_exists('hint_tooltip')) {
    /**
     * Hint component
@@ -167,7 +170,9 @@ if (! function_exists('hint_tooltip')) {
        return $tooltip . '">' . icon('question') . '</span>';
    }
}

// ------------------------------------------------------------------------

if (! function_exists('data_table')) {
    /**
     * Data table component
@@ -223,7 +228,9 @@ if (! function_exists('data_table')) {
            '</div>';
    }
}

// ------------------------------------------------------------------------

if (! function_exists('publication_pill')) {
    /**
     * Publication pill component
@@ -250,7 +257,9 @@ if (! function_exists('publication_pill')) {
            '</span>';
    }
}

// ------------------------------------------------------------------------

if (! function_exists('publication_button')) {
    /**
     * Publication button component
@@ -508,27 +517,5 @@ if (! function_exists('relative_time')) {
        CODE_SAMPLE;
    }
}
// ------------------------------------------------------------------------
if (! function_exists('xml_editor')) {
    /**
     * XML Editor field
     *
     * @param array<string, mixed> $customData
     * @param array<string, mixed> $extra
     */
    function xml_editor(array $customData = [], string $value = '', array $extra = []): string
    {
        $defaultData = [
            'slot' => 'textarea',
            'rows' => 5,
        ];
        $data = array_merge($defaultData, $customData);

        $textarea = form_textarea($data, $value, $extra);

        return <<<CODE_SAMPLE
            <xml-editor>{$textarea}</time-ago>
        CODE_SAMPLE;
    }
}
// ------------------------------------------------------------------------
+1 −105
Original line number Diff line number Diff line
@@ -141,38 +141,12 @@ if (! function_exists('form_label')) {

//--------------------------------------------------------------------

if (! function_exists('form_multiselect')) {
    /**
     * Multi-select menu
     *
     * @param array<string, string> $options
     * @param string[] $selected
     * @param array<string, string> $customExtra
     */
    function form_multiselect(
        string $name = '',
        array $options = [],
        array $selected = [],
        array $customExtra = []
    ): string {
        $defaultExtra = [
            'data-class' => $customExtra['class'],
            'multiple' => 'multiple',
        ];
        $extra = array_merge($defaultExtra, $customExtra);

        return form_dropdown($name, $options, $selected, $extra);
    }
}

//--------------------------------------------------------------------

if (! function_exists('form_dropdown')) {
    /**
     * Drop-down Menu (based on html select tag)
     *
     * @param array<string, mixed> $options
     * @param string[] $selected
     * @param array<string|int> $selected
     * @param array<string, mixed> $customExtra
     */
    function form_dropdown(
@@ -236,81 +210,3 @@ if (! function_exists('form_dropdown')) {
        return $form . "</select>\n";
    }
}

//--------------------------------------------------------------------

if (! function_exists('form_editor')) {
    /**
     * Markdown editor
     *
     * @param array<string, mixed> $data
     * @param array<string, mixed>|string $extra
     */
    function form_markdown_editor(array $data = [], string $value = '', string | array $extra = ''): string
    {
        $editorClass = 'w-full flex flex-col bg-white border border-gray-500 focus-within:ring-1 focus-within:ring-blue-600';
        if (array_key_exists('class', $data) && $data['class'] !== '') {
            $editorClass .= ' ' . $data['class'];
            unset($data['class']);
        }

        $data['class'] = 'border-none outline-none focus:border-none focus:outline-none w-full h-full';

        return '<div class="' . $editorClass . '">' .
            '<header class="sticky top-0 z-20 flex flex-wrap justify-between bg-white border-b border-gray-500">' .
                '<markdown-write-preview for="' . $data['id'] . '" class="relative inline-flex h-8">' .
                    '<button type="button" slot="write" class="px-2 font-semibold focus:outline-none focus:ring-inset focus:ring-2 focus:ring-pine-600">' . lang(
                        'Common.forms.editor.write'
                    ) . '</button>' .
                    '<button type="button" slot="preview" class="px-2 focus:outline-none focus:ring-inset focus:ring-2 focus:ring-pine-600">' . lang(
                        'Common.forms.editor.preview'
                    ) . '</button>' .
                '</markdown-write-preview>' .
                '<markdown-toolbar for="' . $data['id'] . '" class="flex gap-4 px-2 py-1">' .
                    '<div class="inline-flex text-2xl gap-x-1">' .
                        '<md-header class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
                            'heading'
                        ) . '</md-header>' .
                        '<md-bold class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
                            'bold'
                        ) . '</md-bold>' .
                        '<md-italic class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
                            'italic'
                        ) . '</md-italic>' .
                    '</div>' .
                    '<div class="inline-flex text-2xl gap-x-1">' .
                        '<md-unordered-list class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
                            'list-unordered'
                        ) . '</md-unordered-list>' .
                        '<md-ordered-list class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
                            'list-ordered'
                        ) . '</md-ordered-list>' .
                    '</div>' .
                    '<div class="inline-flex text-2xl gap-x-1">' .
                        '<md-quote class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
                            'quote'
                        ) . '</md-quote>' .
                        '<md-link class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
                            'link'
                        ) . '</md-link>' .
                        '<md-image class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
                            'image-add'
                        ) . '</md-image>' .
                    '</div>' .
                '</markdown-toolbar>' .
            '</header>' .
            '<div class="relative">' .
                form_textarea($data, $value, $extra) .
                '<markdown-preview for="' . $data['id'] . '" class="absolute top-0 left-0 hidden w-full h-full p-2 overflow-y-auto prose bg-gray-50" showClass="bg-white"></markdown-preview>' .
            '</div>' .
            '<footer class="flex px-2 py-1 bg-gray-100 border-t">' .
                '<a href="https://commonmark.org/help/" class="inline-flex items-center text-xs font-semibold text-gray-500 hover:text-gray-700" target="_blank" rel="noopener noreferrer">' . icon(
                    'markdown',
                    'mr-1 text-lg text-gray-400'
                ) . lang('Common.forms.editor.help') . '</a>' .
            '</footer>' .
        '</div>';
    }
}

// ------------------------------------------------------------------------
+36 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace ViewComponents;

class Component implements ComponentInterface
{
    /**
     * @var array<string, string>
     */
    protected array $attributes = [
        'class' => '',
    ];

    /**
     * @param array<string, mixed> $properties
     * @param array<string, string> $attributes
     */
    public function __construct(
        protected array $properties,
        array $attributes
    ) {
        // overwrite default properties if set
        foreach ($properties as $key => $value) {
            $this->{$key} = $value;
        }

        $this->attributes = array_merge($this->attributes, $attributes);
    }

    public function render(): string
    {
        return static::class . ': RENDER METHOD NOT IMPLEMENTED';
    }
}
+10 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace ViewComponents;

interface ComponentInterface
{
    public function render(): string;
}
Loading