From 870ee7f2db09f26449b3adac29e1809eaa79bfec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Wed, 29 Oct 2025 22:38:51 +0100 Subject: [PATCH] Implement mj-social components --- src/Elements/BodyComponents/MjSocial.php | 63 +++++++++++++++++++ .../BodyComponents/MjSocialElement.php | 62 ++++++++++++++++++ .../Elements/BodyComponents/MjSocialTest.php | 19 ++++++ 3 files changed, 144 insertions(+) create mode 100644 src/Elements/BodyComponents/MjSocial.php create mode 100644 src/Elements/BodyComponents/MjSocialElement.php create mode 100644 tests/Unit/Elements/BodyComponents/MjSocialTest.php diff --git a/src/Elements/BodyComponents/MjSocial.php b/src/Elements/BodyComponents/MjSocial.php new file mode 100644 index 0000000..eb6eebb --- /dev/null +++ b/src/Elements/BodyComponents/MjSocial.php @@ -0,0 +1,63 @@ + ['unit' => 'string', 'type' => 'alignment', 'default_value' => 'center'], + 'border-radius' => ['unit' => 'px', 'type' => 'string', 'default_value' => '3px'], + 'color' => ['unit' => 'color', 'type' => 'color', 'default_value' => '#333333'], + 'font-family' => [ + 'unit' => 'string', + 'type' => 'string', + 'default_value' => 'Ubuntu, Helvetica, Arial, sans-serif', + ], + 'font-size' => ['unit' => 'px', 'type' => 'string', 'default_value' => '13px'], + 'icon-size' => ['unit' => 'px', 'type' => 'string', 'default_value' => '20px'], + 'mode' => ['unit' => 'string', 'type' => 'string', 'default_value' => 'horizontal'], + 'padding' => ['unit' => 'px', 'type' => 'string', 'default_value' => '10px 25px'], + ]; + + protected array $defaultAttributes = [ + 'align' => 'center', + 'border-radius' => '3px', + 'color' => '#333333', + 'font-size' => '13px', + 'icon-size' => '20px', + 'mode' => 'horizontal', + 'padding' => '10px 25px', + ]; + + public function render(): string + { + $children = $this->getChildren() ?? []; + $content = $this->renderChildren($children, []); + $divAttributes = $this->getHtmlAttributes(['style' => 'div']); + return "
$content
"; + } + + public function getChildContext(): array + { + return [ + ...$this->context, + 'border-radius' => $this->getAttribute('border-radius'), + 'color' => $this->getAttribute('color'), + 'font-family' => $this->getAttribute('font-family'), + 'font-size' => $this->getAttribute('font-size'), + 'icon-size' => $this->getAttribute('icon-size'), + ]; + } + + public function getStyles(): array + { + return ['div' => ['text-align' => $this->getAttribute('align')]]; + } +} diff --git a/src/Elements/BodyComponents/MjSocialElement.php b/src/Elements/BodyComponents/MjSocialElement.php new file mode 100644 index 0000000..621609a --- /dev/null +++ b/src/Elements/BodyComponents/MjSocialElement.php @@ -0,0 +1,62 @@ + ['unit' => 'string', 'type' => 'alignment', 'default_value' => 'left'], + 'background-color' => ['unit' => 'color', 'type' => 'color', 'default_value' => ''], + 'border-radius' => ['unit' => 'px', 'type' => 'string', 'default_value' => ''], + 'color' => ['unit' => 'color', 'type' => 'color', 'default_value' => ''], + 'font-family' => ['unit' => 'string', 'type' => 'string', 'default_value' => ''], + 'font-size' => ['unit' => 'px', 'type' => 'string', 'default_value' => ''], + 'href' => ['unit' => 'string', 'type' => 'string', 'default_value' => ''], + 'icon-size' => ['unit' => 'px', 'type' => 'string', 'default_value' => ''], + 'name' => ['unit' => 'string', 'type' => 'string', 'default_value' => ''], + 'padding' => ['unit' => 'px', 'type' => 'string', 'default_value' => '4px'], + 'src' => ['unit' => 'string', 'type' => 'string', 'default_value' => ''], + 'target' => ['unit' => 'string', 'type' => 'string', 'default_value' => '_blank'], + ]; + + protected array $defaultAttributes = [ + 'align' => 'left', + 'padding' => '4px', + 'target' => '_blank', + ]; + + public function render(): string + { + $href = $this->getAttribute('href'); + $target = $this->getAttribute('target'); + $src = $this->getAttribute('src'); + $iconSize = $this->getAttribute('icon-size') ?: $this->context['icon-size'] ?? '20px'; + $content = $this->getContent(); + + $aAttributes = $this->getHtmlAttributes(['style' => 'a']); + $icon = $src ? "" : ''; + + return "$icon $content"; + } + + public function getStyles(): array + { + $color = $this->getAttribute('color') ?: $this->context['color'] ?? '#333333'; + $fontFamily = $this->getAttribute('font-family') ?: + $this->context['font-family'] ?? 'Ubuntu, Helvetica, Arial, sans-serif'; + + return ['a' => [ + 'color' => $color, + 'font-family' => $fontFamily, + 'padding' => $this->getAttribute('padding'), + 'text-decoration' => 'none', + ]]; + } +} diff --git a/tests/Unit/Elements/BodyComponents/MjSocialTest.php b/tests/Unit/Elements/BodyComponents/MjSocialTest.php new file mode 100644 index 0000000..dfac8bd --- /dev/null +++ b/tests/Unit/Elements/BodyComponents/MjSocialTest.php @@ -0,0 +1,19 @@ + expect((new MjSocial())->getTagName())->toBe('mj-social')); +it('MjSocial has correct defaults', fn() => expect((new MjSocial())->getAttribute('mode'))->toBe('horizontal')); + +it('MjSocialElement has correct tag name', function () { + expect((new MjSocialElement())->getTagName())->toBe('mj-social-element'); +}); + +it('MjSocialElement renders', function () { + $element = new MjSocialElement(['href' => 'https://facebook.com'], 'Facebook'); + $out = $element->render(); + expect($out)->toContain('toContain('https://facebook.com')->toContain('Facebook'); +});