From ec7912b7c13835b2dbda0b353d448f12a017bb72 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 3 Oct 2025 18:26:58 +0200 Subject: [PATCH] feat: Allow to follow the feeds of the current page --- README.md | 1 + src/api.js | 14 ++- src/i18n.js | 16 +++ src/models/feed.js | 24 ++++ src/router.js | 2 + src/screens/FeedsScreen.vue | 191 ++++++++++++++++++++++++++++++++ src/screens/LinkScreen.vue | 4 +- src/screens/Screen.vue | 15 ++- src/stylesheets/application.css | 4 + 9 files changed, 265 insertions(+), 6 deletions(-) create mode 100644 src/models/feed.js create mode 100644 src/screens/FeedsScreen.vue diff --git a/README.md b/README.md index 320b35f..b61e91a 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ It is designed as a simple, yet complete tool for organising the links you gathe This repository contains the code of the browser extension. The extension is the perfect companion for the web application as it allows you to easily mark links as read, save them for later, or add them to collections, as well as add notes. +It is also able to let you follow Web feeds. For the code of the Web application, see [flusio/Flus](https://github.com/flusio/Flus). diff --git a/src/api.js b/src/api.js index 964f9a8..3c21718 100644 --- a/src/api.js +++ b/src/api.js @@ -27,9 +27,7 @@ function logout() { } function search(url) { - return http.post("/search", { url }).then((data) => { - return data.links[0]; - }); + return http.post("/search", { url }); } function markLinkAsRead(link) { @@ -44,6 +42,14 @@ function collections() { return http.get("/collections"); } +function follow(collection) { + return http.post(`/collections/${collection.id}/follow`); +} + +function unfollow(collection) { + return http.delete(`/collections/${collection.id}/follow`); +} + function addCollectionToLink(link, collection) { return http.put(`/links/${link.id}/collections/${collection.id}`); } @@ -66,6 +72,8 @@ export default { authenticate, logout, collections, + follow, + unfollow, addCollectionToLink, removeCollectionFromLink, search, diff --git a/src/i18n.js b/src/i18n.js index 81c06e0..22fa8e3 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -25,6 +25,13 @@ export const i18n = createI18n({ "errors.unknown": "An unknown error has occurred. Please close and reopen the extension. If it still doesn’t work, please contact the support.", "errors.url.url": "The URL of the current page is not supported by Flus.", + "feeds.count_detected": + "No feeds detected on this page. | 1 feed detected on this page. | {count} feeds detected on this page.", + "feeds.follow": "Follow", + "feeds.loading": "Loading the feeds…", + "feeds.open_in_flus": "Open in Flus", + "feeds.title": "List of Web feeds", + "feeds.unfollow": "Unfollow", "forms.error": "Error:", "link.count_collections": "No collections | 1 collection | {count} collections", "link.invalid_protocol": @@ -49,6 +56,7 @@ export const i18n = createI18n({ "login.title": "Login", "menu.back": "Back", "menu.close": "Close the menu", + "menu.feeds": "List of Web feeds", "menu.logout": "Log out", "menu.open": "Open the menu", "menu.open_flus": "Open Flus", @@ -90,6 +98,13 @@ export const i18n = createI18n({ "errors.unknown": "Une erreur inconnue est survenue. Veuillez fermer et réouvrir l’extension. Si cela ne suffit pas, veuillez contacter le support.", "errors.url.url": "L’URL de la page actuelle n’est pas supportée par Flus.", + "feeds.count_detected": + "Aucun flux détecté sur cette page. | 1 flux détecté sur cette page. | {count} flux détectés sur cette page.", + "feeds.follow": "Suivre", + "feeds.loading": "Chargement des flux…", + "feeds.open_in_flus": "Ouvrir dans Flus", + "feeds.title": "Liste des flux Web", + "feeds.unfollow": "Ne plus suivre", "forms.error": "Erreur :", "link.count_collections": "Aucune collection | 1 collection | {count} collections", "link.invalid_protocol": @@ -114,6 +129,7 @@ export const i18n = createI18n({ "login.title": "Connexion", "menu.back": "Retour", "menu.close": "Fermer le menu", + "menu.feeds": "Liste des flux Web", "menu.logout": "Se déconnecter", "menu.open": "Ouvrir le menu", "menu.open_flus": "Ouvrir Flus", diff --git a/src/models/feed.js b/src/models/feed.js new file mode 100644 index 0000000..5c782dc --- /dev/null +++ b/src/models/feed.js @@ -0,0 +1,24 @@ +// This file is part of Flus Browser +// SPDX-License-Identifier: AGPL-3.0-or-later + +export default class { + id = ""; + name = ""; + url = ""; + isFollowed = false; + + init(fetchedFeed) { + this.id = fetchedFeed.id; + this.name = fetchedFeed.name; + this.url = fetchedFeed.url; + this.isFollowed = fetchedFeed.is_followed; + } + + follow() { + this.isFollowed = true; + } + + unfollow() { + this.isFollowed = false; + } +} diff --git a/src/router.js b/src/router.js index 3b49a76..0340f26 100644 --- a/src/router.js +++ b/src/router.js @@ -5,11 +5,13 @@ import { ref, computed } from "vue"; import { store } from "./store.js"; +import FeedsScreen from "./screens/FeedsScreen.vue"; import LinkScreen from "./screens/LinkScreen.vue"; import SettingsScreen from "./screens/SettingsScreen.vue"; const routes = { "/": LinkScreen, + "/feeds": FeedsScreen, "/settings": SettingsScreen, }; diff --git a/src/screens/FeedsScreen.vue b/src/screens/FeedsScreen.vue new file mode 100644 index 0000000..0c0e2af --- /dev/null +++ b/src/screens/FeedsScreen.vue @@ -0,0 +1,191 @@ + + + + + diff --git a/src/screens/LinkScreen.vue b/src/screens/LinkScreen.vue index 5cde37a..467ce74 100644 --- a/src/screens/LinkScreen.vue +++ b/src/screens/LinkScreen.vue @@ -151,8 +151,8 @@ async function refreshForCurrentTab() { } api.search(url) - .then((fetchedLink) => { - link.init(fetchedLink); + .then((data) => { + link.init(data.links[0]); ready.value = true; }) .catch((error) => { diff --git a/src/screens/Screen.vue b/src/screens/Screen.vue index dad96b8..431ae8f 100644 --- a/src/screens/Screen.vue +++ b/src/screens/Screen.vue @@ -15,7 +15,20 @@ -
+
+ + + + + {{ t("menu.feeds") }} + + +