feeds-fun 0.6.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +25 -23
- package/postcss.config.js +6 -0
- package/public/news-filtering-example.png +0 -0
- package/src/components/ConfigFlag.vue +6 -14
- package/src/components/ConfigSelector.vue +3 -1
- package/src/components/DiscoveryForm.vue +9 -2
- package/src/components/EntriesList.vue +15 -4
- package/src/components/EntryForList.vue +76 -65
- package/src/components/FeedForList.vue +15 -32
- package/src/components/FeedInfo.vue +11 -4
- package/src/components/FeedsCollections.vue +23 -15
- package/src/components/FeedsList.vue +7 -18
- package/src/components/FfunTag.vue +6 -13
- package/src/components/NotificationCollections.vue +7 -0
- package/src/components/NotificationOpenaiApiKey.vue +28 -0
- package/src/components/Notifications.vue +32 -0
- package/src/components/OPMLUpload.vue +3 -0
- package/src/components/RuleConstructor.vue +16 -24
- package/src/components/RuleForList.vue +47 -0
- package/src/components/RulesList.vue +7 -43
- package/src/components/SimplePagination.vue +4 -6
- package/src/components/SupertokensLogin.vue +50 -25
- package/src/components/TagsFilter.vue +13 -25
- package/src/components/TagsList.vue +27 -25
- package/src/components/UserSetting.vue +41 -38
- package/src/components/UserSettingForNotification.vue +63 -0
- package/src/inputs/Marker.vue +3 -7
- package/src/inputs/ScoreSelector.vue +11 -12
- package/src/layouts/SidePanelLayout.vue +42 -96
- package/src/layouts/WideLayout.vue +2 -25
- package/src/logic/settings.ts +0 -9
- package/src/main.ts +12 -19
- package/src/stores/entries.ts +1 -6
- package/src/style.css +92 -0
- package/src/values/Score.vue +1 -10
- package/src/views/AuthView.vue +3 -7
- package/src/views/CollectionsView.vue +2 -0
- package/src/views/FeedsView.vue +8 -3
- package/src/views/MainView.vue +37 -83
- package/src/views/NewsView.vue +30 -13
- package/src/views/RulesView.vue +0 -2
- package/src/views/SettingsView.vue +35 -22
- package/tailwind.config.js +14 -0
- package/src/components/EntryInfo.vue +0 -23
- package/src/components/FfunGithubButtons.vue +0 -22
package/src/views/FeedsView.vue
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
<template #side-menu-item-1>
|
|
4
4
|
Show descriptions:
|
|
5
5
|
<config-flag
|
|
6
|
+
style="min-width: 2.5rem"
|
|
6
7
|
v-model:flag="globalSettings.showFeedsDescriptions"
|
|
7
8
|
on-text="yes"
|
|
8
9
|
off-text="no" />
|
|
@@ -19,6 +20,7 @@
|
|
|
19
20
|
Show failed
|
|
20
21
|
<config-flag
|
|
21
22
|
v-model:flag="globalSettings.failedFeedsFirst"
|
|
23
|
+
style="min-width: 2.5rem"
|
|
22
24
|
on-text="first"
|
|
23
25
|
off-text="last" />
|
|
24
26
|
</template>
|
|
@@ -28,11 +30,16 @@
|
|
|
28
30
|
<span v-if="sortedFeeds"> [{{ sortedFeeds.length }}] </span>
|
|
29
31
|
</template>
|
|
30
32
|
|
|
31
|
-
<
|
|
33
|
+
<notifications
|
|
34
|
+
v-if="sortedFeeds !== null"
|
|
35
|
+
:openai-api-key="false"
|
|
36
|
+
:collections="sortedFeeds === null || sortedFeeds.length == 0" />
|
|
32
37
|
|
|
33
38
|
<feeds-list
|
|
34
39
|
v-if="sortedFeeds"
|
|
35
40
|
:feeds="sortedFeeds" />
|
|
41
|
+
|
|
42
|
+
<template #main-footer> </template>
|
|
36
43
|
</side-panel-layout>
|
|
37
44
|
</template>
|
|
38
45
|
|
|
@@ -120,5 +127,3 @@
|
|
|
120
127
|
return sorted;
|
|
121
128
|
});
|
|
122
129
|
</script>
|
|
123
|
-
|
|
124
|
-
<style></style>
|
package/src/views/MainView.vue
CHANGED
|
@@ -1,96 +1,50 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<wide-layout>
|
|
3
|
-
<template #header>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
<template #header>
|
|
4
|
+
Feeds Fun
|
|
5
|
+
<small class="block text-lg font-normal">Personalized news for professionals</small>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<div class="max-w-md mx-auto">
|
|
9
|
+
<div class="ffun-info-good">
|
|
10
|
+
<supertokens-login />
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<h2>News reader with tags</h2>
|
|
14
|
+
|
|
15
|
+
<ul class="list-disc list-inside text-left">
|
|
16
|
+
<li>Reader automatically assigns tags to news.</li>
|
|
17
|
+
<li>You create rules to score news by tags.</li>
|
|
18
|
+
<li>Filter and sort news how you want ⇒ read only what you want.</li>
|
|
19
|
+
</ul>
|
|
20
|
+
|
|
21
|
+
<h2>You are in control</h2>
|
|
22
|
+
|
|
23
|
+
<ul class="list-disc list-inside text-left">
|
|
24
|
+
<li
|
|
25
|
+
><a
|
|
26
|
+
class="ffun-normal-link"
|
|
27
|
+
:href="settings.githubRepo"
|
|
28
|
+
target="_blank"
|
|
29
|
+
>Open source</a
|
|
30
|
+
>, self-hosted.</li
|
|
31
|
+
>
|
|
32
|
+
<li>No black box recommendation algorithms.</li>
|
|
33
|
+
<li>No "smart" reordering.</li>
|
|
34
|
+
<li>No ads.</li>
|
|
35
|
+
<li>No selling of your data.</li>
|
|
36
|
+
</ul>
|
|
37
|
+
|
|
38
|
+
<h2>How it looks like</h2>
|
|
12
39
|
</div>
|
|
13
40
|
|
|
14
|
-
<br />
|
|
15
|
-
|
|
16
|
-
<ffun-github-buttons :repository="settings.githubRepo" />
|
|
17
|
-
|
|
18
|
-
<h2>What is it?</h2>
|
|
19
|
-
|
|
20
|
-
<p>
|
|
21
|
-
<i>Web-based news reader. Self-hosted, if it is your way.</i>
|
|
22
|
-
</p>
|
|
23
|
-
|
|
24
|
-
<ul class="main-page-element">
|
|
25
|
-
<li>Reader automatically assigns tags to news entries.</li>
|
|
26
|
-
<li>You create rules to score news by tags.</li>
|
|
27
|
-
<li>Filter and sort news how you want, to read only what you want.</li>
|
|
28
|
-
<li>?????</li>
|
|
29
|
-
<li>Profit.</li>
|
|
30
|
-
</ul>
|
|
31
|
-
|
|
32
|
-
<h2>You are in control</h2>
|
|
33
|
-
|
|
34
|
-
<ul class="main-page-element">
|
|
35
|
-
<li>No black box recommendation algorithms.</li>
|
|
36
|
-
<li>No "smart" reordering of your news.</li>
|
|
37
|
-
<li>No ads.</li>
|
|
38
|
-
<li>No selling of your data.</li>
|
|
39
|
-
</ul>
|
|
40
|
-
|
|
41
|
-
<h2>Screenshots</h2>
|
|
42
|
-
|
|
43
|
-
<p><i>GUI is still in the early development stage, like the whole project. It will become more pleasurable.</i></p>
|
|
44
|
-
|
|
45
41
|
<img
|
|
42
|
+
class="border-2 rounded border-slate-300"
|
|
46
43
|
src="/news-filtering-example.png"
|
|
47
44
|
alt="News filtering example" />
|
|
48
|
-
|
|
49
|
-
<p class="main-page-element"><strong>Explanation</strong></p>
|
|
50
|
-
|
|
51
|
-
<ul class="main-page-element">
|
|
52
|
-
<li>From the news for the last week, sorted by score.</li>
|
|
53
|
-
<li>Show only news about <code>game-development</code> from <code>reddit.com</code>.</li>
|
|
54
|
-
<li>Exclude news related to <code>employment</code>.</li>
|
|
55
|
-
<li>Hide already read news.</li>
|
|
56
|
-
</ul>
|
|
57
|
-
|
|
58
|
-
<p class="main-page-element"><strong>Tags sorting for news records</strong></p>
|
|
59
|
-
|
|
60
|
-
<ul class="main-page-element">
|
|
61
|
-
<li>Tags are sorted by the impact on the score.</li>
|
|
62
|
-
<li>Green tags have a positive impact.</li>
|
|
63
|
-
<li>Red tags have a negative impact.</li>
|
|
64
|
-
</ul>
|
|
65
45
|
</wide-layout>
|
|
66
46
|
</template>
|
|
67
47
|
|
|
68
48
|
<script lang="ts" setup>
|
|
69
|
-
import {useRouter} from "vue-router";
|
|
70
|
-
import {useGlobalSettingsStore} from "@/stores/globalSettings";
|
|
71
|
-
import {useSupertokens} from "@/stores/supertokens";
|
|
72
|
-
import {useGlobalState} from "@/stores/globalState";
|
|
73
|
-
import {computedAsync} from "@vueuse/core";
|
|
74
49
|
import * as settings from "@/logic/settings";
|
|
75
|
-
import * as e from "@/logic/enums";
|
|
76
|
-
|
|
77
|
-
const globalSettings = useGlobalSettingsStore();
|
|
78
|
-
const globalState = useGlobalState();
|
|
79
|
-
|
|
80
|
-
const supertokens = useSupertokens();
|
|
81
|
-
|
|
82
|
-
const router = useRouter();
|
|
83
|
-
|
|
84
|
-
function goToWorkspace() {
|
|
85
|
-
router.push({name: e.MainPanelMode.Entries, params: {}});
|
|
86
|
-
}
|
|
87
50
|
</script>
|
|
88
|
-
|
|
89
|
-
<style>
|
|
90
|
-
.main-page-element {
|
|
91
|
-
text-align: left;
|
|
92
|
-
margin-left: auto;
|
|
93
|
-
max-width: 27rem;
|
|
94
|
-
margin-right: auto;
|
|
95
|
-
}
|
|
96
|
-
</style>
|
package/src/views/NewsView.vue
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<side-panel-layout>
|
|
3
3
|
<template #side-menu-item-1>
|
|
4
|
-
For
|
|
4
|
+
For
|
|
5
5
|
<config-selector
|
|
6
6
|
:values="e.LastEntriesPeriodProperties"
|
|
7
7
|
v-model:property="globalSettings.lastEntriesPeriod" />
|
|
8
8
|
</template>
|
|
9
9
|
|
|
10
10
|
<template #side-menu-item-2>
|
|
11
|
-
|
|
11
|
+
Sort by
|
|
12
12
|
<config-selector
|
|
13
13
|
:values="e.EntriesOrderProperties"
|
|
14
14
|
v-model:property="globalSettings.entriesOrder" />
|
|
@@ -17,17 +17,19 @@
|
|
|
17
17
|
<template #side-menu-item-3>
|
|
18
18
|
Show tags:
|
|
19
19
|
<config-flag
|
|
20
|
+
style="min-width: 2.5rem"
|
|
20
21
|
v-model:flag="globalSettings.showEntriesTags"
|
|
21
|
-
on-text="
|
|
22
|
-
off-text="
|
|
22
|
+
on-text="no"
|
|
23
|
+
off-text="yes" />
|
|
23
24
|
</template>
|
|
24
25
|
|
|
25
26
|
<template #side-menu-item-4>
|
|
26
|
-
Show
|
|
27
|
+
Show read:
|
|
27
28
|
<config-flag
|
|
29
|
+
style="min-width: 2.5rem"
|
|
28
30
|
v-model:flag="globalSettings.showRead"
|
|
29
|
-
on-text="
|
|
30
|
-
off-text="
|
|
31
|
+
on-text="no"
|
|
32
|
+
off-text="yes" />
|
|
31
33
|
</template>
|
|
32
34
|
|
|
33
35
|
<template #side-footer>
|
|
@@ -43,11 +45,10 @@
|
|
|
43
45
|
|
|
44
46
|
<template #main-footer> </template>
|
|
45
47
|
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
</template>
|
|
48
|
+
<notifications
|
|
49
|
+
v-if="entriesStore.loadedEntriesReport !== null"
|
|
50
|
+
:openai-api-key="true"
|
|
51
|
+
:collections="!hasEntries" />
|
|
51
52
|
|
|
52
53
|
<entries-list
|
|
53
54
|
:entriesIds="entriesReport"
|
|
@@ -55,7 +56,8 @@
|
|
|
55
56
|
:show-tags="globalSettings.showEntriesTags"
|
|
56
57
|
:tags-count="tagsCount"
|
|
57
58
|
:showFromStart="25"
|
|
58
|
-
:showPerPage="25"
|
|
59
|
+
:showPerPage="25"
|
|
60
|
+
@entry:bodyVisibilityChanged="onBodyVisibilityChanged" />
|
|
59
61
|
</side-panel-layout>
|
|
60
62
|
</template>
|
|
61
63
|
|
|
@@ -79,11 +81,22 @@
|
|
|
79
81
|
|
|
80
82
|
globalSettings.updateDataVersion();
|
|
81
83
|
|
|
84
|
+
const entriesWithOpenedBody = ref<{[key: t.EntryId]: boolean}>({});
|
|
85
|
+
|
|
82
86
|
const entriesReport = computed(() => {
|
|
87
|
+
if (entriesStore.loadedEntriesReport === null) {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
|
|
83
91
|
let report = entriesStore.loadedEntriesReport.slice();
|
|
84
92
|
|
|
85
93
|
if (!globalSettings.showRead) {
|
|
86
94
|
report = report.filter((entryId) => {
|
|
95
|
+
if (entriesWithOpenedBody.value[entryId]) {
|
|
96
|
+
// always show read entries with open body
|
|
97
|
+
// otherwise, they will hide right after opening it
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
87
100
|
return !entriesStore.entries[entryId].hasMarker(e.Marker.Read);
|
|
88
101
|
});
|
|
89
102
|
}
|
|
@@ -167,6 +180,10 @@
|
|
|
167
180
|
function onTagStateChanged({tag, state}: {tag: string; state: tagsFilterState.State}) {
|
|
168
181
|
tagsStates.value.onTagStateChanged({tag, state});
|
|
169
182
|
}
|
|
183
|
+
|
|
184
|
+
function onBodyVisibilityChanged({entryId, visible}: {entryId: t.EntryId; visible: boolean}) {
|
|
185
|
+
entriesWithOpenedBody.value[entryId] = visible;
|
|
186
|
+
}
|
|
170
187
|
</script>
|
|
171
188
|
|
|
172
189
|
<style></style>
|
package/src/views/RulesView.vue
CHANGED
|
@@ -1,53 +1,66 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<side-panel-layout :reload-button="false">
|
|
3
|
-
<
|
|
3
|
+
<template #main-header> Settings </template>
|
|
4
4
|
|
|
5
5
|
<ul>
|
|
6
|
-
<li
|
|
6
|
+
<li>
|
|
7
|
+
<strong class="mr-1">User id</strong>
|
|
8
|
+
<input
|
|
9
|
+
class="ffun-input w-72"
|
|
10
|
+
disabled
|
|
11
|
+
:value="userId" />
|
|
12
|
+
</li>
|
|
7
13
|
</ul>
|
|
8
14
|
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
<template #main-header> Settings </template>
|
|
15
|
+
<hr />
|
|
12
16
|
|
|
13
|
-
<
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
<template v-for="(value, kind) of globalSettings.userSettings">
|
|
18
|
+
<user-setting :kind="kind" />
|
|
19
|
+
<hr />
|
|
20
|
+
</template>
|
|
16
21
|
|
|
17
22
|
<h2>OpenAI usage</h2>
|
|
18
23
|
|
|
19
24
|
<p>Token usage for your OpenAI key per month.</p>
|
|
20
25
|
|
|
21
|
-
<ul>
|
|
22
|
-
<li> <strong>Used tokens</strong
|
|
26
|
+
<ul class="list-disc list-inside">
|
|
27
|
+
<li> <strong>Used tokens</strong> — the number of tokens in processed requests. </li>
|
|
23
28
|
<li>
|
|
24
|
-
<strong>Reserved tokens</strong
|
|
29
|
+
<strong>Reserved tokens</strong> — the number of tokens reserved for requests that currently are processing or
|
|
25
30
|
were not processed correctly.
|
|
26
31
|
</li>
|
|
27
32
|
<li>
|
|
28
|
-
<strong>Total tokens</strong
|
|
29
|
-
used tokens, but can be bigger because we reserve more tokens than actually use.
|
|
33
|
+
<strong>Total tokens</strong> — the total number of tokens used in the month. Should be not less than the
|
|
34
|
+
actual used tokens, but can be bigger because we reserve more tokens than actually use.
|
|
30
35
|
</li>
|
|
31
36
|
</ul>
|
|
32
37
|
|
|
33
38
|
<p v-if="openAIUsage == null">Loading...</p>
|
|
34
39
|
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
<thead>
|
|
40
|
+
<table
|
|
41
|
+
v-else
|
|
42
|
+
class="border border-gray-300 rounded-lg">
|
|
43
|
+
<thead class="bg-slate-200">
|
|
39
44
|
<tr>
|
|
40
|
-
<th
|
|
41
|
-
<th
|
|
42
|
-
<th
|
|
43
|
-
<th
|
|
44
|
-
<th
|
|
45
|
+
<th class="p-2">Period</th>
|
|
46
|
+
<th class="p-2">Used tokens</th>
|
|
47
|
+
<th class="p-2">Reserved tokens</th>
|
|
48
|
+
<th class="p-2">Total tokens</th>
|
|
49
|
+
<th class="p-2">% from current maximum</th>
|
|
45
50
|
</tr>
|
|
46
51
|
</thead>
|
|
47
52
|
<tbody>
|
|
48
53
|
<openai-tokens-usage
|
|
49
54
|
:usage="usage"
|
|
50
55
|
v-for="usage of openAIUsage" />
|
|
56
|
+
|
|
57
|
+
<tr v-if="openAIUsage.length == 0">
|
|
58
|
+
<td class="text-center">—</td>
|
|
59
|
+
<td class="text-center">—</td>
|
|
60
|
+
<td class="text-center">—</td>
|
|
61
|
+
<td class="text-center">—</td>
|
|
62
|
+
<td class="text-center">—</td>
|
|
63
|
+
</tr>
|
|
51
64
|
</tbody>
|
|
52
65
|
</table>
|
|
53
66
|
</side-panel-layout>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** @type {import('tailwindcss').Config} */
|
|
2
|
+
module.exports = {
|
|
3
|
+
content: [
|
|
4
|
+
"./index.html",
|
|
5
|
+
"./src/*.{vue,js,ts,jsx,tsx}",
|
|
6
|
+
"./src/**/*.{vue,js,ts,jsx,tsx}",
|
|
7
|
+
],
|
|
8
|
+
theme: {
|
|
9
|
+
extend: {},
|
|
10
|
+
},
|
|
11
|
+
plugins: [
|
|
12
|
+
require('@tailwindcss/typography'),
|
|
13
|
+
],
|
|
14
|
+
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div>
|
|
3
|
-
<a
|
|
4
|
-
:href="entry.url"
|
|
5
|
-
target="_blank"
|
|
6
|
-
rel="noopener noreferrer">
|
|
7
|
-
{{ entry.title }}
|
|
8
|
-
</a>
|
|
9
|
-
</div>
|
|
10
|
-
</template>
|
|
11
|
-
|
|
12
|
-
<script lang="ts" setup>
|
|
13
|
-
import {computed, ref} from "vue";
|
|
14
|
-
import type * as t from "@/logic/types";
|
|
15
|
-
import * as e from "@/logic/enums";
|
|
16
|
-
import * as api from "@/logic/api";
|
|
17
|
-
import {computedAsync} from "@vueuse/core";
|
|
18
|
-
import {useEntriesStore} from "@/stores/entries";
|
|
19
|
-
|
|
20
|
-
const props = defineProps<{entry: t.EntryInfo}>();
|
|
21
|
-
</script>
|
|
22
|
-
|
|
23
|
-
<style scoped></style>
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div>
|
|
3
|
-
<github-button
|
|
4
|
-
:href="repository"
|
|
5
|
-
data-icon="octicon-star"
|
|
6
|
-
>Star</github-button
|
|
7
|
-
>
|
|
8
|
-
|
|
9
|
-
<github-button
|
|
10
|
-
:href="repository + '/discussions'"
|
|
11
|
-
data-show-count="true"
|
|
12
|
-
data-icon="octicon-comment-discussion"
|
|
13
|
-
>Discuss</github-button
|
|
14
|
-
>
|
|
15
|
-
</div>
|
|
16
|
-
</template>
|
|
17
|
-
|
|
18
|
-
<script lang="ts" setup>
|
|
19
|
-
const props = defineProps<{repository: string}>();
|
|
20
|
-
</script>
|
|
21
|
-
|
|
22
|
-
<style></style>
|