Quellcode durchsuchen

Reading view: action icons position (#6297)

* add configs in reading

* implementation into the reading view

* CSS

* i18n

* Credits to  joshka

* Update article.phtml

* fix

* fix

* <br />

* Update app/i18n/fr/conf.php

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>

* Update app/i18n/en/conf.php

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>

* fix French

* show_articleicons  => show_article_icons

* Update app/i18n/en/conf.php

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>

* Update app/i18n/en-us/conf.php

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>

---------

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
maTh vor 1 Jahr
Ursprung
Commit
20f13312d1

+ 1 - 0
CREDITS.md

@@ -108,6 +108,7 @@ People are sorted by name so please keep this order.
 * [Jonas Östanbäck](https://github.com/cez81): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:cez81)
 * [Jordi Garcia](https://github.com/jgtorcal): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:jgtorcal)
 * [Joris Kinable](https://github.com/jkinable): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:jkinable)
+* [Josh McKinney](https://github.com/joshka): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:joshka)
 * [Jules Bertholet](https://github.com/Jules-Bertholet): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:Jules-Bertholet)
 * [Julien Reichardt](https://github.com/j8r): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:j8r), [Web](https://blog.jrei.ch/)
 * [Julien-Pierre Avérous](https://github.com/javerous): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:javerous), [Web](https://www.sourcemac.com/)

+ 1 - 0
app/Controllers/configureController.php

@@ -123,6 +123,7 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
 			FreshRSS_Context::userConf()->show_tags_max = Minz_Request::paramInt('show_tags_max');
 			FreshRSS_Context::userConf()->show_author_date = Minz_Request::paramString('show_author_date') ?: '0';
 			FreshRSS_Context::userConf()->show_feed_name = Minz_Request::paramString('show_feed_name') ?: 't';
+			FreshRSS_Context::userConf()->show_article_icons = Minz_Request::paramString('show_article_icons') ?: 't';
 			FreshRSS_Context::userConf()->hide_read_feeds = Minz_Request::paramBoolean('hide_read_feeds');
 			FreshRSS_Context::userConf()->onread_jump_next = Minz_Request::paramBoolean('onread_jump_next');
 			FreshRSS_Context::userConf()->lazyload = Minz_Request::paramBoolean('lazyload');

+ 1 - 0
app/Models/UserConfiguration.php

@@ -21,6 +21,7 @@ declare(strict_types=1);
  * @property int $show_tags_max
  * @property string $show_author_date
  * @property string $show_feed_name
+ * @property string $show_article_icons
  * @property bool $display_posts
  * @property string $email_validation_token
  * @property-read bool $enabled

+ 5 - 0
app/i18n/cs/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => 'V řádku s autory a datem',
 			),
 			'feed_title' => 'Název feedu',
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// TODO
+				'above_title' => 'Above title',	// TODO
+				'with_authors' => 'In authors and date row',	// TODO
+			),
 			'tags' => array(
 				'_' => 'Štítky',
 				'both' => 'V záhlaví a zápatí',

+ 5 - 0
app/i18n/de/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => 'In der Zeile mit Autoren und Datum',
 			),
 			'feed_title' => 'Feed Titel',
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// TODO
+				'above_title' => 'Above title',	// TODO
+				'with_authors' => 'In authors and date row',	// TODO
+			),
 			'tags' => array(
 				'_' => 'Hashtags',
 				'both' => 'In Kopf- und Fußzeile',

+ 5 - 0
app/i18n/el/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => 'In authors and date row',	// TODO
 			),
 			'feed_title' => 'Feed title',	// TODO
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// TODO
+				'above_title' => 'Above title',	// TODO
+				'with_authors' => 'In authors and date row',	// TODO
+			),
 			'tags' => array(
 				'_' => 'Tags',	// TODO
 				'both' => 'In header and footer',	// TODO

+ 5 - 0
app/i18n/en-us/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => 'In authors and date row',	// IGNORE
 			),
 			'feed_title' => 'Feed title',	// IGNORE
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// IGNORE
+				'above_title' => 'Above title',	// IGNORE
+				'with_authors' => 'In authors and date row',	// IGNORE
+			),
 			'tags' => array(
 				'_' => 'Tags',	// IGNORE
 				'both' => 'In header and footer',	// IGNORE

+ 5 - 0
app/i18n/en/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => 'In authors and date row',
 			),
 			'feed_title' => 'Feed title',
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',
+				'above_title' => 'Above title',
+				'with_authors' => 'In authors and date row',
+			),
 			'tags' => array(
 				'_' => 'Tags',
 				'both' => 'In header and footer',

+ 5 - 0
app/i18n/es/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => 'En la fila de autores y fecha',
 			),
 			'feed_title' => 'Título del Feed',
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// TODO
+				'above_title' => 'Above title',	// TODO
+				'with_authors' => 'In authors and date row',	// TODO
+			),
 			'tags' => array(
 				'_' => 'Etiquetas',
 				'both' => 'En el encabezado y pie de página',

+ 5 - 0
app/i18n/fa/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => ' در نویسندگان و ردیف تاریخ',
 			),
 			'feed_title' => ' عنوان خوراک',
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// TODO
+				'above_title' => 'Above title',	// TODO
+				'with_authors' => 'In authors and date row',	// TODO
+			),
 			'tags' => array(
 				'_' => ' برچسب ها',
 				'both' => ' در سرصفحه و پاورقی',

+ 5 - 0
app/i18n/fr/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => 'Sur la ligne « Auteurs et date »',
 			),
 			'feed_title' => 'Titre du flux',
+			'icons' => array(
+				'_' => 'Position des icônes d’article<br /><small>(Vue lecture seulement)</small>',
+				'above_title' => 'Au dessus du titre',
+				'with_authors' => 'Sur la ligne auteur et date',
+			),
 			'tags' => array(
 				'_' => 'Tags',	// IGNORE
 				'both' => 'En en-tête et en pied d’article',

+ 5 - 0
app/i18n/he/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => 'In authors and date row',	// TODO
 			),
 			'feed_title' => 'Feed title',	// TODO
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// TODO
+				'above_title' => 'Above title',	// TODO
+				'with_authors' => 'In authors and date row',	// TODO
+			),
 			'tags' => array(
 				'_' => 'Tags',	// TODO
 				'both' => 'In header and footer',	// TODO

+ 5 - 0
app/i18n/hu/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => 'A szerzők és dátum sorban',
 			),
 			'feed_title' => 'Hírforrás címe',
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// TODO
+				'above_title' => 'Above title',	// TODO
+				'with_authors' => 'In authors and date row',	// TODO
+			),
 			'tags' => array(
 				'_' => 'Címkék',
 				'both' => 'Fejlécben és láblécben',

+ 5 - 0
app/i18n/id/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => 'Di baris penulis dan tanggal',
 			),
 			'feed_title' => 'Judul feed',
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// TODO
+				'above_title' => 'Above title',	// TODO
+				'with_authors' => 'In authors and date row',	// TODO
+			),
 			'tags' => array(
 				'_' => 'Tag',
 				'both' => 'Di header dan footer',

+ 5 - 0
app/i18n/it/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => 'Nella riga degli autori e data',
 			),
 			'feed_title' => 'Titolo del feed',
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// TODO
+				'above_title' => 'Above title',	// TODO
+				'with_authors' => 'In authors and date row',	// TODO
+			),
 			'tags' => array(
 				'_' => 'Tag',
 				'both' => 'Nell’intestazione e nel fondo pagina',

+ 5 - 0
app/i18n/ja/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => '著者と日付の行',
 			),
 			'feed_title' => 'フィードのタイトル',
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// TODO
+				'above_title' => 'Above title',	// TODO
+				'with_authors' => 'In authors and date row',	// TODO
+			),
 			'tags' => array(
 				'_' => 'タグ',
 				'both' => 'ヘッダーとフッター',

+ 5 - 0
app/i18n/ko/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => '작성자, 작성일과 같은 줄에',
 			),
 			'feed_title' => '피드 제목',
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// TODO
+				'above_title' => 'Above title',	// TODO
+				'with_authors' => 'In authors and date row',	// TODO
+			),
 			'tags' => array(
 				'_' => '태그',
 				'both' => '머리말과 꼬리말에',

+ 5 - 0
app/i18n/lv/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => 'Autoru un datuma rindā',
 			),
 			'feed_title' => 'Barotnes tituls',
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// TODO
+				'above_title' => 'Above title',	// TODO
+				'with_authors' => 'In authors and date row',	// TODO
+			),
 			'tags' => array(
 				'_' => 'Birkas',
 				'both' => 'Virsrakstā un kājenē',

+ 5 - 0
app/i18n/nl/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => 'In lijn met auteurs en datum',
 			),
 			'feed_title' => 'Feedtitel',
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// TODO
+				'above_title' => 'Above title',	// TODO
+				'with_authors' => 'In authors and date row',	// TODO
+			),
 			'tags' => array(
 				'_' => 'Tags',	// IGNORE
 				'both' => 'In kop en voet',

+ 5 - 0
app/i18n/oc/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => 'Dins la linha autors e data',
 			),
 			'feed_title' => 'Títol del flux',
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// TODO
+				'above_title' => 'Above title',	// TODO
+				'with_authors' => 'In authors and date row',	// TODO
+			),
 			'tags' => array(
 				'_' => 'Etiquetas',
 				'both' => 'Dins l’entèsta e lo bas de pagina',

+ 5 - 0
app/i18n/pl/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => 'W tej samej linii co autor i data',
 			),
 			'feed_title' => 'Nazwa kanału',
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// TODO
+				'above_title' => 'Above title',	// TODO
+				'with_authors' => 'In authors and date row',	// TODO
+			),
 			'tags' => array(
 				'_' => 'Tagi',
 				'both' => 'W nagłówku i stopce',

+ 5 - 0
app/i18n/pt-br/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => 'Com autores e data',
 			),
 			'feed_title' => 'Título do Feed',
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// TODO
+				'above_title' => 'Above title',	// TODO
+				'with_authors' => 'In authors and date row',	// TODO
+			),
 			'tags' => array(
 				'_' => 'Tag',
 				'both' => 'No cabeçalho e rodapé',

+ 5 - 0
app/i18n/ru/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => 'В строке с автором и датой',
 			),
 			'feed_title' => 'Титул ленты',
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// TODO
+				'above_title' => 'Above title',	// TODO
+				'with_authors' => 'In authors and date row',	// TODO
+			),
 			'tags' => array(
 				'_' => 'Метки',
 				'both' => 'В верхнем и нижнем колонтитулах',

+ 1 - 1
app/i18n/ru/sub.php

@@ -16,7 +16,7 @@ return array(
 		'title' => 'API',	// IGNORE
 	),
 	'bookmarklet' => array(
-		'documentation' => 'Перетяните эту кнопку на вашу панель закладок, или нажмите правой кнопкой мыши и выберите "Добавить ссылку в закладки". Нажимайте кнопку "Подписаться" на любой странице, на которую вы хотите подписаться.<br>',
+		'documentation' => 'Перетяните эту кнопку на вашу панель закладок, или нажмите правой кнопкой мыши и выберите "Добавить ссылку в закладки". Нажимайте кнопку "Подписаться" на любой странице, на которую вы хотите подписаться.<br />',
 		'label' => 'Подписаться',
 		'title' => 'Букмарклет',
 	),

+ 5 - 0
app/i18n/sk/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => 'V riadku autori a dátum',
 			),
 			'feed_title' => 'Nadpis kanála',
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// TODO
+				'above_title' => 'Above title',	// TODO
+				'with_authors' => 'In authors and date row',	// TODO
+			),
 			'tags' => array(
 				'_' => 'Značky',
 				'both' => 'V záhlaví a pätičke',

+ 5 - 0
app/i18n/tr/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => 'Yazarlar ve tarihler satırında',
 			),
 			'feed_title' => 'Akış Başlığı',
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// TODO
+				'above_title' => 'Above title',	// TODO
+				'with_authors' => 'In authors and date row',	// TODO
+			),
 			'tags' => array(
 				'_' => 'Etiketler',
 				'both' => 'Üst Bilgi ve Alt Bilgide',

+ 5 - 0
app/i18n/zh-cn/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => '与作者和日期一行',
 			),
 			'feed_title' => '订阅源标题',
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// TODO
+				'above_title' => 'Above title',	// TODO
+				'with_authors' => 'In authors and date row',	// TODO
+			),
 			'tags' => array(
 				'_' => '文章标签',
 				'both' => '页脚与页眉',

+ 5 - 0
app/i18n/zh-tw/conf.php

@@ -186,6 +186,11 @@ return array(
 				'with_authors' => '與作者和日期一行',
 			),
 			'feed_title' => '訂閱源標題',
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// TODO
+				'above_title' => 'Above title',	// TODO
+				'with_authors' => 'In authors and date row',	// TODO
+			),
 			'tags' => array(
 				'_' => '文章標籤',
 				'both' => '兩者都顯示',

+ 9 - 0
app/views/configure/reading.phtml

@@ -136,6 +136,15 @@
 					</select>
 				</div>
 			</div>
+			<div class="form-group">
+				<label class="group-name" for="show_article_icons"><?= _t('conf.reading.article.icons') ?></label>
+				<div class="group-controls">
+					<select name="show_article_icons" id="show_article_icons" data-leave-validation="<?= FreshRSS_Context::userConf()->show_article_icons ?>">
+						<option value="t" <?= FreshRSS_Context::userConf()->show_article_icons === 't' ? ' selected="selected"' : '' ?> data-input-visible="true"><?= _t('conf.reading.article.icons.above_title') ?></option>	
+						<option value="a" <?= FreshRSS_Context::userConf()->show_article_icons === 'a' ? ' selected="selected"' : '' ?> data-input-visible="true"><?= _t('conf.reading.article.icons.with_authors') ?></option>
+					</select>
+				</div>
+			</div>
 			<div class="form-group">
 				<label class="group-name" for="show_tags"><?= _t('conf.reading.article.tags') ?></label>
 				<div class="group-controls">

+ 57 - 26
app/views/helpers/index/article.phtml

@@ -1,4 +1,5 @@
 <?php
+	// used only in Reading view and html.phtml
 	declare(strict_types=1);
 	/** @var FreshRSS_View $this */
 	$entry = $this->entry;
@@ -17,16 +18,32 @@
 				$readUrl['params']['is_read'] = '0';
 			}
 		?>
-		<div class="article-header-topline">
+		<div class="article-header-topline horizontal-list">
 			<?php if (FreshRSS_Auth::hasAccess()) { ?>
-				<a class="read" href="<?= Minz_Url::display($readUrl) ?>" title="<?= _t('conf.shortcut.mark_read') ?>"><?= _i($entry->isRead() ? 'read' : 'unread') ?></a>
-				<a class="bookmark" href="<?= Minz_Url::display($favoriteUrl) ?>" title="<?= _t('conf.shortcut.mark_favorite') ?>"><?= _i($entry->isFavorite() ? 'starred' : 'non-starred') ?></a>
+				<?php if (FreshRSS_Context::userConf()->topline_read && FreshRSS_Context::userConf()->show_article_icons == 't') { ?>
+					<div class="item manage">
+						<a class="read" href="<?= Minz_Url::display($readUrl) ?>" title="<?= _t('conf.shortcut.mark_read') ?>"><?= _i($entry->isRead() ? 'read' : 'unread') ?></a>
+					</div>
+				<?php } ?>
+				<?php if (FreshRSS_Context::userConf()->topline_favorite && FreshRSS_Context::userConf()->show_article_icons == 't') { ?>
+					<div class="item manage">
+						<a class="bookmark" href="<?= Minz_Url::display($favoriteUrl) ?>" title="<?= _t('conf.shortcut.mark_favorite') ?>"><?= _i($entry->isFavorite() ? 'starred' : 'non-starred') ?></a>
+					</div>
+				<?php } ?>					
 			<?php } ?>
-			<?php if (FreshRSS_Context::userConf()->show_feed_name === 't') { ?>
-				<a class="website" href="<?= _url('index', 'reader', 'get', 'f_' . $feed->id()) ?>" title="<?= _t('gen.action.filter') ?>">
-					<?php if (FreshRSS_Context::userConf()->show_favicons): ?>
-						<img class="favicon" src="<?= $feed->favicon() ?>" alt="✇" loading="lazy" /><?php
-					endif; ?><span><?= $feed->name() ?></span></a>
+			<div class="item">
+				<?php if (FreshRSS_Context::userConf()->show_feed_name === 't') { ?>
+					<a class="website" href="<?= _url('index', 'reader', 'get', 'f_' . $feed->id()) ?>" title="<?= _t('gen.action.filter') ?>">
+						<?php if (FreshRSS_Context::userConf()->show_favicons): ?>
+							<img class="favicon" src="<?= $feed->favicon() ?>" alt="✇" loading="lazy" /><?php
+						endif; ?><span><?= $feed->name() ?></span></a>
+				<?php } ?>
+			</div>
+			<?php
+			if (FreshRSS_Context::userConf()->topline_link && FreshRSS_Context::userConf()->show_article_icons == 't') { ?>
+				<div class="item link">
+					<a target="_blank" rel="noreferrer" href="<?= $this->entry->link() ?>" class="item-element" title="<?= _t('conf.shortcut.see_on_website') ?>"><?= _i('link') ?></a>
+				</div>
 			<?php } ?>
 		</div>
 
@@ -35,24 +52,31 @@
 				$this->renderHelper('index/tags');
 			}
 		?>
-
 		<h1 class="title"><a target="_blank" rel="noreferrer" class="go_website" href="<?= $entry->link() ?>"><?= $entry->title() ?></a></h1>
-		<?php if (FreshRSS_Context::userConf()->show_author_date === 'h' || FreshRSS_Context::userConf()->show_author_date === 'b') { ?>
-			<div class="subtitle">
-				<?php if (FreshRSS_Context::userConf()->show_feed_name === 'a') { ?>
-					<div class="website">
-						<a href="<?= $this->internal_rendering ? $feed->website() : _url('index', 'reader', 'get', 'f_' . $feed->id()) ?>" title="<?= _t('gen.action.filter') ?>">
+		<?php if (in_array(FreshRSS_Context::userConf()->show_author_date, ['h','b'], true)) { ?>
+			<div class="subtitle horizontal-list">
+				<?php if (FreshRSS_Auth::hasAccess()) { ?>
+					<?php if (FreshRSS_Context::userConf()->topline_read && FreshRSS_Context::userConf()->show_article_icons == 'a') { ?>
+						<div class="item manage">
+							<a class="read" href="<?= Minz_Url::display($readUrl) ?>" title="<?= _t('conf.shortcut.mark_read') ?>"><?= _i($entry->isRead() ? 'read' : 'unread') ?></a>
+						</div>
+					<?php } ?>
+					<?php if (FreshRSS_Context::userConf()->topline_favorite && FreshRSS_Context::userConf()->show_article_icons == 'a') { ?>
+						<div class="item manage">
+							<a class="bookmark" href="<?= Minz_Url::display($favoriteUrl) ?>" title="<?= _t('conf.shortcut.mark_favorite') ?>"><?= _i($entry->isFavorite() ? 'starred' : 'non-starred') ?></a>
+						</div>
+					<?php } ?>
+				<?php } ?>
+				<div class="item">
+					<?php if (FreshRSS_Context::userConf()->show_feed_name === 'a') { ?>
+						<span class="website"><a href="<?= $this->internal_rendering ? $feed->website() : _url('index', 'reader', 'get', 'f_' . $feed->id()) ?>" title="<?= _t('gen.action.filter') ?>">
 							<?php if (FreshRSS_Context::userConf()->show_favicons): ?>
 								<img class="favicon" src="<?= $feed->favicon() ?>" alt="✇" loading="lazy" /><?php
-							endif; ?><span><?= $feed->name() ?></span>
-						</a>
-					</div>
-				<?php }
-
-				$authors = $entry->authors();
-				if (!empty($authors) && is_array($authors)) {
-					?>
-					<div class="author">
+							endif; ?><span><?= $feed->name() ?></span></a></span>
+					<?php }
+					$authors = $entry->authors();
+					if (!empty($authors) && is_array($authors)) { ?>
+						<div class="author">
 						<?= _t('gen.short.by_author') ?>
 						<?php
 						foreach ($authors as $author) {
@@ -60,11 +84,18 @@
 							?>
 							<a href="<?= $href ?>" title="<?= _t('gen.action.filter') ?>"><?= $author ?></a>
 						<?php } ?>
-					</div>
-				<?php } ?>
-				<div class="date">
+						</div>
+					<?php } ?>
+				</div>
+				<div class="item date">
 					<time datetime="<?= $entry->machineReadableDate() ?>"><?= $entry->date() ?></time>
 				</div>
+				<?php
+				if (FreshRSS_Context::userConf()->topline_link && FreshRSS_Context::userConf()->show_article_icons == 'a') { ?>
+					<div class="item link">
+						<a target="_blank" rel="noreferrer" href="<?= $this->entry->link() ?>" class="item-element" title="<?= _t('conf.shortcut.see_on_website') ?>"><?= _i('link') ?></a>
+					</div>
+				<?php } ?>
 			</div>
 		<?php } ?>
 	</header>

+ 1 - 0
config-user.default.php

@@ -40,6 +40,7 @@ return array (
 	'show_tags_max' => 7,
 	'show_author_date' => 'h',	// {0 => none, b => both, f => footer, h => header}
 	'show_feed_name' => 'a',	// {0 => none, a => with authors, t => above title}
+	'show_article_icons' => 't', // {a => with_authors, t => above title}
 	'hide_read_feeds' => true,
 	'onread_jump_next' => true,
 	'lazyload' => true,

+ 47 - 1
p/themes/base-theme/frss.css

@@ -1539,6 +1539,52 @@ a.website:hover .favicon {
 	padding: 0 0 0.25rem 1rem;
 }
 
+.content .article-header-topline.horizontal-list .item.manage,
+.content .subtitle.horizontal-list .item.manage {
+	text-align: left;
+	width: 2rem;
+}
+
+.content .article-header-topline.horizontal-list .item.manage a,
+.content .subtitle.horizontal-list .item.manage a {
+	padding: 0.5rem 0.25rem;
+}
+
+.content .article-header-topline.horizontal-list .item,
+.content .subtitle.horizontal-list .item {
+	vertical-align: top;
+}
+
+.content .article-header-topline.horizontal-list .item .website,
+.content .subtitle.horizontal-list .item .website {
+	display: inline-block;
+	max-width: 100%;
+	overflow: hidden;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+	vertical-align: top;
+}
+
+.content .subtitle.horizontal-list .item .author {
+	display: inline-block;
+}
+
+.content .subtitle.horizontal-list .item.date {
+	padding: 0.25rem;
+	width: 155px;
+	text-align: right;
+}
+
+.content .article-header-topline.horizontal-list .item.link,
+.content .subtitle.horizontal-list .item.link {
+	text-align: right;
+}
+
+.content .article-header-topline.horizontal-list .item.link a,
+.content .subtitle.horizontal-list .item.link a {
+	padding: 0.25rem 0.5rem;
+}
+
 .content pre {
 	overflow: auto;
 }
@@ -1547,7 +1593,7 @@ a.website:hover .favicon {
 	display: inline;
 }
 
-.subtitle > div:not(:first-of-type)::before {
+.subtitle:not(.horizontal-list) > div:not(:first-of-type)::before {
 	content: ' · ';
 }
 

+ 47 - 1
p/themes/base-theme/frss.rtl.css

@@ -1539,6 +1539,52 @@ a.website:hover .favicon {
 	padding: 0 1rem 0.25rem 0;
 }
 
+.content .article-header-topline.horizontal-list .item.manage,
+.content .subtitle.horizontal-list .item.manage {
+	text-align: right;
+	width: 2rem;
+}
+
+.content .article-header-topline.horizontal-list .item.manage a,
+.content .subtitle.horizontal-list .item.manage a {
+	padding: 0.5rem 0.25rem;
+}
+
+.content .article-header-topline.horizontal-list .item,
+.content .subtitle.horizontal-list .item {
+	vertical-align: top;
+}
+
+.content .article-header-topline.horizontal-list .item .website,
+.content .subtitle.horizontal-list .item .website {
+	display: inline-block;
+	max-width: 100%;
+	overflow: hidden;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+	vertical-align: top;
+}
+
+.content .subtitle.horizontal-list .item .author {
+	display: inline-block;
+}
+
+.content .subtitle.horizontal-list .item.date {
+	padding: 0.25rem;
+	width: 155px;
+	text-align: left;
+}
+
+.content .article-header-topline.horizontal-list .item.link,
+.content .subtitle.horizontal-list .item.link {
+	text-align: left;
+}
+
+.content .article-header-topline.horizontal-list .item.link a,
+.content .subtitle.horizontal-list .item.link a {
+	padding: 0.25rem 0.5rem;
+}
+
 .content pre {
 	overflow: auto;
 }
@@ -1547,7 +1593,7 @@ a.website:hover .favicon {
 	display: inline;
 }
 
-.subtitle > div:not(:first-of-type)::before {
+.subtitle:not(.horizontal-list) > div:not(:first-of-type)::before {
 	content: ' · ';
 }