]> git.mxchange.org Git - friendica.git/commitdiff
Add new horizontal masonry and image height allocation
authorHypolite Petovan <hypolite@mrpetovan.com>
Fri, 29 Sep 2023 07:28:22 +0000 (03:28 -0400)
committerHypolite Petovan <hypolite@mrpetovan.com>
Tue, 3 Oct 2023 23:58:52 +0000 (19:58 -0400)
- Move image templates to content/image sub-folder

15 files changed:
src/Content/Image.php [new file with mode: 0644]
src/Content/Image/Collection/MasonryImageRow.php [new file with mode: 0644]
src/Content/Image/Entity/MasonryImage.php [new file with mode: 0644]
src/Content/Post/Collection/PostMedias.php
src/Content/Post/Entity/PostMedia.php
src/Model/Item.php
view/global.css
view/templates/content/image.tpl [deleted file]
view/templates/content/image/grid.tpl [new file with mode: 0644]
view/templates/content/image/horizontal_masonry.tpl [new file with mode: 0644]
view/templates/content/image/single.tpl [new file with mode: 0644]
view/templates/content/image/single_with_height_allocation.tpl [new file with mode: 0644]
view/templates/content/image_grid.tpl [deleted file]
view/theme/frio/scheme/black.css
view/theme/frio/scheme/dark.css

diff --git a/src/Content/Image.php b/src/Content/Image.php
new file mode 100644 (file)
index 0000000..cc2fd51
--- /dev/null
@@ -0,0 +1,154 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Content;
+
+use Friendica\Content\Image\Collection\MasonryImageRow;
+use Friendica\Content\Image\Entity\MasonryImage;
+use Friendica\Content\Post\Collection\PostMedias;
+use Friendica\Core\Renderer;
+
+class Image
+{
+       public static function getBodyAttachHtml(PostMedias $PostMediaImages): string
+       {
+               $media = '';
+
+               if ($PostMediaImages->haveDimensions()) {
+                       if (count($PostMediaImages) > 1) {
+                               $media = self::getHorizontalMasonryHtml($PostMediaImages);
+                       } elseif (count($PostMediaImages) == 1) {
+                               $media = Renderer::replaceMacros(Renderer::getMarkupTemplate('content/image/single_with_height_allocation.tpl'), [
+                                       '$image' => $PostMediaImages[0],
+                                       '$allocated_height' => $PostMediaImages[0]->getAllocatedHeight(),
+                                       '$allocated_max_width' => ($PostMediaImages[0]->previewWidth ?? $PostMediaImages[0]->width) . 'px',
+                               ]);
+                       }
+               } else {
+                       if (count($PostMediaImages) > 1) {
+                               $media = self::getImageGridHtml($PostMediaImages);
+                       } elseif (count($PostMediaImages) == 1) {
+                               $media = Renderer::replaceMacros(Renderer::getMarkupTemplate('content/image/single.tpl'), [
+                                       '$image' => $PostMediaImages[0],
+                               ]);
+                       }
+               }
+
+               return $media;
+       }
+
+       /**
+        * @param PostMedias $images
+        * @return string
+        * @throws \Friendica\Network\HTTPException\ServiceUnavailableException
+        */
+       private static function getImageGridHtml(PostMedias $images): string
+       {
+               // Image for first column (fc) and second column (sc)
+               $images_fc = [];
+               $images_sc = [];
+
+               for ($i = 0; $i < count($images); $i++) {
+                       ($i % 2 == 0) ? ($images_fc[] = $images[$i]) : ($images_sc[] = $images[$i]);
+               }
+
+               return Renderer::replaceMacros(Renderer::getMarkupTemplate('content/image/grid.tpl'), [
+                       'columns' => [
+                               'fc' => $images_fc,
+                               'sc' => $images_sc,
+                       ],
+               ]);
+       }
+
+       /**
+        * Creates a horizontally masoned gallery with a fixed maximum number of pictures per row.
+        *
+        * For each row, we calculate how much of the total width each picture will take depending on their aspect ratio
+        * and how much relative height it needs to accomodate all pictures next to each other with their height normalized.
+        *
+        * @param array $images
+        * @return string
+        * @throws \Friendica\Network\HTTPException\ServiceUnavailableException
+        */
+       private static function getHorizontalMasonryHtml(PostMedias $images): string
+       {
+               static $column_size = 2;
+
+               $rows = array_map(
+                       function (PostMedias $PostMediaImages) {
+                               if ($singleImageInRow = count($PostMediaImages) == 1) {
+                                       $PostMediaImages[] = $PostMediaImages[0];
+                               }
+
+                               $widths = [];
+                               $heights = [];
+                               foreach ($PostMediaImages as $PostMediaImage) {
+                                       if ($PostMediaImage->width && $PostMediaImage->height) {
+                                               $widths[] = $PostMediaImage->width;
+                                               $heights[] = $PostMediaImage->height;
+                                       } else {
+                                               $widths[] = $PostMediaImage->previewWidth;
+                                               $heights[] = $PostMediaImage->previewHeight;
+                                       }
+                               }
+
+                               $maxHeight = max($heights);
+
+                               // Corrected width preserving aspect ratio when all images on a row are the same height
+                               $correctedWidths = [];
+                               foreach ($widths as $i => $width) {
+                                       $correctedWidths[] = $width * $maxHeight / $heights[$i];
+                               }
+
+                               $totalWidth = array_sum($correctedWidths);
+
+                               $row_images2 = [];
+
+                               if ($singleImageInRow) {
+                                       unset($PostMediaImages[1]);
+                               }
+
+                               foreach ($PostMediaImages as $i => $PostMediaImage) {
+                                       $row_images2[] = new MasonryImage(
+                                               $PostMediaImage->uriId,
+                                               $PostMediaImage->url,
+                                               $PostMediaImage->preview,
+                                               $PostMediaImage->description ?? '',
+                                               100 * $correctedWidths[$i] / $totalWidth,
+                                               100 * $maxHeight / $correctedWidths[$i]
+                                       );
+                               }
+
+                               // This magic value will stay constant for each image of any given row and is ultimately
+                               // used to determine the height of the row container relative to the available width.
+                               $commonHeightRatio = 100 * $correctedWidths[0] / $totalWidth / ($widths[0] / $heights[0]);
+
+                               return new MasonryImageRow($row_images2, count($row_images2), $commonHeightRatio);
+                       },
+                       $images->chunk($column_size)
+               );
+
+               return Renderer::replaceMacros(Renderer::getMarkupTemplate('content/image/horizontal_masonry.tpl'), [
+                       '$rows' => $rows,
+                       '$column_size' => $column_size,
+               ]);
+       }
+}
diff --git a/src/Content/Image/Collection/MasonryImageRow.php b/src/Content/Image/Collection/MasonryImageRow.php
new file mode 100644 (file)
index 0000000..ff50778
--- /dev/null
@@ -0,0 +1,57 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Content\Image\Collection;
+
+use Friendica\Content\Image\Entity;
+use Friendica\BaseCollection;
+use Friendica\Content\Image\Entity\MasonryImage;
+
+class MasonryImageRow extends BaseCollection
+{
+       /** @var ?float */
+       protected $heightRatio;
+
+       /**
+        * @param MasonryImage[] $entities
+        * @param int|null       $totalCount
+        * @param float|null     $heightRatio
+        */
+       public function __construct(array $entities = [], int $totalCount = null, float $heightRatio = null)
+       {
+               parent::__construct($entities, $totalCount);
+
+               $this->heightRatio = $heightRatio;
+       }
+
+       /**
+        * @return Entity\MasonryImage
+        */
+       public function current(): Entity\MasonryImage
+       {
+               return parent::current();
+       }
+
+       public function getHeightRatio(): ?float
+       {
+               return $this->heightRatio;
+       }
+}
diff --git a/src/Content/Image/Entity/MasonryImage.php b/src/Content/Image/Entity/MasonryImage.php
new file mode 100644 (file)
index 0000000..e85688e
--- /dev/null
@@ -0,0 +1,60 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Content\Image\Entity;
+
+use Friendica\BaseEntity;
+use Psr\Http\Message\UriInterface;
+
+/**
+ * @property-read int $uriId
+ * @property-read UriInterface $url
+ * @property-read ?UriInterface $preview
+ * @property-read string $description
+ * @property-read float $heightRatio
+ * @property-read float $widthRatio
+ * @see \Friendica\Content\Image::getHorizontalMasonryHtml()
+ */
+class MasonryImage extends BaseEntity
+{
+       /** @var int */
+       protected $uriId;
+       /** @var UriInterface */
+       protected $url;
+       /** @var ?UriInterface */
+       protected $preview;
+       /** @var string */
+       protected $description;
+       /** @var float Ratio of the width of the image relative to the total width of the images on the row */
+       protected $widthRatio;
+       /** @var float Ratio of the height of the image relative to its width for height allocation */
+       protected $heightRatio;
+
+       public function __construct(int $uriId, UriInterface $url, ?UriInterface $preview, string $description, float $widthRatio, float $heightRatio)
+       {
+               $this->url         = $url;
+               $this->uriId       = $uriId;
+               $this->preview     = $preview;
+               $this->description = $description;
+               $this->widthRatio  = $widthRatio;
+               $this->heightRatio = $heightRatio;
+       }
+}
index 5e75d908a7462567223e10ddc2dc7437c51ff53c..9f7d10d0cee8d1a5317ca4958882d56cecec8e43 100644 (file)
@@ -42,4 +42,16 @@ class PostMedias extends BaseCollection
        {
                return parent::current();
        }
+
+       /**
+        * Determine whether all the collection's item have at least one set of dimensions provided
+        *
+        * @return bool
+        */
+       public function haveDimensions(): bool
+       {
+               return array_reduce($this->getArrayCopy(), function (bool $carry, Entity\PostMedia $item) {
+                       return $carry && $item->hasDimensions();
+               }, true);
+       }
 }
index e03246315c24506363cd06e7e7829e66a3423b20..8220624198cfb7208799f03a75c10035e6f762eb 100644 (file)
@@ -188,6 +188,30 @@ class PostMedia extends BaseEntity
 
        }
 
+       /**
+        * Computes the allocated height value used in the content/image/single_with_height_allocation.tpl template
+        *
+        * Either base or preview dimensions need to be set at runtime.
+        *
+        * @return string
+        */
+       public function getAllocatedHeight(): string
+       {
+               if (!$this->hasDimensions()) {
+                       throw new \RangeException('Either width and height or previewWidth and previewHeight must be defined to use this method.');
+               }
+
+               if ($this->width && $this->height) {
+                       $width  = $this->width;
+                       $height = $this->height;
+               } else {
+                       $width  = $this->previewWidth;
+                       $height = $this->previewHeight;
+               }
+
+               return (100 * $height / $width) . '%';
+       }
+
        /**
         * Return a new PostMedia entity with a different preview URI and an optional proxy size name.
         * The new entity preview's width and height are rescaled according to the provided size.
@@ -263,4 +287,14 @@ class PostMedia extends BaseEntity
                        $this->id,
                );
        }
+
+       /**
+        * Checks the media has at least one full set of dimensions, needed for the height allocation feature
+        *
+        * @return bool
+        */
+       public function hasDimensions(): bool
+       {
+               return $this->width && $this->height || $this->previewWidth && $this->previewHeight;
+       }
 }
index 53183f1d2f60179c1fb1b77bbf7bc1335dde08a4..457d76ec78c271f31e83b939ed424000503336a2 100644 (file)
@@ -22,6 +22,7 @@
 namespace Friendica\Model;
 
 use Friendica\Contact\LocalRelationship\Entity\LocalRelationship;
+use Friendica\Content\Image;
 use Friendica\Content\Post\Collection\PostMedias;
 use Friendica\Content\Post\Entity\PostMedia;
 use Friendica\Content\Text\BBCode;
@@ -3241,7 +3242,7 @@ class Item
                }
 
                if (!empty($sharedSplitAttachments)) {
-                       $s = self::addGallery($s, $sharedSplitAttachments['visual'], $item['uri-id']);
+                       $s = self::addGallery($s, $sharedSplitAttachments['visual']);
                        $s = self::addVisualAttachments($sharedSplitAttachments['visual'], $shared_item, $s, true);
                        $s = self::addLinkAttachment($shared_uri_id ?: $item['uri-id'], $sharedSplitAttachments, $body, $s, true, $quote_shared_links);
                        $s = self::addNonVisualAttachments($sharedSplitAttachments['additional'], $item, $s, true);
@@ -3254,7 +3255,7 @@ class Item
                        $s = substr($s, 0, $pos);
                }
 
-               $s = self::addGallery($s, $itemSplitAttachments['visual'], $item['uri-id']);
+               $s = self::addGallery($s, $itemSplitAttachments['visual']);
                $s = self::addVisualAttachments($itemSplitAttachments['visual'], $item, $s, false);
                $s = self::addLinkAttachment($item['uri-id'], $itemSplitAttachments, $body, $s, false, $shared_links);
                $s = self::addNonVisualAttachments($itemSplitAttachments['additional'], $item, $s, false);
@@ -3285,45 +3286,32 @@ class Item
                return $hook_data['html'];
        }
 
-       /**
-        * @param PostMedias $images
-        * @return string
-        * @throws \Friendica\Network\HTTPException\ServiceUnavailableException
-        */
-       private static function makeImageGrid(PostMedias $images): string
-       {
-               // Image for first column (fc) and second column (sc)
-               $images_fc = [];
-               $images_sc = [];
-
-               for ($i = 0; $i < count($images); $i++) {
-                       ($i % 2 == 0) ? ($images_fc[] = $images[$i]) : ($images_sc[] = $images[$i]);
-               }
-
-               return Renderer::replaceMacros(Renderer::getMarkupTemplate('content/image_grid.tpl'), [
-                       'columns' => [
-                               'fc' => $images_fc,
-                               'sc' => $images_sc,
-                       ],
-               ]);
-       }
-
        /**
         * Modify links to pictures to links for the "Fancybox" gallery
         *
         * @param string     $s
         * @param PostMedias $PostMedias
-        * @param int        $uri_id
         * @return string
         */
-       private static function addGallery(string $s, PostMedias $PostMedias, int $uri_id): string
+       private static function addGallery(string $s, PostMedias $PostMedias): string
        {
                foreach ($PostMedias as $PostMedia) {
                        if (!$PostMedia->preview || ($PostMedia->type !== Post\Media::IMAGE)) {
                                continue;
                        }
 
-                       $s = str_replace('<a href="' . $PostMedia->url . '"', '<a data-fancybox="' . $uri_id . '" href="' . $PostMedia->url . '"', $s);
+                       if ($PostMedia->hasDimensions()) {
+                               $pattern = '#<a href="' . preg_quote($PostMedia->url) . '">(.*?)"></a>#';
+
+                               $s = preg_replace_callback($pattern, function () use ($PostMedia) {
+                                       return Renderer::replaceMacros(Renderer::getMarkupTemplate('content/image/single_with_height_allocation.tpl'), [
+                                               '$image' => $PostMedia,
+                                               '$allocated_height' => $PostMedia->getAllocatedHeight(),
+                                       ]);
+                               }, $s);
+                       } else {
+                               $s = str_replace('<a href="' . $PostMedia->url . '"', '<a data-fancybox="uri-id-' . $PostMedia->uriId . '" href="' . $PostMedia->url . '"', $s);
+                       }
                }
 
                return $s;
@@ -3494,14 +3482,7 @@ class Item
                        }
                }
 
-               $media = '';
-               if (count($images) > 1) {
-                       $media = self::makeImageGrid($images);
-               } elseif (count($images) == 1) {
-                       $media = Renderer::replaceMacros(Renderer::getMarkupTemplate('content/image.tpl'), [
-                               '$image' => $images[0],
-                       ]);
-               }
+               $media = Image::getBodyAttachHtml($images);
 
                // On Diaspora posts the attached pictures are leading
                if ($item['network'] == Protocol::DIASPORA) {
index 714bb55dbd7f029aade134a669d1275f7cbb889d..ecab5a1c159ea02508124dad8f47abb4316fdc19 100644 (file)
@@ -706,6 +706,39 @@ audio {
  * Image grid settings END
  **/
 
+/* This helps allocating space for image before they are loaded, preventing content shifting once they are.
+ * Inspired by https://www.smashingmagazine.com/2016/08/ways-to-reduce-content-shifting-on-page-load/
+ * Please note: The space is effectively allocated using padding-bottom using the image ratio as a value.
+ * This ratio is never known in advance so no value is set in the stylesheet.
+ */
+figure.img-allocated-height {
+       position: relative;
+       background: center / auto rgba(0, 0, 0, 0.05) url(/images/icons/image.png) no-repeat;
+       margin: 0;
+}
+figure.img-allocated-height img{
+       position: absolute;
+       top: 0;
+       right: 0;
+       bottom: 0;
+       left: 0;
+       width: 100%;
+}
+
+/**
+ * Horizontal masonry settings START
+ **/
+.masonry-row {
+       display: -ms-flexbox; /* IE10 */
+       display: flex;
+       /* Both the following values should be the same to ensure consistent margins between images in the grid */
+       column-gap: 5px;
+       margin-top: 5px;
+}
+/**
+ * Horizontal masonry settings AND
+ **/
+
 #contactblock .icon {
        width: 48px;
        height: 48px;
diff --git a/view/templates/content/image.tpl b/view/templates/content/image.tpl
deleted file mode 100644 (file)
index b3dfb74..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-{{if $image->preview}}
-<a data-fancybox="{{$image->uriId}}" href="{{$image->url}}"><img src="{{$image->preview}}" alt="{{$image->description}}" title="{{$image->description}}" loading="lazy"></a>
-{{else}}
-<img src="{{$image->url}}" alt="{{$image->description}}" title="{{$image->description}}" loading="lazy">
-{{/if}}
diff --git a/view/templates/content/image/grid.tpl b/view/templates/content/image/grid.tpl
new file mode 100644 (file)
index 0000000..091e69e
--- /dev/null
@@ -0,0 +1,12 @@
+<div class="imagegrid-row">
+       <div class="imagegrid-column">
+               {{foreach $columns.fc as $img}}
+                               {{include file="content/image/single.tpl" image=$img}}
+               {{/foreach}}
+       </div>
+       <div class="imagegrid-column">
+               {{foreach $columns.sc as $img}}
+                               {{include file="content/image/single.tpl" image=$img}}
+               {{/foreach}}
+       </div>
+</div>
diff --git a/view/templates/content/image/horizontal_masonry.tpl b/view/templates/content/image/horizontal_masonry.tpl
new file mode 100644 (file)
index 0000000..223a9c4
--- /dev/null
@@ -0,0 +1,12 @@
+{{foreach $rows as $images}}
+       <div class="masonry-row" style="height: {{$images->getHeightRatio()}}%">
+        {{foreach $images as $image}}
+            {{* The absolute pixel value in the calc() should be mirrored from the .imagegrid-row column-gap value *}}
+            {{include file="content/image/single_with_height_allocation.tpl"
+                   image=$image
+                   allocated_height="calc(`$image->heightRatio * $image->widthRatio / 100`% - 5px / `$column_size`)"
+                   allocated_width="`$image->widthRatio`%"
+            }}
+        {{/foreach}}
+       </div>
+{{/foreach}}
diff --git a/view/templates/content/image/single.tpl b/view/templates/content/image/single.tpl
new file mode 100644 (file)
index 0000000..b3dfb74
--- /dev/null
@@ -0,0 +1,5 @@
+{{if $image->preview}}
+<a data-fancybox="{{$image->uriId}}" href="{{$image->url}}"><img src="{{$image->preview}}" alt="{{$image->description}}" title="{{$image->description}}" loading="lazy"></a>
+{{else}}
+<img src="{{$image->url}}" alt="{{$image->description}}" title="{{$image->description}}" loading="lazy">
+{{/if}}
diff --git a/view/templates/content/image/single_with_height_allocation.tpl b/view/templates/content/image/single_with_height_allocation.tpl
new file mode 100644 (file)
index 0000000..1d70194
--- /dev/null
@@ -0,0 +1,20 @@
+{{* The padding-top height allocation trick only works if the <figure> fills its parent's width completely or with flex. 🤷‍♂️
+       As a result, we need to add a wrapping element for non-flex (non-image grid) environments, mostly single-image cases.
+ *}}
+{{if $allocated_max_width}}
+<div style="max-width: {{$allocated_max_width|default:"auto"}};">
+{{/if}}
+
+<figure class="img-allocated-height" style="width: {{$allocated_width|default:"auto"}}; padding-bottom: {{$allocated_height}}">
+    {{if $image->preview}}
+               <a data-fancybox="uri-id-{{$image->uriId}}" href="{{$image->url}}">
+                       <img src="{{$image->preview}}" alt="{{$image->description}}" title="{{$image->description}}" loading="lazy">
+               </a>
+    {{else}}
+               <img src="{{$image->url}}" alt="{{$image->description}}" title="{{$image->description}}" loading="lazy">
+    {{/if}}
+</figure>
+
+{{if $allocated_max_width}}
+</div>
+{{/if}}
diff --git a/view/templates/content/image_grid.tpl b/view/templates/content/image_grid.tpl
deleted file mode 100644 (file)
index 95e49ee..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<div class="imagegrid-row">
-       <div class="imagegrid-column">
-               {{foreach $columns.fc as $img}}
-                               {{include file="content/image.tpl" image=$img}}
-               {{/foreach}}
-       </div>
-       <div class="imagegrid-column">
-               {{foreach $columns.sc as $img}}
-                               {{include file="content/image.tpl" image=$img}}
-               {{/foreach}}
-       </div>
-</div>
\ No newline at end of file
index debf9d99b3e12af2f6d5b23b97a245c310c67a8f..561f708a81b312951bdea12833b84a650dcbe7d2 100644 (file)
@@ -394,3 +394,7 @@ input[type="text"].tt-input {
 textarea#profile-jot-text:focus + #preview_profile-jot-text, textarea.comment-edit-text:focus + .comment-edit-form .preview {
        border-color: $link_color;
 }
+
+figure.img-allocated-height {
+       background-color: rgba(255, 255, 255, 0.15);
+}
index add36fff1041d9eaac4a9b22cb2feed393cff8e6..434681c5587a3e49e33eece3020e7c9f3b999631 100644 (file)
@@ -354,3 +354,7 @@ input[type="text"].tt-input {
 textarea#profile-jot-text:focus + #preview_profile-jot-text, textarea.comment-edit-text:focus + .comment-edit-form .preview {
        border-color: $link_color;
 }
+
+figure.img-allocated-height {
+       background-color: rgba(255, 255, 255, 0.05);
+}