diff options
-rw-r--r-- | .eslintrc.js | 44 | ||||
-rw-r--r-- | babel.config.js | 8 | ||||
-rw-r--r-- | lib/Explore/feeds/feeds.en.json | 199 | ||||
-rw-r--r-- | src/App.vue | 28 | ||||
-rw-r--r-- | src/components/AddFeed.vue | 259 | ||||
-rw-r--r-- | src/components/Explore.vue | 141 | ||||
-rw-r--r-- | src/components/Sidebar.vue | 324 | ||||
-rw-r--r-- | src/main.js | 176 | ||||
-rw-r--r-- | stylelint.config.js | 2 | ||||
-rw-r--r-- | webpack.js | 26 |
10 files changed, 615 insertions, 592 deletions
diff --git a/.eslintrc.js b/.eslintrc.js index 1e9e7379f..3290cc73f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,26 +1,22 @@ module.exports = { - root: true, - parser: 'vue-eslint-parser', - parserOptions: { - parser: { - ts: '@typescript-eslint/parser', - }, - ecmaVersion: 2020, - }, - extends: [ - 'eslint:recommended', - 'plugin:vue/base', - 'plugin:vue/essential', - '@vue/standard', - '@vue/typescript/recommended', - '@nextcloud', - ], - ignorePatterns: ['*.d.ts'], - rules: { - 'node/no-unpublished-import': 'off', // necessary for vue-property-decorator (not published?) - - // TODO: remove these indentation rules during reformat (expects tab char \t but right now code base uses spaces) - 'vue/html-indent': 'off', - indent: ['error', 4], - }, + root: true, + parser: 'vue-eslint-parser', + parserOptions: { + parser: { + ts: '@typescript-eslint/parser', + }, + ecmaVersion: 2020, + }, + extends: [ + 'eslint:recommended', + 'plugin:vue/base', + 'plugin:vue/essential', + '@vue/standard', + '@vue/typescript/recommended', + '@nextcloud', + ], + ignorePatterns: ['*.d.ts'], + rules: { + 'node/no-unpublished-import': 'off', // necessary for vue-property-decorator (not published?) + }, } diff --git a/babel.config.js b/babel.config.js index ec45a210c..a179fa443 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,6 +1,6 @@ module.exports = { - plugins: [ - '@babel/plugin-syntax-dynamic-import', - ], - presets: ['@babel/preset-env'], + plugins: [ + '@babel/plugin-syntax-dynamic-import', + ], + presets: ['@babel/preset-env'], } diff --git a/lib/Explore/feeds/feeds.en.json b/lib/Explore/feeds/feeds.en.json index d855b243c..e6a59c86f 100644 --- a/lib/Explore/feeds/feeds.en.json +++ b/lib/Explore/feeds/feeds.en.json @@ -1,98 +1,105 @@ { - "Nextcloud": [{ - "title": "Nextcloud News", - "favicon": "https://nextcloud.com/wp-content/themes/next/assets/img/common/favicon-touch.png", - "url": "https://nextcloud.com/news/", - "feed": "https://nextcloud.com/blog/feed", - "description": "See what is going on in and around Nextcloud", - "votes": 1000 - }, - { - "title": "Nextcloud Podcast", - "favicon": "https://nextcloud.com/wp-content/themes/next/assets/img/common/favicon-touch.png", - "url": "https://nextcloud.com/podcast/", - "feed": "https://nextcloud.com/podcast-feed.rss", - "description": "Digital Sovereignty, self hosting, privacy and more", - "votes": 1000 - }], - "News": [{ - "title": "World Health Organization", - "favicon": "https://www.who.int/favicon.ico", - "url": "https://www.who.int/", - "feed": "https://www.who.int/rss-feeds/news-english.xml", - "description": "All news releases, notes for the media, statements issued by WHO", - "votes": 500 - }, - { - "title": "Wikinews", - "favicon": "https://en.wikinews.org/static/apple-touch/wikinews.png", - "url": "https://en.wikinews.org/", - "feed": "https://en.wikinews.org/w/index.php?title=Special:NewsFeed&feed=atom&categories=Published¬categories=No%20publish%7CArchived%7CAutoArchived%7Cdisputed&namespace=0&count=30&hourcount=124&ordermethod=categoryadd&stablepages=only", - "description": "Collaborative journalism news site by the Wikimedia Foundation", - "votes": 100 - }, - { - "title": "Privacy International", - "favicon": "https://privacyinternational.org/sites/default/files/fav/apple-icon-60x60.png", - "url": "https://privacyinternational.org/", - "feed": "https://privacyinternational.org/rss.xml", - "description": "News on the right to privacy", - "votes": 100 - }], - "Open knowledge": [{ - "title": "Wikipedia picture of the day", - "favicon": "https://www.wikipedia.org/static/apple-touch/wikipedia.png", - "url": "https://en.wikipedia.org/wiki/Wikipedia:Featured_pictures", - "feed": "https://en.wikipedia.org/w/api.php?action=featuredfeed&feed=potd&feedformat=atom", - "description": "Some of the finest images on Wikipedia", - "votes": 100 - }, - { - "title": "Wikipedia article of the day", - "favicon": "https://www.wikipedia.org/static/apple-touch/wikipedia.png", - "url": "https://en.wikipedia.org/", - "feed": "https://en.wikipedia.org/w/api.php?action=featuredfeed&feed=featured&feedformat=atom", - "description": "The best articles Wikipedia has to offer", - "votes": 100 - }, - { - "title": "Project Gutenberg", - "favicon": "https://www.gutenberg.org/gutenberg/favicon.ico", - "url": "https://gutenberg.org/", - "feed": "http://www.gutenberg.org/cache/epub/feeds/today.rss", - "description": "A library of over 60,000 free eBooks", - "votes": 100 - }, - { - "title": "LibriVox", - "favicon": "https://librivox.org/wp-content/themes/librivox/favicon.ico", - "url": "https://librivox.org/", - "feed": "https://librivox.org/rss/latest_releases", - "description": "Free public domain audiobooks", - "votes": 100 - }, - { - "title": "Public Domain Review", - "favicon": "https://publicdomainreview.org/favicon-96x96.png", - "url": "https://publicdomainreview.org/", - "feed": "https://publicdomainreview.org/rss.xml", - "description": "Curious and compelling works from the history of art, literature, and ideas", - "votes": 100 - }, - { - "title": "Public Library of Science", - "favicon": "https://plos.org/wp-content/themes/plos/favicon/apple-touch-icon.png", - "url": "https://plos.org/", - "feed": "https://journals.plos.org/plosone/feed/atom", - "description": "Primary research from any discipline within science and medicine", - "votes": 100 - }, - { - "title": "ccMixter", - "favicon": "http://ccmixter.org/mixter-files/images/mixter-default.gif", - "url": "http://ccmixter.org/", - "feed": "http://ccmixter.org/api/query?f=rss&tags=editorial_pick&sort=date&dir=DESC&limit=22", - "description": "Editor’s picks from the global music community", - "votes": 100 - }] + "Nextcloud": [ + { + "title": "Nextcloud News", + "favicon": "https://nextcloud.com/wp-content/themes/next/assets/img/common/favicon-touch.png", + "url": "https://nextcloud.com/news/", + "feed": "https://nextcloud.com/blog/feed", + "description": "See what is going on in and around Nextcloud", + "votes": 1000 + }, + { + "title": "Nextcloud Podcast", + "favicon": "https://nextcloud.com/wp-content/themes/next/assets/img/common/favicon-touch.png", + "url": "https://nextcloud.com/podcast/", + "feed": "https://nextcloud.com/podcast-feed.rss", + "description": "Digital Sovereignty, self hosting, privacy and more", + "votes": 1000 + } + ], + "News": [{ + + "title": "World Health Organization", + "favicon": "https://www.who.int/favicon.ico", + "url": "https://www.who.int/", + "feed": "https://www.who.int/rss-feeds/news-english.xml", + "description": "All news releases, notes for the media, statements issued by WHO", + "votes": 500 + }, + { + "title": "Wikinews", + "favicon": "https://en.wikinews.org/static/apple-touch/wikinews.png", + "url": "https://en.wikinews.org/", + "feed": "https://en.wikinews.org/w/index.php?title=Special:NewsFeed&feed=atom&categories=Published¬categories=No%20publish%7CArchived%7CAutoArchived%7Cdisputed&namespace=0&count=30&hourcount=124&ordermethod=categoryadd&stablepages=only", + "description": "Collaborative journalism news site by the Wikimedia Foundation", + "votes": 100 + }, + { + "title": "Privacy International", + "favicon": "https://privacyinternational.org/sites/default/files/fav/apple-icon-60x60.png", + "url": "https://privacyinternational.org/", + "feed": "https://privacyinternational.org/rss.xml", + "description": "News on the right to privacy", + "votes": 100 + } + ], + "Open knowledge": [ + { + "title": "Wikipedia picture of the day", + "favicon": "https://www.wikipedia.org/static/apple-touch/wikipedia.png", + "url": "https://en.wikipedia.org/wiki/Wikipedia:Featured_pictures", + "feed": "https://en.wikipedia.org/w/api.php?action=featuredfeed&feed=potd&feedformat=atom", + "description": "Some of the finest images on Wikipedia", + "votes": 100 + }, + { + "title": "Wikipedia article of the day", + "favicon": "https://www.wikipedia.org/static/apple-touch/wikipedia.png", + "url": "https://en.wikipedia.org/", + "feed": "https://en.wikipedia.org/w/api.php?action=featuredfeed&feed=featured&feedformat=atom", + "description": "The best articles Wikipedia has to offer", + "votes": 100 + }, + { + "title": "Project Gutenberg", + "favicon": "https://www.gutenberg.org/gutenberg/favicon.ico", + "url": "https://gutenberg.org/", + "feed": "http://www.gutenberg.org/cache/epub/feeds/today.rss", + "description": "A library of over 60,000 free eBooks", + "votes": 100 + }, + { + "title": "LibriVox", + "favicon": "https://librivox.org/wp-content/themes/librivox/favicon.ico", + "url": "https://librivox.org/", + "feed": "https://librivox.org/rss/latest_releases", + "description": "Free public domain audiobooks", + "votes": 100 + }, + { + "title": "Public Domain Review", + "favicon": "https://publicdomainreview.org/favicon-96x96.png", + "url": "https://publicdomainreview.org/", + "feed": "https://publicdomainreview.org/rss.xml", + "description": "Curious and compelling works from the history of art, literature, and ideas", + "votes": 100 + }, + { + "title": "Public Library of Science", + "favicon": "https://plos.org/wp-content/themes/plos/favicon/apple-touch-icon.png", + "url": "https://plos.org/", + "feed": "https://journals.plos.org/plosone/feed/atom", + "description": "Primary research from any discipline within science and medicine", + "votes": 100 + }, + { + "title": "ccMixter", + "favicon": "http://ccmixter.org/mixter-files/images/mixter-default.gif", + "url": "http://ccmixter.org/", + "feed": "http://ccmixter.org/api/query?f=rss&tags=editorial_pick&sort=date&dir=DESC&limit=22", + "description": "Editor’s picks from the global music community", + "votes": 100 + } + ] } +
\ No newline at end of file diff --git a/src/App.vue b/src/App.vue index a5b4034ad..ad80f18d5 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,10 +1,10 @@ <template> - <Content app-name="news"> - <Sidebar /> - <AppContent> - <router-view /> - </AppContent> - </Content> + <Content app-name="news"> + <Sidebar /> + <AppContent> + <router-view /> + </AppContent> + </Content> </template> <script> @@ -13,13 +13,13 @@ import AppContent from '@nextcloud/vue/dist/Components/AppContent' import Sidebar from './components/Sidebar.vue' export default { - components: { - Content, - Sidebar, - AppContent, - }, - created() { - this.$store.dispatch('loadFolder') - }, + components: { + Content, + Sidebar, + AppContent, + }, + created() { + this.$store.dispatch('loadFolder') + }, } </script> diff --git a/src/components/AddFeed.vue b/src/components/AddFeed.vue index a07125d3a..9eded0159 100644 --- a/src/components/AddFeed.vue +++ b/src/components/AddFeed.vue @@ -1,45 +1,45 @@ <template> - <Modal @close="$emit('close')"> - <div id="new-feed" news-add-feed="Navigation.feed"> - <form ng-submit="Navigation.createFeed(Navigation.feed)" - ng-init="Navigation.feed.autoDiscover=true" - name="feedform"> - <fieldset ng-disabled="Navigation.addingFeed" style="padding: 16px"> - <input type="text" - :value="feed" - ng-model="Navigation.feed.url" - ng-class="{'ng-invalid': + <Modal @close="$emit('close')"> + <div id="new-feed" news-add-feed="Navigation.feed"> + <form ng-submit="Navigation.createFeed(Navigation.feed)" + ng-init="Navigation.feed.autoDiscover=true" + name="feedform"> + <fieldset ng-disabled="Navigation.addingFeed" style="padding: 16px"> + <input type="text" + :value="feed" + ng-model="Navigation.feed.url" + ng-class="{'ng-invalid': !Navigation.addingFeed && Navigation.feedUrlExists(Navigation.feed.url) }" - :placeholder="t('news', 'Web address')" - name="address" - pattern="[^\s]+" - required - autofocus /> - - <p class="error" - ng-show="!Navigation.addingFeed && + :placeholder="t('news', 'Web address')" + name="address" + pattern="[^\s]+" + required + autofocus> + + <p class="error" + ng-show="!Navigation.addingFeed && Navigation.feedUrlExists(Navigation.feed.url)"> - {{ t("news", "Feed exists already!") }} - </p> - - <!-- select a folder --> - <CheckboxRadioSwitch :checked.sync="createNewFolder" type="switch"> - {{ t("news", "New folder") }}? - </CheckboxRadioSwitch> - - <Multiselect v-if="!createNewFolder" - v-model="folder" - :options="folders" - track-by="id" - label="name" /> - - <!-- add a folder --> - <input v-if="createNewFolder" - type="text" - ng-model="Navigation.feed.newFolder" - ng-class="{'ng-invalid': + {{ t("news", "Feed exists already!") }} + </p> + + <!-- select a folder --> + <CheckboxRadioSwitch :checked.sync="createNewFolder" type="switch"> + {{ t("news", "New folder") }}? + </CheckboxRadioSwitch> + + <Multiselect v-if="!createNewFolder" + v-model="folder" + :options="folders" + track-by="id" + label="name" /> + + <!-- add a folder --> + <input v-if="createNewFolder" + type="text" + ng-model="Navigation.feed.newFolder" + ng-class="{'ng-invalid': !Navigation.addingFeed && !Navigation.addingFeed && Navigation.showNewFolder && @@ -47,64 +47,64 @@ Navigation.feed.newFolder ) }" - :placeholder="t('news', 'Folder name')" - name="folderName" - style="width: 90%" - required /> + :placeholder="t('news', 'Folder name')" + name="folderName" + style="width: 90%" + required> - <p class="error" - ng-show="!Navigation.addingFeed && + <p class="error" + ng-show="!Navigation.addingFeed && Navigation.folderNameExists(Navigation.feed.newFolder)"> - {{ t("news", "Folder exists already!") }} - </p> - - <!-- basic auth --> - - <CheckboxRadioSwitch :checked.sync="withBasicAuth" type="switch"> - {{ t("news", "Credentials") }}? - </CheckboxRadioSwitch> - - <div v-if="withBasicAuth" class="add-feed-basicauth"> - <p class="warning"> - {{ - t( - "news", - "HTTP Basic Auth credentials must be stored unencrypted! Everyone with access to the server or database will be able to access them!" - ) - }}> - </p> - <input type="text" - ng-model="Navigation.feed.user" - :placeholder="t('news', 'Username')" - name="user" - autofocus /> - - <input type="password" - ng-model="Navigation.feed.password" - :placeholder="t('news', 'Password')" - name="password" - autocomplete="new-password" /> - </div> - - <CheckboxRadioSwitch :checked.sync="autoDiscover" type="switch"> - {{ t("news", "Auto discover Feed") }}? - </CheckboxRadioSwitch> - - <Button :wide="true" - type="primary" - ng-disabled=" + {{ t("news", "Folder exists already!") }} + </p> + + <!-- basic auth --> + + <CheckboxRadioSwitch :checked.sync="withBasicAuth" type="switch"> + {{ t("news", "Credentials") }}? + </CheckboxRadioSwitch> + + <div v-if="withBasicAuth" class="add-feed-basicauth"> + <p class="warning"> + {{ + t( + "news", + "HTTP Basic Auth credentials must be stored unencrypted! Everyone with access to the server or database will be able to access them!" + ) + }}> + </p> + <input type="text" + ng-model="Navigation.feed.user" + :placeholder="t('news', 'Username')" + name="user" + autofocus> + + <input type="password" + ng-model="Navigation.feed.password" + :placeholder="t('news', 'Password')" + name="password" + autocomplete="new-password"> + </div> + + <CheckboxRadioSwitch :checked.sync="autoDiscover" type="switch"> + {{ t("news", "Auto discover Feed") }}? + </CheckboxRadioSwitch> + + <Button :wide="true" + type="primary" + ng-disabled=" Navigation.feedUrlExists(Navigation.feed.url) || ( Navigation.showNewFolder && Navigation.folderNameExists(folder.name) )" - @click="addFeed()"> - {{ t("news", "Subscribe") }} - </Button> - </fieldset> - </form> - </div> - </Modal> + @click="addFeed()"> + {{ t("news", "Subscribe") }} + </Button> + </fieldset> + </form> + </div> + </Modal> </template> <script> @@ -116,46 +116,49 @@ import Button from '@nextcloud/vue/dist/Components/Button' import Multiselect from '@nextcloud/vue/dist/Components/Multiselect' export default { - components: { - Modal, - CheckboxRadioSwitch, - Button, - Multiselect, - }, - props: { - feed: '', - }, - emits: ['close'], - data() { - return { - folder: {}, - autoDiscover: true, - createNewFolder: false, - withBasicAuth: false, - } - }, - computed: { - folders() { - return this.$store.state.folders - }, - }, - methods: { - newFolder() { - this.createNewFolder = true - }, - abortNewFolder() { - this.createNewFolder = false - }, - addFeed() { - this.$store.dispatch('addFeed', { - feedReq: { - url: this.feed, - folder: this.folder, - autoDiscover: true, - }, - }) - }, - }, + components: { + Modal, + CheckboxRadioSwitch, + Button, + Multiselect, + }, + props: { + feed: { + type: String, + default: '', + }, + }, + emits: ['close'], + data() { + return { + folder: {}, + autoDiscover: true, + createNewFolder: false, + withBasicAuth: false, + } + }, + computed: { + folders() { + return this.$store.state.folders + }, + }, + methods: { + newFolder() { + this.createNewFolder = true + }, + abortNewFolder() { + this.createNewFolder = false + }, + addFeed() { + this.$store.dispatch('addFeed', { + feedReq: { + url: this.feed, + folder: this.folder, + autoDiscover: true, + }, + }) + }, + }, } </script> diff --git a/src/components/Explore.vue b/src/components/Explore.vue index 11c370ce8..96e90fad1 100644 --- a/src/components/Explore.vue +++ b/src/components/Explore.vue @@ -1,33 +1,33 @@ <template> - <div id="explore"> - <AddFeed v-if="showAddFeed" :feed="feed" @close="closeShowAddFeed()" /> - <div class="grid-container"> - <div v-for="entry in exploreSites" - :key="entry.title" - class="explore-feed grid-item"> - <h2 v-if="entry.favicon" - class="explore-title" - :style="{ backgroundImage: 'url(' + entry.favicon + ')' }"> - <a target="_blank" rel="noreferrer" :href="entry.url"> - {{ entry.title }} - </a> - </h2> - <h2 v-if="!entry.favicon" class="icon-rss explore-title"> - {{ entry.title }} - </h2> - <div class="explore-content"> - <p>{{ entry.description }}</p> + <div id="explore"> + <AddFeed v-if="showAddFeed" :feed="feed" @close="closeShowAddFeed()" /> + <div class="grid-container"> + <div v-for="entry in exploreSites" + :key="entry.title" + class="explore-feed grid-item"> + <h2 v-if="entry.favicon" + class="explore-title" + :style="{ backgroundImage: 'url(' + entry.favicon + ')' }"> + <a target="_blank" rel="noreferrer" :href="entry.url"> + {{ entry.title }} + </a> + </h2> + <h2 v-if="!entry.favicon" class="icon-rss explore-title"> + {{ entry.title }} + </h2> + <div class="explore-content"> + <p>{{ entry.description }}</p> - <div class="explore-logo"> - <img :src="entry.image"> - </div> - </div> - <Button @click="subscribe(entry.feed)"> - {{ t("news", "Subscribe to") }} {{ entry.title }} - </Button> - </div> - </div> - </div> + <div class="explore-logo"> + <img :src="entry.image"> + </div> + </div> + <Button @click="subscribe(entry.feed)"> + {{ t("news", "Subscribe to") }} {{ entry.title }} + </Button> + </div> + </div> + </div> </template> <script lang="ts"> @@ -37,47 +37,60 @@ import axios from '@nextcloud/axios' import AddFeed from './AddFeed.vue' import { generateUrl } from '@nextcloud/router' +type ExploreSite = { + title: string; + favicon: string; + url: string; + feed: string; + description: string; + votes: number; +} + +type Feed = { + url?: string; +}; + const ExploreComponent = Vue.extend({ - components: { - Button, - AddFeed, - }, - data: () => { - const exploreSites: any[] = [] - const feed: any = {} - const showAddFeed = false + components: { + Button, + AddFeed, + }, + data: () => { + const exploreSites: ExploreSite[] = [] + const feed: Feed = {} + const showAddFeed = false - return { - exploreSites, - feed, - showAddFeed, - } - }, - created() { - this.sites() - }, + return { + exploreSites, + feed, + showAddFeed, + } + }, + created() { + this.sites() + }, - methods: { - async sites() { - const settings = await axios.get(generateUrl('/apps/news/settings')) + methods: { + async sites() { + const settings = await axios.get(generateUrl('/apps/news/settings')) - const exploreUrl = settings.data.settings.exploreUrl + 'feeds.en.json' - const explore = await axios.get(exploreUrl) + const exploreUrl = settings.data.settings.exploreUrl + 'feeds.en.json' + const explore = await axios.get(exploreUrl) - Object.keys(explore.data).forEach((key) => - explore.data[key].forEach((value: any) => - this.exploreSites.push(value), - ), - ) - }, - async subscribe(feed: any) { - this.feed = feed - this.showAddFeed = true - }, - closeShowAddFeed() { - this.showAddFeed = false - }, - }, + Object.keys(explore.data).forEach((key) => + explore.data[key].forEach((value: ExploreSite) => + this.exploreSites.push(value), + ), + ) + }, + async subscribe(feed: Feed) { + this.feed = feed + this.showAddFeed = true + }, + closeShowAddFeed() { + this.showAddFeed = false + }, + }, }) export default ExploreComponent diff --git a/src/components/Sidebar.vue b/src/components/Sidebar.vue index c0a141230..a0722fe0a 100644 --- a/src/components/Sidebar.vue +++ b/src/components/Sidebar.vue @@ -1,127 +1,127 @@ <template> - <AppNavigation> - <AddFeed v-if="showAddFeed" @close="closeShowAddFeed()" /> - <AppNavigationNew :text="t('news', 'Subscribe')" - button-id="new-feed-button" - button-class="icon-add" - @click="showShowAddFeed()" /> + <AppNavigation> + <AddFeed v-if="showAddFeed" @close="closeShowAddFeed()" /> + <AppNavigationNew :text="t('news', 'Subscribe')" + button-id="new-feed-button" + button-class="icon-add" + @click="showShowAddFeed()" /> - <ul id="locations" class="with-icon"> - <AppNavigationNewItem :title="t('news', 'New folder')" - icon="icon-add-folder" - @new-item="newFolder" /> + <ul id="locations" class="with-icon"> + <AppNavigationNewItem :title="t('news', 'New folder')" + icon="icon-add-folder" + @new-item="newFolder" /> - <AppNavigationItem :title="t('news', 'Unread articles')" icon="icon-rss"> - <template #actions> - <ActionButton icon="icon-checkmark" @click="alert('Edit')"> - t('news','Mark read') - </ActionButton> - </template> - <template #counter> - <CounterBubble>5</CounterBubble> - </template> - </AppNavigationItem> - <AppNavigationItem :title="t('news', 'All articles')" icon="icon-rss"> - <template #actions> - <ActionButton icon="icon-checkmark" @click="alert('Edit')"> - t('news','Mark read') - </ActionButton> - </template> - </AppNavigationItem> - <AppNavigationItem :title="t('news', 'Starred')" icon="icon-starred"> - <template #counter> - <CounterBubble>35</CounterBubble> - </template> - </AppNavigationItem> + <AppNavigationItem :title="t('news', 'Unread articles')" icon="icon-rss"> + <template #actions> + <ActionButton icon="icon-checkmark" @click="alert('Edit')"> + t('news','Mark read') + </ActionButton> + </template> + <template #counter> + <CounterBubble>5</CounterBubble> + </template> + </AppNavigationItem> + <AppNavigationItem :title="t('news', 'All articles')" icon="icon-rss"> + <template #actions> + <ActionButton icon="icon-checkmark" @click="alert('Edit')"> + t('news','Mark read') + </ActionButton> + </template> + </AppNavigationItem> + <AppNavigationItem :title="t('news', 'Starred')" icon="icon-starred"> + <template #counter> + <CounterBubble>35</CounterBubble> + </template> + </AppNavigationItem> - <AppNavigationItem v-for="folder in folders" - :key="folder.name" - :title="folder.name" - icon="icon-folder" - :allow-collapse="true"> - <template #default> - <AppNavigationItem v-for="feed in folder.feeds" - :key="feed.name" - :title="feed.title"> - <template #icon> - <img v-if="feed.faviconLink" - :src="feed.faviconLink" - alt="feedIcon"> - <div v-if="!feed.faviconLink" class="icon-rss" /> - </template> - <template #actions> - <ActionButton icon="icon-checkmark" @click="alert('Mark read')"> - {{ t("news", "Mark read") }} - </ActionButton> - <ActionButton icon="icon-pinned" @click="alert('Rename')"> - {{ t("news", "Unpin from top") }} - </ActionButton> - <ActionButton icon="icon-caret-dark" - @click="deleteFolder(folder)"> - {{ t("news", "Newest first") }} - </ActionButton> - <ActionButton icon="icon-caret-dark" - @click="deleteFolder(folder)"> - {{ t("news", "Oldest first") }} - </ActionButton> - <ActionButton icon="icon-caret-dark" - @click="deleteFolder(folder)"> - {{ t("news", "Default order") }} - </ActionButton> - <ActionButton icon="icon-full-text-disabled" - @click="deleteFolder(folder)"> - {{ t("news", "Enable full text") }} - </ActionButton> - <ActionButton icon="icon-full-text-enabled" - @click="deleteFolder(folder)"> - {{ t("news", "Disable full text") }} - </ActionButton> - <ActionButton icon="icon-updatemode-default" - @click="deleteFolder(folder)"> - {{ t("news", "Unread updated") }} - </ActionButton> - <ActionButton icon="icon-updatemode-unread" - @click="deleteFolder(folder)"> - {{ t("news", "Ignore updated") }} - </ActionButton> - <ActionButton icon="icon-icon-rss" @click="deleteFolder(folder)"> - {{ t("news", "Open feed URL") }} - </ActionButton> - <ActionButton icon="icon-icon-rename" - @click="deleteFolder(folder)"> - {{ t("news", "Rename") }} - </ActionButton> - <ActionButton icon="icon-delete" @click="deleteFolder(folder)"> - |