Procházet zdrojové kódy

Add SVG icons to entry actions

Frédéric Guillot před 6 roky
rodič
revize
3c3241f93c

+ 8 - 8
locale/translations.go

@@ -398,7 +398,7 @@ var translations = map[string]string{
     "entry.save.title": "Save this article",
     "entry.save.completed": "Done!",
     "entry.save.toast.completed": "Article saved",
-    "entry.scraper.label": "Fetch original content",
+    "entry.scraper.label": "Original",
     "entry.scraper.title": "Fetch original content",
     "entry.scraper.completed": "Done!",
     "entry.original.label": "Original",
@@ -1014,7 +1014,7 @@ var translations = map[string]string{
     "entry.save.title": "Sauvegarder cet article",
     "entry.save.completed": "Terminé !",
     "entry.save.toast.completed": "Article sauvegardé",
-    "entry.scraper.label": "Contenu original",
+    "entry.scraper.label": "Original",
     "entry.scraper.title": "Récupérer le contenu original",
     "entry.scraper.completed": "Terminé !",
     "entry.original.label": "Original",
@@ -1345,7 +1345,7 @@ var translations = map[string]string{
     "entry.scraper.label": "Scarica il contenuto integrale",
     "entry.scraper.title": "Scarica il contenuto integrale",
     "entry.scraper.completed": "Fatto!",
-    "entry.original.label": "Contenuto originale",
+    "entry.original.label": "Originale",
     "entry.comments.label": "Commenti",
     "entry.comments.title": "Mostra i commenti",
     "entry.share.label": "Condividi",
@@ -2287,7 +2287,7 @@ var translations = map[string]string{
     "entry.scraper.label": "Pobierz treść",
     "entry.scraper.title": "Pobierz oryginalną treść",
     "entry.scraper.completed": "Gotowe!",
-    "entry.original.label": "Oryginalny artykuł",
+    "entry.original.label": "Oryginalny",
     "entry.comments.label": "Komentarze",
     "entry.comments.title": "Zobacz komentarze",
     "entry.share.label": "Podzielić się",
@@ -3190,13 +3190,13 @@ var translations = map[string]string{
 
 var translationsChecksums = map[string]string{
 	"de_DE": "7360a69e038d71e00f64c03891401cd517779687d46a907688f4a9a7b6205146",
-	"en_US": "92dda79899a673652a43fd8d61c893749713af09909ca03ac6fea06ac617d361",
+	"en_US": "5d9cad74ccfd94393aa98a25f28fa4f41895d8f758461760601d04c92f898d02",
 	"es_ES": "813b8cd42907dfbc19ff51f3367e0dbb013d373b013d7854df512e846652ff21",
-	"fr_FR": "279c52bbf682949cf8782e7e81f2bf5cfd300cebf577d51ce9436d44aaaf6323",
-	"it_IT": "5e8408e9aee142e1bd7e73f2a91ae96bc9ad0ab61c20416ad9e93b6fe505e8a9",
+	"fr_FR": "bf770b1ecfd722bbf4fa29d2ea567b064c8bcb517141073ab3d170d27f4e53e4",
+	"it_IT": "fe2c7147f3c39784f482cf922d9d3a85a94f15af8ff28ebcec64723555a3fb10",
 	"ja_JP": "508025c0c7e7f57195ae011c4499ab58a85d043c828565c1740df879fb2376c1",
 	"nl_NL": "e621a5e7408928624a060a832d9fc36b74026221bd7b07894a4cce267be3cdd1",
-	"pl_PL": "2383c1a9be451557fe601f346e30bb165a88d9c00d17909a9c747d64864a423d",
+	"pl_PL": "6edcefd04e453c84b03207653c54f7be9a4a8ce4699e06c82bfcca2d7946f47e",
 	"ru_RU": "d7ad59bbd7a150af9d476c4c3034eb85762de7381e2925d75e373584ed45c725",
 	"zh_CN": "e5f169a3c83c9bd7a41e9737e001e58fec243eee7aa23a71d37bfa8e05d92860",
 }

+ 1 - 1
locale/translations/en_US.json

@@ -65,7 +65,7 @@
     "entry.save.title": "Save this article",
     "entry.save.completed": "Done!",
     "entry.save.toast.completed": "Article saved",
-    "entry.scraper.label": "Fetch original content",
+    "entry.scraper.label": "Original",
     "entry.scraper.title": "Fetch original content",
     "entry.scraper.completed": "Done!",
     "entry.original.label": "Original",

+ 1 - 1
locale/translations/fr_FR.json

@@ -65,7 +65,7 @@
     "entry.save.title": "Sauvegarder cet article",
     "entry.save.completed": "Terminé !",
     "entry.save.toast.completed": "Article sauvegardé",
-    "entry.scraper.label": "Contenu original",
+    "entry.scraper.label": "Original",
     "entry.scraper.title": "Récupérer le contenu original",
     "entry.scraper.completed": "Terminé !",
     "entry.original.label": "Original",

+ 1 - 1
locale/translations/it_IT.json

@@ -68,7 +68,7 @@
     "entry.scraper.label": "Scarica il contenuto integrale",
     "entry.scraper.title": "Scarica il contenuto integrale",
     "entry.scraper.completed": "Fatto!",
-    "entry.original.label": "Contenuto originale",
+    "entry.original.label": "Originale",
     "entry.comments.label": "Commenti",
     "entry.comments.title": "Mostra i commenti",
     "entry.share.label": "Condividi",

+ 1 - 1
locale/translations/pl_PL.json

@@ -68,7 +68,7 @@
     "entry.scraper.label": "Pobierz treść",
     "entry.scraper.title": "Pobierz oryginalną treść",
     "entry.scraper.completed": "Gotowe!",
-    "entry.original.label": "Oryginalny artykuł",
+    "entry.original.label": "Oryginalny",
     "entry.comments.label": "Komentarze",
     "entry.comments.title": "Zobacz komentarze",
     "entry.share.label": "Podzielić się",

+ 106 - 8
template/common.go

@@ -97,6 +97,94 @@ var templateCommonMap = map[string]string{
         <a href="{{ route "refreshAllFeeds" }}">{{ t "menu.refresh_all_feeds" }}</a>
     </li>
 </ul>
+{{ end }}`,
+	"icons": `<!--
+
+MIT License
+
+Copyright (c) 2020 Paweł Kuna
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+-->
+{{ define "icon_read" }}
+<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-circle-check" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
+    <path stroke="none" d="M0 0h24v24H0z"/>
+    <circle cx="12" cy="12" r="9" />
+    <path d="M9 12l2 2l4 -4" />
+</svg>
+{{ end }}
+{{ define "icon_unread" }}
+<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-circle-x" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
+    <path stroke="none" d="M0 0h24v24H0z"/>
+    <circle cx="12" cy="12" r="9" />
+    <path d="M10 10l4 4m0 -4l-4 4" />
+</svg>
+{{ end }}
+{{ define "icon_star" }}
+<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-star" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
+    <path stroke="none" d="M0 0h24v24H0z"/>
+    <path d="M12 17.75l-6.172 3.245 1.179-6.873-4.993-4.867 6.9-1.002L12 2l3.086 6.253 6.9 1.002-4.993 4.867 1.179 6.873z" />
+</svg>
+{{ end }}
+{{ define "icon_save" }}
+<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-download" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
+    <path stroke="none" d="M0 0h24v24H0z"/>
+    <path d="M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2v-2" />
+    <polyline points="7 11 12 16 17 11" />
+    <line x1="12" y1="4" x2="12" y2="16" />
+</svg>
+{{ end }}
+{{ define "icon_scraper" }}
+<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-cloud-download" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
+    <path stroke="none" d="M0 0h24v24H0z"/>
+    <path d="M19 18a3.5 3.5 0 0 0 0 -7h-1a5 4.5 0 0 0 -11 -2a4.6 4.4 0 0 0 -2.1 8.4" />
+    <line x1="12" y1="13" x2="12" y2="22" />
+    <polyline points="9 19 12 22 15 19" />
+</svg>
+{{ end }}
+{{ define "icon_share" }}
+<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-share" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
+    <path stroke="none" d="M0 0h24v24H0z"/>
+    <circle cx="6" cy="12" r="3" />
+    <circle cx="18" cy="6" r="3" />
+    <circle cx="18" cy="18" r="3" />
+    <line x1="8.7" y1="10.7" x2="15.3" y2="7.3" />
+    <line x1="8.7" y1="13.3" x2="15.3" y2="16.7" />
+</svg>
+{{ end }}
+{{ define "icon_comment" }}
+<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-message-circle" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
+    <path stroke="none" d="M0 0h24v24H0z"/>
+    <path d="M3 20l1.3 -3.9a9 8 0 1 1 3.4 2.9l-4.7 1" />
+    <line x1="12" y1="12" x2="12" y2="12.01" />
+    <line x1="8" y1="12" x2="8" y2="12.01" />
+    <line x1="16" y1="12" x2="16" y2="12.01" />
+</svg>
+{{ end }}
+{{ define "icon_original" }}
+<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-external-link" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
+    <path stroke="none" d="M0 0h24v24H0z"/>
+    <path d="M11 7h-5a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-5" />
+    <line x1="10" y1="14" x2="20" y2="4" />
+    <polyline points="15 4 20 4 20 9" />
+</svg>
 {{ end }}`,
 	"item_meta": `{{ define "item_meta" }}
 <div class="item-meta">
@@ -108,7 +196,7 @@ var templateCommonMap = map[string]string{
             <time datetime="{{ isodate .entry.Date }}" title="{{ isodate .entry.Date }}">{{ elapsed .user.Timezone .entry.Date }}</time>
         </li>
     </ul>
-    <ul>
+    <ul class="item-meta-icons">
         {{ if .hasSaveEntry }}
             <li>
                 <a href="#"
@@ -117,15 +205,24 @@ var templateCommonMap = map[string]string{
                     data-save-url="{{ route "saveEntry" "entryID" .entry.ID }}"
                     data-label-loading="{{ t "entry.state.saving" }}"
                     data-label-done="{{ t "entry.save.completed" }}"
-                    >{{ t "entry.save.label" }}</a>
+                    >{{ template "icon_save" }}<span class="icon-label">{{ t "entry.save.label" }}</span></a>
             </li>
         {{ end }}
         <li>
-            <a href="{{ .entry.URL | safeURL  }}" target="_blank" rel="noopener noreferrer" referrerpolicy="no-referrer" data-original-link="true">{{ t "entry.original.label" }}</a>
+            <a href="{{ .entry.URL | safeURL  }}"
+                target="_blank"
+                rel="noopener noreferrer"
+                referrerpolicy="no-referrer"
+                data-original-link="true">{{ template "icon_original" }}<span class="icon-label">{{ t "entry.original.label" }}</span></a>
         </li>
         {{ if .entry.CommentsURL }}
             <li>
-                <a href="{{ .entry.CommentsURL | safeURL  }}" title="{{ t "entry.comments.title" }}" target="_blank" rel="noopener noreferrer" referrerpolicy="no-referrer" data-comments-link="true">{{ t "entry.comments.label" }}</a>
+                <a href="{{ .entry.CommentsURL | safeURL  }}"
+                    title="{{ t "entry.comments.title" }}"
+                    target="_blank"
+                    rel="noopener noreferrer"
+                    referrerpolicy="no-referrer"
+                    data-comments-link="true">{{ template "icon_comment" }}<span class="icon-label">{{ t "entry.comments.label" }}</span></a>
             </li>
         {{ end }}
         <li>
@@ -136,16 +233,16 @@ var templateCommonMap = map[string]string{
                 data-label-star="☆&nbsp;{{ t "entry.bookmark.toggle.on" }}"
                 data-label-unstar="★&nbsp;{{ t "entry.bookmark.toggle.off" }}"
                 data-value="{{ if .entry.Starred }}star{{ else }}unstar{{ end }}"
-                >{{ if .entry.Starred }}★&nbsp;{{ t "entry.bookmark.toggle.off" }}{{ else }}☆&nbsp;{{ t "entry.bookmark.toggle.on" }}{{ end }}</a>
+                ><span class="icon-label">{{ if .entry.Starred }}★&nbsp;{{ t "entry.bookmark.toggle.off" }}{{ else }}☆&nbsp;{{ t "entry.bookmark.toggle.on" }}{{ end }}</span></a>
         </li>
         <li>
             <a href="#"
                 title="{{ t "entry.status.title" }}"
                 data-toggle-status="true"
-                data-label-read="✔&#xfe0e;&nbsp;{{ t "entry.status.read" }}"
+                data-label-read="✔&nbsp;{{ t "entry.status.read" }}"
                 data-label-unread="✘&nbsp;{{ t "entry.status.unread" }}"
                 data-value="{{ if eq .entry.Status "read" }}read{{ else }}unread{{ end }}"
-                >{{ if eq .entry.Status "read" }}✘&nbsp;{{ t "entry.status.unread" }}{{ else }}✔&#xfe0e;&nbsp;{{ t "entry.status.read" }}{{ end }}</a>
+                ><span class="icon-label">{{ if eq .entry.Status "read" }}✘&nbsp;{{ t "entry.status.unread" }}{{ else }}✔&nbsp;{{ t "entry.status.read" }}{{ end }}</span></a>
         </li>
     </ul>
 </div>
@@ -358,7 +455,8 @@ var templateCommonMapChecksums = map[string]string{
 	"entry_pagination": "cdca9cf12586e41e5355190b06d9168f57f77b85924d1e63b13524bc15abcbf6",
 	"feed_list":        "db406e7cb81292ce1d974d63f63270384a286848b2e74fe36bf711b4eb5717dd",
 	"feed_menu":        "318d8662dda5ca9dfc75b909c8461e79c86fb5082df1428f67aaf856f19f4b50",
-	"item_meta":        "d046305e8935ecd8643a94d28af384df29e40fc7ce334123cd057a6522bac23f",
+	"icons":            "d9b4105a89364d913ad975b569286e6bd79f270da995856d21a10537e42b93f4",
+	"item_meta":        "d7aac9a904f07c57e35c9756c3fafb03e6b65c7e72a301e81cb62d99be2bd866",
 	"layout":           "a1f67b8908745ee4f9cee6f7bbbb0b242d4dcc101207ad4a9d67242b45683299",
 	"pagination":       "7b61288e86283c4cf0dc83bcbf8bf1c00c7cb29e60201c8c0b633b2450d2911f",
 	"settings_menu":    "e2b777630c0efdbc529800303c01d6744ed3af80ec505ac5a5b3f99c9b989156",

+ 88 - 0
template/html/common/icons.html

@@ -0,0 +1,88 @@
+<!--
+
+MIT License
+
+Copyright (c) 2020 Paweł Kuna
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+-->
+{{ define "icon_read" }}
+<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-circle-check" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
+    <path stroke="none" d="M0 0h24v24H0z"/>
+    <circle cx="12" cy="12" r="9" />
+    <path d="M9 12l2 2l4 -4" />
+</svg>
+{{ end }}
+{{ define "icon_unread" }}
+<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-circle-x" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
+    <path stroke="none" d="M0 0h24v24H0z"/>
+    <circle cx="12" cy="12" r="9" />
+    <path d="M10 10l4 4m0 -4l-4 4" />
+</svg>
+{{ end }}
+{{ define "icon_star" }}
+<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-star" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
+    <path stroke="none" d="M0 0h24v24H0z"/>
+    <path d="M12 17.75l-6.172 3.245 1.179-6.873-4.993-4.867 6.9-1.002L12 2l3.086 6.253 6.9 1.002-4.993 4.867 1.179 6.873z" />
+</svg>
+{{ end }}
+{{ define "icon_save" }}
+<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-download" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
+    <path stroke="none" d="M0 0h24v24H0z"/>
+    <path d="M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2v-2" />
+    <polyline points="7 11 12 16 17 11" />
+    <line x1="12" y1="4" x2="12" y2="16" />
+</svg>
+{{ end }}
+{{ define "icon_scraper" }}
+<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-cloud-download" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
+    <path stroke="none" d="M0 0h24v24H0z"/>
+    <path d="M19 18a3.5 3.5 0 0 0 0 -7h-1a5 4.5 0 0 0 -11 -2a4.6 4.4 0 0 0 -2.1 8.4" />
+    <line x1="12" y1="13" x2="12" y2="22" />
+    <polyline points="9 19 12 22 15 19" />
+</svg>
+{{ end }}
+{{ define "icon_share" }}
+<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-share" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
+    <path stroke="none" d="M0 0h24v24H0z"/>
+    <circle cx="6" cy="12" r="3" />
+    <circle cx="18" cy="6" r="3" />
+    <circle cx="18" cy="18" r="3" />
+    <line x1="8.7" y1="10.7" x2="15.3" y2="7.3" />
+    <line x1="8.7" y1="13.3" x2="15.3" y2="16.7" />
+</svg>
+{{ end }}
+{{ define "icon_comment" }}
+<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-message-circle" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
+    <path stroke="none" d="M0 0h24v24H0z"/>
+    <path d="M3 20l1.3 -3.9a9 8 0 1 1 3.4 2.9l-4.7 1" />
+    <line x1="12" y1="12" x2="12" y2="12.01" />
+    <line x1="8" y1="12" x2="8" y2="12.01" />
+    <line x1="16" y1="12" x2="16" y2="12.01" />
+</svg>
+{{ end }}
+{{ define "icon_original" }}
+<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-external-link" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
+    <path stroke="none" d="M0 0h24v24H0z"/>
+    <path d="M11 7h-5a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-5" />
+    <line x1="10" y1="14" x2="20" y2="4" />
+    <polyline points="15 4 20 4 20 9" />
+</svg>
+{{ end }}

+ 16 - 7
template/html/common/item_meta.html

@@ -8,7 +8,7 @@
             <time datetime="{{ isodate .entry.Date }}" title="{{ isodate .entry.Date }}">{{ elapsed .user.Timezone .entry.Date }}</time>
         </li>
     </ul>
-    <ul>
+    <ul class="item-meta-icons">
         {{ if .hasSaveEntry }}
             <li>
                 <a href="#"
@@ -17,15 +17,24 @@
                     data-save-url="{{ route "saveEntry" "entryID" .entry.ID }}"
                     data-label-loading="{{ t "entry.state.saving" }}"
                     data-label-done="{{ t "entry.save.completed" }}"
-                    >{{ t "entry.save.label" }}</a>
+                    >{{ template "icon_save" }}<span class="icon-label">{{ t "entry.save.label" }}</span></a>
             </li>
         {{ end }}
         <li>
-            <a href="{{ .entry.URL | safeURL  }}" target="_blank" rel="noopener noreferrer" referrerpolicy="no-referrer" data-original-link="true">{{ t "entry.original.label" }}</a>
+            <a href="{{ .entry.URL | safeURL  }}"
+                target="_blank"
+                rel="noopener noreferrer"
+                referrerpolicy="no-referrer"
+                data-original-link="true">{{ template "icon_original" }}<span class="icon-label">{{ t "entry.original.label" }}</span></a>
         </li>
         {{ if .entry.CommentsURL }}
             <li>
-                <a href="{{ .entry.CommentsURL | safeURL  }}" title="{{ t "entry.comments.title" }}" target="_blank" rel="noopener noreferrer" referrerpolicy="no-referrer" data-comments-link="true">{{ t "entry.comments.label" }}</a>
+                <a href="{{ .entry.CommentsURL | safeURL  }}"
+                    title="{{ t "entry.comments.title" }}"
+                    target="_blank"
+                    rel="noopener noreferrer"
+                    referrerpolicy="no-referrer"
+                    data-comments-link="true">{{ template "icon_comment" }}<span class="icon-label">{{ t "entry.comments.label" }}</span></a>
             </li>
         {{ end }}
         <li>
@@ -36,16 +45,16 @@
                 data-label-star="☆&nbsp;{{ t "entry.bookmark.toggle.on" }}"
                 data-label-unstar="★&nbsp;{{ t "entry.bookmark.toggle.off" }}"
                 data-value="{{ if .entry.Starred }}star{{ else }}unstar{{ end }}"
-                >{{ if .entry.Starred }}★&nbsp;{{ t "entry.bookmark.toggle.off" }}{{ else }}☆&nbsp;{{ t "entry.bookmark.toggle.on" }}{{ end }}</a>
+                ><span class="icon-label">{{ if .entry.Starred }}★&nbsp;{{ t "entry.bookmark.toggle.off" }}{{ else }}☆&nbsp;{{ t "entry.bookmark.toggle.on" }}{{ end }}</span></a>
         </li>
         <li>
             <a href="#"
                 title="{{ t "entry.status.title" }}"
                 data-toggle-status="true"
-                data-label-read="✔&#xfe0e;&nbsp;{{ t "entry.status.read" }}"
+                data-label-read="✔&nbsp;{{ t "entry.status.read" }}"
                 data-label-unread="✘&nbsp;{{ t "entry.status.unread" }}"
                 data-value="{{ if eq .entry.Status "read" }}read{{ else }}unread{{ end }}"
-                >{{ if eq .entry.Status "read" }}✘&nbsp;{{ t "entry.status.unread" }}{{ else }}✔&#xfe0e;&nbsp;{{ t "entry.status.read" }}{{ end }}</a>
+                ><span class="icon-label">{{ if eq .entry.Status "read" }}✘&nbsp;{{ t "entry.status.unread" }}{{ else }}✔&nbsp;{{ t "entry.status.read" }}{{ end }}</span></a>
         </li>
     </ul>
 </div>

+ 16 - 11
template/html/entry.html

@@ -13,12 +13,12 @@
                     <a href="#"
                         title="{{ t "entry.status.title" }}"
                         data-toggle-status="true"
-                        data-label-read="✔&#xfe0e;&nbsp;{{ t "entry.status.read" }}"
-                        data-label-unread="✘&nbsp;{{ t "entry.status.unread" }}"
-                        data-toast-read="✔︎&nbsp;{{ t "entry.status.toast.read" }}"
-                        data-toast-unread="✘&nbsp;{{ t "entry.status.toast.unread" }}"
+                        data-label-read="✘&nbsp;{{ t "entry.status.unread" }}"
+                        data-label-unread="✔︎&nbsp;{{ t "entry.status.read" }}"
+                        data-toast-read="✘&nbsp;{{ t "entry.status.toast.unread" }}"
+                        data-toast-unread="✔︎&nbsp;{{ t "entry.status.toast.read" }}"
                         data-value="{{ if eq .entry.Status "read" }}read{{ else }}unread{{ end }}"
-                        >{{ if eq .entry.Status "read" }}✘&nbsp;{{ t "entry.status.unread" }}{{ else }}✔&#xfe0e;&nbsp;{{ t "entry.status.read" }}{{ end }}</a>
+                        ><span class="icon-label">{{ if eq .entry.Status "read" }}✔&nbsp;{{ t "entry.status.read" }}{{ else }}✘&nbsp;{{ t "entry.status.unread" }}{{ end }}</span></a>
                 </li>
                 <li>
                     <a href="#"
@@ -30,7 +30,7 @@
                         data-toast-star="★&nbsp;{{ t "entry.bookmark.toast.on" }}"
                         data-toast-unstar="☆&nbsp;{{ t "entry.bookmark.toast.off" }}"
                         data-value="{{ if .entry.Starred }}star{{ else }}unstar{{ end }}"
-                        >{{ if .entry.Starred }}★&nbsp;{{ t "entry.bookmark.toggle.off" }}{{ else }}☆&nbsp;{{ t "entry.bookmark.toggle.on" }}{{ end }}</a>
+                        ><span class="icon-label">{{ if .entry.Starred }}★&nbsp;{{ t "entry.bookmark.toggle.off" }}{{ else }}☆&nbsp;{{ t "entry.bookmark.toggle.on" }}{{ end }}</span></a>
                 </li>
                 {{ if .hasSaveEntry }}
                     <li>
@@ -41,14 +41,14 @@
                             data-label-loading="{{ t "entry.state.saving" }}"
                             data-label-done="{{ t "entry.save.completed" }}"
                             data-toast-done="{{ t "entry.save.toast.completed" }}"
-                            >{{ t "entry.save.title" }}</a>
+                            >{{ template "icon_save" }}<span class="icon-label">{{ t "entry.save.label" }}</span></a>
                     </li>
                 {{ end }}
                 <li>
                     <a href="{{ route "shareGenerate" "entryID" .entry.ID }}"
                         title="{{ t "entry.share.title" }}"
                         target="_blank"
-                        >{{ t "entry.share.label" }}</a>
+                        >{{ template "icon_share" }}<span class="icon-label">{{ t "entry.share.label" }}</span></a>
                 </li>
                 <li>
                     <a href="#"
@@ -56,12 +56,17 @@
                         data-fetch-content-entry="true"
                         data-fetch-content-url="{{ route "fetchContent" "entryID" .entry.ID }}"
                         data-label-loading="{{ t "entry.state.loading" }}"
-                        data-label-done="{{ t "entry.scraper.completed" }}"
-                        >{{ t "entry.scraper.label" }}</a>
+                        >{{ template "icon_scraper" }}<span class="icon-label">{{ t "entry.scraper.label" }}</span></a>
                 </li>
                 {{ if .entry.CommentsURL }}
                     <li>
-                        <a href="{{ .entry.CommentsURL | safeURL }}" title="{{ t "entry.comments.title" }}" target="_blank" rel="noopener noreferrer" referrerpolicy="no-referrer" data-comments-link="true">{{ t "entry.comments.label" }}</a>
+                        <a href="{{ .entry.CommentsURL | safeURL }}"
+                           title="{{ t "entry.comments.title" }}"
+                           target="_blank"
+                           rel="noopener noreferrer"
+                           referrerpolicy="no-referrer"
+                           data-comments-link="true"
+                        >{{ template "icon_comment" }}<span class="icon-label">{{ t "entry.comments.label" }}</span></a>
                     </li>
                 {{ end }}
             </ul>

+ 17 - 12
template/views.go

@@ -660,12 +660,12 @@ var templateViewsMap = map[string]string{
                     <a href="#"
                         title="{{ t "entry.status.title" }}"
                         data-toggle-status="true"
-                        data-label-read="✔&#xfe0e;&nbsp;{{ t "entry.status.read" }}"
-                        data-label-unread="✘&nbsp;{{ t "entry.status.unread" }}"
-                        data-toast-read="✔︎&nbsp;{{ t "entry.status.toast.read" }}"
-                        data-toast-unread="✘&nbsp;{{ t "entry.status.toast.unread" }}"
+                        data-label-read="✘&nbsp;{{ t "entry.status.unread" }}"
+                        data-label-unread="✔︎&nbsp;{{ t "entry.status.read" }}"
+                        data-toast-read="✘&nbsp;{{ t "entry.status.toast.unread" }}"
+                        data-toast-unread="✔︎&nbsp;{{ t "entry.status.toast.read" }}"
                         data-value="{{ if eq .entry.Status "read" }}read{{ else }}unread{{ end }}"
-                        >{{ if eq .entry.Status "read" }}✘&nbsp;{{ t "entry.status.unread" }}{{ else }}✔&#xfe0e;&nbsp;{{ t "entry.status.read" }}{{ end }}</a>
+                        ><span class="icon-label">{{ if eq .entry.Status "read" }}✔&nbsp;{{ t "entry.status.read" }}{{ else }}✘&nbsp;{{ t "entry.status.unread" }}{{ end }}</span></a>
                 </li>
                 <li>
                     <a href="#"
@@ -677,7 +677,7 @@ var templateViewsMap = map[string]string{
                         data-toast-star="★&nbsp;{{ t "entry.bookmark.toast.on" }}"
                         data-toast-unstar="☆&nbsp;{{ t "entry.bookmark.toast.off" }}"
                         data-value="{{ if .entry.Starred }}star{{ else }}unstar{{ end }}"
-                        >{{ if .entry.Starred }}★&nbsp;{{ t "entry.bookmark.toggle.off" }}{{ else }}☆&nbsp;{{ t "entry.bookmark.toggle.on" }}{{ end }}</a>
+                        ><span class="icon-label">{{ if .entry.Starred }}★&nbsp;{{ t "entry.bookmark.toggle.off" }}{{ else }}☆&nbsp;{{ t "entry.bookmark.toggle.on" }}{{ end }}</span></a>
                 </li>
                 {{ if .hasSaveEntry }}
                     <li>
@@ -688,14 +688,14 @@ var templateViewsMap = map[string]string{
                             data-label-loading="{{ t "entry.state.saving" }}"
                             data-label-done="{{ t "entry.save.completed" }}"
                             data-toast-done="{{ t "entry.save.toast.completed" }}"
-                            >{{ t "entry.save.title" }}</a>
+                            >{{ template "icon_save" }}<span class="icon-label">{{ t "entry.save.label" }}</span></a>
                     </li>
                 {{ end }}
                 <li>
                     <a href="{{ route "shareGenerate" "entryID" .entry.ID }}"
                         title="{{ t "entry.share.title" }}"
                         target="_blank"
-                        >{{ t "entry.share.label" }}</a>
+                        >{{ template "icon_share" }}<span class="icon-label">{{ t "entry.share.label" }}</span></a>
                 </li>
                 <li>
                     <a href="#"
@@ -703,12 +703,17 @@ var templateViewsMap = map[string]string{
                         data-fetch-content-entry="true"
                         data-fetch-content-url="{{ route "fetchContent" "entryID" .entry.ID }}"
                         data-label-loading="{{ t "entry.state.loading" }}"
-                        data-label-done="{{ t "entry.scraper.completed" }}"
-                        >{{ t "entry.scraper.label" }}</a>
+                        >{{ template "icon_scraper" }}<span class="icon-label">{{ t "entry.scraper.label" }}</span></a>
                 </li>
                 {{ if .entry.CommentsURL }}
                     <li>
-                        <a href="{{ .entry.CommentsURL | safeURL }}" title="{{ t "entry.comments.title" }}" target="_blank" rel="noopener noreferrer" referrerpolicy="no-referrer" data-comments-link="true">{{ t "entry.comments.label" }}</a>
+                        <a href="{{ .entry.CommentsURL | safeURL }}"
+                           title="{{ t "entry.comments.title" }}"
+                           target="_blank"
+                           rel="noopener noreferrer"
+                           referrerpolicy="no-referrer"
+                           data-comments-link="true"
+                        >{{ template "icon_comment" }}<span class="icon-label">{{ t "entry.comments.label" }}</span></a>
                     </li>
                 {{ end }}
             </ul>
@@ -1452,7 +1457,7 @@ var templateViewsMapChecksums = map[string]string{
 	"edit_category":       "b1c0b38f1b714c5d884edcd61e5b5295a5f1c8b71c469b35391e4dcc97cc6d36",
 	"edit_feed":           "cc0b5dbb73f81398410958b41771ed38246bc7ae4bd548228f0d48c49a598c2a",
 	"edit_user":           "c692db9de1a084c57b93e95a14b041d39bf489846cbb91fc982a62b72b77062a",
-	"entry":               "0b66e8fa35f301808122f405544021b1c7070ea8734cc4348ba1a85a338d3646",
+	"entry":               "03814d36909f3af1a9164c407d8733bcf1f15c4aee516186d07561a81fa42eb3",
 	"feed_entries":        "9c70b82f55e4b311eff20be1641733612e3c1b406ce8010861e4c417d97b6dcc",
 	"feeds":               "ec7d3fa96735bd8422ba69ef0927dcccddc1cc51327e0271f0312d3f881c64fd",
 	"history_entries":     "87e17d39de70eb3fdbc4000326283be610928758eae7924e4b08dcb446f3b6a9",

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 0
ui/static/css.go


+ 26 - 5
ui/static/css/common.css

@@ -689,6 +689,18 @@ a.button {
     content: "";
 }
 
+.item-meta-icons li:after {
+    content: "";
+}
+
+.item-meta-icons li {
+    margin-right: 10px;
+}
+
+.item-meta-icons li:last-child {
+    margin-right: 0;
+}
+
 .items {
     overflow-x: hidden;
 }
@@ -713,6 +725,18 @@ article.feed-parsing-error {
     cursor: pointer;
 }
 
+/* Icons */
+.icon,
+.icon-label {
+    vertical-align: middle;
+    display: inline-block;
+}
+
+.icon {
+    width: 16px;
+    height: 16px;
+}
+
 /* Entry view */
 .entry header {
     padding-bottom: 5px;
@@ -744,11 +768,8 @@ article.feed-parsing-error {
 }
 
 .entry-actions li {
-    display: inline;
-}
-
-.entry-actions li:not(:last-child):after {
-    content: "|";
+    display: inline-block;
+    margin-right: 15px;
 }
 
 .entry-meta {

+ 5 - 6
ui/static/js.go

@@ -60,21 +60,20 @@ function showKeyboardShortcuts(){let template=document.getElementById("keyboard-
 function markPageAsRead(){let items=DomHelper.getVisibleElements(".items .item");let entryIDs=[];items.forEach((element)=>{element.classList.add("item-status-read");entryIDs.push(parseInt(element.dataset.id,10));});if(entryIDs.length>0){updateEntriesStatus(entryIDs,"read",()=>{let element=document.querySelector("a[data-action=markPageAsRead]");let showOnlyUnread=false;if(element){showOnlyUnread=element.dataset.showOnlyUnread||false;}
 if(showOnlyUnread){window.location.reload();}else{goToPage("next",true);}});}}
 function handleEntryStatus(element){let toasting=!element;let currentEntry=findEntry(element);if(currentEntry){toggleEntryStatus(currentEntry,toasting);if(isListView()&&currentEntry.classList.contains('current-item')){goToNextListItem();}}}
-function toggleEntryStatus(element,toasting){let entryID=parseInt(element.dataset.id,10);let link=element.querySelector("a[data-toggle-status]");let currentStatus=link.dataset.value;let newStatus=currentStatus==="read"?"unread":"read";updateEntriesStatus([entryID],newStatus);if(currentStatus==="read"){link.innerHTML=link.dataset.labelRead;link.dataset.value="unread";if(toasting){toast(link.dataset.toastUnread);}}else{link.innerHTML=link.dataset.labelUnread;link.dataset.value="read";if(toasting){toast(link.dataset.toastRead);}}
+function toggleEntryStatus(element,toasting){let entryID=parseInt(element.dataset.id,10);let link=element.querySelector("a[data-toggle-status]");let currentStatus=link.dataset.value;let newStatus=currentStatus==="read"?"unread":"read";updateEntriesStatus([entryID],newStatus);if(currentStatus==="read"){link.innerHTML='<span class="icon-label">'+link.dataset.labelRead+'</span>';link.dataset.value="unread";if(toasting){toast(link.dataset.toastUnread);}}else{link.innerHTML='<span class="icon-label">'+link.dataset.labelUnread+'</span>';link.dataset.value="read";if(toasting){toast(link.dataset.toastRead);}}
 if(element.classList.contains("item-status-"+currentStatus)){element.classList.remove("item-status-"+currentStatus);element.classList.add("item-status-"+newStatus);}}
 function markEntryAsRead(element){if(element.classList.contains("item-status-unread")){element.classList.remove("item-status-unread");element.classList.add("item-status-read");let entryID=parseInt(element.dataset.id,10);updateEntriesStatus([entryID],"read");}}
 function updateEntriesStatus(entryIDs,status,callback){let url=document.body.dataset.entriesStatusUrl;let request=new RequestBuilder(url);request.withBody({entry_ids:entryIDs,status:status});request.withCallback(callback);request.execute();if(status==="read"){decrementUnreadCounter(1);}else{incrementUnreadCounter(1);}}
 function handleSaveEntry(element){let toasting=!element;let currentEntry=findEntry(element);if(currentEntry){saveEntry(currentEntry.querySelector("a[data-save-entry]"),toasting);}}
 function saveEntry(element,toasting){if(!element){return;}
 if(element.dataset.completed){return;}
-element.innerHTML=element.dataset.labelLoading;let request=new RequestBuilder(element.dataset.saveUrl);request.withCallback(()=>{element.innerHTML=element.dataset.labelDone;element.dataset.completed=true;if(toasting){toast(element.dataset.toastDone);}});request.execute();}
+let previousInnerHTML=element.innerHTML;element.innerHTML='<span class="icon-label">'+element.dataset.labelLoading+'</span>';let request=new RequestBuilder(element.dataset.saveUrl);request.withCallback(()=>{element.innerHTML=previousInnerHTML;element.dataset.completed=true;if(toasting){toast(element.dataset.toastDone);}});request.execute();}
 function handleBookmark(element){let toasting=!element;let currentEntry=findEntry(element);if(currentEntry){toggleBookmark(currentEntry,toasting);}}
 function toggleBookmark(parentElement,toasting){let element=parentElement.querySelector("a[data-toggle-bookmark]");if(!element){return;}
-element.innerHTML=element.dataset.labelLoading;let request=new RequestBuilder(element.dataset.bookmarkUrl);request.withCallback(()=>{if(element.dataset.value==="star"){element.innerHTML=element.dataset.labelStar;element.dataset.value="unstar";if(toasting){toast(element.dataset.toastUnstar);}}else{element.innerHTML=element.dataset.labelUnstar;element.dataset.value="star";if(toasting){toast(element.dataset.toastStar);}}});request.execute();}
+element.innerHTML='<span class="icon-label">'+element.dataset.labelLoading+'</span>';let request=new RequestBuilder(element.dataset.bookmarkUrl);request.withCallback(()=>{if(element.dataset.value==="star"){element.innerHTML='<span class="icon-label">'+element.dataset.labelStar+'</span>';element.dataset.value="unstar";if(toasting){toast(element.dataset.toastUnstar);}}else{element.innerHTML='<span class="icon-label">'+element.dataset.labelUnstar+'</span>';element.dataset.value="star";if(toasting){toast(element.dataset.toastStar);}}});request.execute();}
 function handleFetchOriginalContent(){if(isListView()){return;}
 let element=document.querySelector("a[data-fetch-content-entry]");if(!element){return;}
-if(element.dataset.completed){return;}
-element.innerHTML=element.dataset.labelLoading;let request=new RequestBuilder(element.dataset.fetchContentUrl);request.withCallback((response)=>{element.innerHTML=element.dataset.labelDone;element.dataset.completed=true;response.json().then((data)=>{if(data.hasOwnProperty("content")){document.querySelector(".entry-content").innerHTML=data.content;}});});request.execute();}
+let previousInnerHTML=element.innerHTML;element.innerHTML='<span class="icon-label">'+element.dataset.labelLoading+'</span>';let request=new RequestBuilder(element.dataset.fetchContentUrl);request.withCallback((response)=>{element.innerHTML=previousInnerHTML;response.json().then((data)=>{if(data.hasOwnProperty("content")){document.querySelector(".entry-content").innerHTML=data.content;}});});request.execute();}
 function openOriginalLink(openLinkInCurrentTab){let entryLink=document.querySelector(".entry h1 a");if(entryLink!==null){if(openLinkInCurrentTab){window.location.href=entryLink.getAttribute("href");}else{DomHelper.openNewTab(entryLink.getAttribute("href"));}
 return;}
 let currentItemOriginalLink=document.querySelector(".current-item a[data-original-link]");if(currentItemOriginalLink!==null){DomHelper.openNewTab(currentItemOriginalLink.getAttribute("href"));let currentItem=document.querySelector(".current-item");if(document.location.href!=document.querySelector('a[data-page=starred]').href){goToNextListItem();}
@@ -111,6 +110,6 @@ window.addEventListener('beforeinstallprompt',(e)=>{e.preventDefault();let defer
 }
 
 var JavascriptsChecksums = map[string]string{
-	"app": "f26277a4397cc129a40190d5b7f008611a4cbe052e3fad71b7a4f5de473a1bf9",
+	"app": "e7f953dd231bd59b239ba4c801366d1bc5d59233f085e4b0801e27c94e416416",
 	"sw":  "55fffa223919cc18572788fb9c62fccf92166c0eb5d3a1d6f91c31f24d020be9",
 }

+ 11 - 14
ui/static/js/app.js

@@ -137,13 +137,13 @@ function toggleEntryStatus(element, toasting) {
     updateEntriesStatus([entryID], newStatus);
 
     if (currentStatus === "read") {
-        link.innerHTML = link.dataset.labelRead;
+        link.innerHTML = '<span class="icon-label">' + link.dataset.labelRead + '</span>';
         link.dataset.value = "unread";
         if (toasting) {
             toast(link.dataset.toastUnread);
         }
     } else {
-        link.innerHTML = link.dataset.labelUnread;
+        link.innerHTML = '<span class="icon-label">' + link.dataset.labelUnread + '</span>';
         link.dataset.value = "read";
         if (toasting) {
             toast(link.dataset.toastRead);
@@ -201,11 +201,12 @@ function saveEntry(element, toasting) {
         return;
     }
 
-    element.innerHTML = element.dataset.labelLoading;
+    let previousInnerHTML = element.innerHTML;
+    element.innerHTML = '<span class="icon-label">' + element.dataset.labelLoading + '</span>';
 
     let request = new RequestBuilder(element.dataset.saveUrl);
     request.withCallback(() => {
-        element.innerHTML = element.dataset.labelDone;
+        element.innerHTML = previousInnerHTML;
         element.dataset.completed = true;
         if (toasting) {
             toast(element.dataset.toastDone);
@@ -230,18 +231,18 @@ function toggleBookmark(parentElement, toasting) {
         return;
     }
 
-    element.innerHTML = element.dataset.labelLoading;
+    element.innerHTML = '<span class="icon-label">' + element.dataset.labelLoading + '</span>';
 
     let request = new RequestBuilder(element.dataset.bookmarkUrl);
     request.withCallback(() => {
         if (element.dataset.value === "star") {
-            element.innerHTML = element.dataset.labelStar;
+            element.innerHTML = '<span class="icon-label">' + element.dataset.labelStar + '</span>';
             element.dataset.value = "unstar";
             if (toasting) {
                 toast(element.dataset.toastUnstar);
             }
         } else {
-            element.innerHTML = element.dataset.labelUnstar;
+            element.innerHTML = '<span class="icon-label">' + element.dataset.labelUnstar + '</span>';
             element.dataset.value = "star";
             if (toasting) {
                 toast(element.dataset.toastStar);
@@ -262,16 +263,12 @@ function handleFetchOriginalContent() {
         return;
     }
 
-    if (element.dataset.completed) {
-        return;
-    }
-
-    element.innerHTML = element.dataset.labelLoading;
+    let previousInnerHTML = element.innerHTML;
+    element.innerHTML = '<span class="icon-label">' + element.dataset.labelLoading + '</span>';
 
     let request = new RequestBuilder(element.dataset.fetchContentUrl);
     request.withCallback((response) => {
-        element.innerHTML = element.dataset.labelDone;
-        element.dataset.completed = true;
+        element.innerHTML = previousInnerHTML;
 
         response.json().then((data) => {
             if (data.hasOwnProperty("content")) {

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů