feeds-fun 1.2.0 → 1.3.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 +1 -1
- package/src/components/DiscoveryForm.vue +62 -45
- package/src/components/EntryForList.vue +9 -7
- package/src/components/FeedsCollections.vue +66 -25
- package/src/components/OPMLUpload.vue +53 -11
- package/src/components/RuleConstructor.vue +2 -0
- package/src/components/RuleForList.vue +53 -23
- package/src/inputs/Marker.vue +1 -1
- package/src/layouts/SidePanelLayout.vue +1 -1
- package/src/logic/enums.ts +10 -5
- package/src/main.ts +0 -2
- package/src/views/NewsView.vue +2 -2
- package/src/components/RuleScoreUpdater.vue +0 -33
package/package.json
CHANGED
|
@@ -1,44 +1,53 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
3
|
+
<form @submit.prevent="searhedUrl = search">
|
|
4
|
+
<input
|
|
5
|
+
type="text"
|
|
6
|
+
class="ffun-input mr-1"
|
|
7
|
+
v-model="search"
|
|
8
|
+
:disabled="disableInputs"
|
|
9
|
+
placeholder="Enter a site URL" />
|
|
10
|
+
|
|
11
|
+
<button
|
|
12
|
+
type="submit"
|
|
13
|
+
class="ffun-form-button"
|
|
14
|
+
:disabled="disableInputs">
|
|
15
|
+
Search
|
|
16
|
+
</button>
|
|
17
|
+
</form>
|
|
18
|
+
|
|
19
|
+
<p
|
|
20
|
+
v-if="searching"
|
|
21
|
+
class="ffun-info-attention"
|
|
22
|
+
>Searching for feeds…</p
|
|
23
|
+
>
|
|
24
|
+
|
|
25
|
+
<div v-else-if="foundFeeds === null"></div>
|
|
26
|
+
|
|
27
|
+
<p
|
|
28
|
+
v-else-if="foundFeeds.length === 0"
|
|
29
|
+
class="ffun-info-attention"
|
|
30
|
+
>No feeds found.</p
|
|
31
|
+
>
|
|
32
|
+
|
|
33
|
+
<div
|
|
34
|
+
v-for="feed in foundFeeds"
|
|
35
|
+
:key="feed.url">
|
|
36
|
+
<feed-info :feed="feed" />
|
|
37
|
+
|
|
38
|
+
<button
|
|
39
|
+
class="ffun-form-button"
|
|
40
|
+
v-if="!addedFeeds[feed.url]"
|
|
41
|
+
:disabled="disableInputs"
|
|
42
|
+
@click.prevent="addFeed(feed.url)">
|
|
43
|
+
Add
|
|
44
|
+
</button>
|
|
45
|
+
|
|
46
|
+
<p
|
|
47
|
+
v-else
|
|
48
|
+
class="ffun-info-good"
|
|
49
|
+
>Feed added</p
|
|
50
|
+
>
|
|
42
51
|
</div>
|
|
43
52
|
</div>
|
|
44
53
|
</template>
|
|
@@ -52,7 +61,11 @@
|
|
|
52
61
|
import {useEntriesStore} from "@/stores/entries";
|
|
53
62
|
|
|
54
63
|
const search = ref("");
|
|
55
|
-
|
|
64
|
+
|
|
65
|
+
const searching = ref(false);
|
|
66
|
+
const adding = ref(false);
|
|
67
|
+
|
|
68
|
+
const disableInputs = computed(() => searching.value || adding.value);
|
|
56
69
|
|
|
57
70
|
const searhedUrl = ref("");
|
|
58
71
|
|
|
@@ -60,10 +73,10 @@
|
|
|
60
73
|
|
|
61
74
|
const foundFeeds = computedAsync(async () => {
|
|
62
75
|
if (searhedUrl.value === "") {
|
|
63
|
-
return
|
|
76
|
+
return null;
|
|
64
77
|
}
|
|
65
78
|
|
|
66
|
-
|
|
79
|
+
searching.value = true;
|
|
67
80
|
|
|
68
81
|
let feeds: t.FeedInfo[] = [];
|
|
69
82
|
|
|
@@ -73,15 +86,19 @@
|
|
|
73
86
|
console.error(e);
|
|
74
87
|
}
|
|
75
88
|
|
|
76
|
-
|
|
89
|
+
searching.value = false;
|
|
77
90
|
|
|
78
91
|
return feeds;
|
|
79
|
-
},
|
|
92
|
+
}, null);
|
|
80
93
|
|
|
81
94
|
async function addFeed(url: string) {
|
|
82
|
-
|
|
95
|
+
adding.value = true;
|
|
83
96
|
|
|
84
97
|
await api.addFeed({url: url});
|
|
98
|
+
|
|
99
|
+
addedFeeds.value[url] = true;
|
|
100
|
+
|
|
101
|
+
adding.value = false;
|
|
85
102
|
}
|
|
86
103
|
</script>
|
|
87
104
|
|
|
@@ -12,6 +12,15 @@
|
|
|
12
12
|
class="w-4 h-4 align-text-bottom mx-1 inline" />
|
|
13
13
|
</div>
|
|
14
14
|
|
|
15
|
+
<div class="flex-shrink-0 text-right">
|
|
16
|
+
<input-marker
|
|
17
|
+
class="w-7 mr-2"
|
|
18
|
+
:marker="e.Marker.Read"
|
|
19
|
+
:entry-id="entryId"
|
|
20
|
+
on-text="read"
|
|
21
|
+
off-text="new" />
|
|
22
|
+
</div>
|
|
23
|
+
|
|
15
24
|
<div class="flex-grow">
|
|
16
25
|
<a
|
|
17
26
|
:href="entry.url"
|
|
@@ -30,13 +39,6 @@
|
|
|
30
39
|
</div>
|
|
31
40
|
|
|
32
41
|
<div class="flex flex-shrink-0">
|
|
33
|
-
<input-marker
|
|
34
|
-
class="w-7 mr-2"
|
|
35
|
-
:marker="e.Marker.Read"
|
|
36
|
-
:entry-id="entryId"
|
|
37
|
-
on-text="read"
|
|
38
|
-
off-text="new" />
|
|
39
|
-
|
|
40
42
|
<div class="w-7">
|
|
41
43
|
<value-date-time
|
|
42
44
|
:value="timeFor"
|
|
@@ -1,27 +1,47 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<
|
|
4
|
-
<
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
3
|
+
<form @submit.prevent="subscribe">
|
|
4
|
+
<ul class="mb-1">
|
|
5
|
+
<li v-for="item in collections">
|
|
6
|
+
<input
|
|
7
|
+
class="ffun-checkbox"
|
|
8
|
+
type="checkbox"
|
|
9
|
+
:id="item"
|
|
10
|
+
:name="item"
|
|
11
|
+
:value="item"
|
|
12
|
+
v-model="selectedCollections"
|
|
13
|
+
checked />
|
|
14
|
+
<label
|
|
15
|
+
class="ml-2"
|
|
16
|
+
:for="item"
|
|
17
|
+
>{{ item }}</label
|
|
18
|
+
>
|
|
19
|
+
</li>
|
|
20
|
+
</ul>
|
|
21
|
+
|
|
22
|
+
<button
|
|
23
|
+
type="submit"
|
|
24
|
+
class="ffun-form-button"
|
|
25
|
+
>Subscribe</button
|
|
26
|
+
>
|
|
27
|
+
</form>
|
|
28
|
+
|
|
29
|
+
<p
|
|
30
|
+
v-if="loading"
|
|
31
|
+
class="ffun-info-attention"
|
|
32
|
+
>subscribing...</p
|
|
33
|
+
>
|
|
34
|
+
|
|
35
|
+
<p
|
|
36
|
+
v-if="loaded"
|
|
37
|
+
class="ffun-info-good"
|
|
38
|
+
>Feeds added!</p
|
|
39
|
+
>
|
|
40
|
+
|
|
41
|
+
<p
|
|
42
|
+
v-if="error"
|
|
43
|
+
class="ffun-info-bad"
|
|
44
|
+
>Unknown error occurred! Please, try later.</p
|
|
25
45
|
>
|
|
26
46
|
</div>
|
|
27
47
|
</template>
|
|
@@ -36,6 +56,10 @@
|
|
|
36
56
|
import {useEntriesStore} from "@/stores/entries";
|
|
37
57
|
import {useGlobalSettingsStore} from "@/stores/globalSettings";
|
|
38
58
|
|
|
59
|
+
const loading = ref(false);
|
|
60
|
+
const loaded = ref(false);
|
|
61
|
+
const error = ref(false);
|
|
62
|
+
|
|
39
63
|
const selectedCollections = ref<t.FeedsCollectionId[]>([]);
|
|
40
64
|
|
|
41
65
|
const globalSettings = useGlobalSettingsStore();
|
|
@@ -51,9 +75,26 @@
|
|
|
51
75
|
});
|
|
52
76
|
|
|
53
77
|
async function subscribe() {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
78
|
+
loading.value = true;
|
|
79
|
+
loaded.value = false;
|
|
80
|
+
error.value = false;
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
await api.subscribeToFeedsCollections({
|
|
84
|
+
collectionsIds: selectedCollections.value
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
loading.value = false;
|
|
88
|
+
loaded.value = true;
|
|
89
|
+
error.value = false;
|
|
90
|
+
} catch (e) {
|
|
91
|
+
console.error(e);
|
|
92
|
+
|
|
93
|
+
loading.value = false;
|
|
94
|
+
loaded.value = false;
|
|
95
|
+
error.value = true;
|
|
96
|
+
}
|
|
97
|
+
|
|
57
98
|
globalSettings.updateDataVersion();
|
|
58
99
|
}
|
|
59
100
|
</script>
|
|
@@ -1,15 +1,37 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
<form @submit.prevent="submit">
|
|
4
|
+
<input
|
|
5
|
+
type="file"
|
|
6
|
+
class="ffun-file-button"
|
|
7
|
+
:disabled="loading"
|
|
8
|
+
@change="uploadFile" />
|
|
9
|
+
|
|
10
|
+
<button
|
|
11
|
+
class="ffun-form-button"
|
|
12
|
+
type="submit"
|
|
13
|
+
:disabled="loading"
|
|
14
|
+
@click.prevent="submit"
|
|
15
|
+
>Submit</button
|
|
16
|
+
>
|
|
17
|
+
</form>
|
|
18
|
+
|
|
19
|
+
<p
|
|
20
|
+
v-if="loading"
|
|
21
|
+
class="ffun-info-attention"
|
|
22
|
+
>Loading...</p
|
|
23
|
+
>
|
|
24
|
+
|
|
25
|
+
<p
|
|
26
|
+
v-if="loaded"
|
|
27
|
+
class="ffun-info-good"
|
|
28
|
+
>Feeds added!</p
|
|
29
|
+
>
|
|
30
|
+
|
|
31
|
+
<p
|
|
32
|
+
v-if="error"
|
|
33
|
+
class="ffun-info-bad"
|
|
34
|
+
>Error occurred! Maybe you chose a wrong file?</p
|
|
13
35
|
>
|
|
14
36
|
</div>
|
|
15
37
|
</template>
|
|
@@ -24,8 +46,13 @@
|
|
|
24
46
|
|
|
25
47
|
const opmlFile = ref<File | null>(null);
|
|
26
48
|
|
|
49
|
+
const loading = ref(false);
|
|
50
|
+
const loaded = ref(false);
|
|
51
|
+
const error = ref(false);
|
|
52
|
+
|
|
27
53
|
function uploadFile(event: Event) {
|
|
28
54
|
opmlFile.value = (event.target as HTMLInputElement).files?.[0] ?? null;
|
|
55
|
+
loaded.value = false;
|
|
29
56
|
}
|
|
30
57
|
|
|
31
58
|
async function submit() {
|
|
@@ -33,6 +60,10 @@
|
|
|
33
60
|
return;
|
|
34
61
|
}
|
|
35
62
|
|
|
63
|
+
loading.value = true;
|
|
64
|
+
loaded.value = false;
|
|
65
|
+
error.value = false;
|
|
66
|
+
|
|
36
67
|
const reader = new FileReader();
|
|
37
68
|
|
|
38
69
|
reader.readAsText(opmlFile.value);
|
|
@@ -42,7 +73,18 @@
|
|
|
42
73
|
};
|
|
43
74
|
});
|
|
44
75
|
|
|
45
|
-
|
|
76
|
+
try {
|
|
77
|
+
await api.addOPML({content: content});
|
|
78
|
+
|
|
79
|
+
loading.value = false;
|
|
80
|
+
loaded.value = true;
|
|
81
|
+
error.value = false;
|
|
82
|
+
} catch (e) {
|
|
83
|
+
console.error(e);
|
|
84
|
+
loading.value = false;
|
|
85
|
+
loaded.value = false;
|
|
86
|
+
error.value = true;
|
|
87
|
+
}
|
|
46
88
|
}
|
|
47
89
|
</script>
|
|
48
90
|
|
|
@@ -1,29 +1,42 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
2
|
+
<div>
|
|
3
|
+
<div
|
|
4
|
+
v-if="rule !== null"
|
|
5
|
+
class="flex mb-1">
|
|
6
|
+
<div class="flex-shrink-0 min-w-fit mr-2">
|
|
7
|
+
<a
|
|
8
|
+
href="#"
|
|
9
|
+
class="ffun-normal-link"
|
|
10
|
+
@click.prevent="deleteRule()">
|
|
11
|
+
remove
|
|
12
|
+
</a>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<score-selector
|
|
16
|
+
class="flex-shrink-0 mr-2"
|
|
17
|
+
:modelValue="rule.score"
|
|
18
|
+
@input="updateSelected" />
|
|
13
19
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
<template
|
|
22
|
-
v-for="tag of rule.tags"
|
|
23
|
-
:key="tag">
|
|
24
|
-
<ffun-tag :uid="tag" />
|
|
25
|
-
</template>
|
|
20
|
+
<div class="flex-grow">
|
|
21
|
+
<template
|
|
22
|
+
v-for="tag of rule.tags"
|
|
23
|
+
:key="tag">
|
|
24
|
+
<ffun-tag :uid="tag" />
|
|
25
|
+
</template>
|
|
26
|
+
</div>
|
|
26
27
|
</div>
|
|
28
|
+
|
|
29
|
+
<p
|
|
30
|
+
v-if="scoreChanged"
|
|
31
|
+
class="ffun-info-good">
|
|
32
|
+
Score updated
|
|
33
|
+
<a
|
|
34
|
+
href="#"
|
|
35
|
+
class="ffun-form-button"
|
|
36
|
+
@click.prevent="scoreChanged = false"
|
|
37
|
+
>close</a
|
|
38
|
+
>
|
|
39
|
+
</p>
|
|
27
40
|
</div>
|
|
28
41
|
</template>
|
|
29
42
|
|
|
@@ -40,8 +53,25 @@
|
|
|
40
53
|
|
|
41
54
|
const properties = defineProps<{rule: t.Rule}>();
|
|
42
55
|
|
|
56
|
+
const scoreChanged = ref(false);
|
|
57
|
+
|
|
43
58
|
async function deleteRule() {
|
|
44
59
|
await api.deleteRule({id: properties.rule.id});
|
|
45
60
|
globalSettings.updateDataVersion();
|
|
46
61
|
}
|
|
62
|
+
|
|
63
|
+
async function updateSelected(event: Event) {
|
|
64
|
+
const target = event.target as HTMLInputElement;
|
|
65
|
+
const newScore = Number(target.value);
|
|
66
|
+
|
|
67
|
+
await api.updateRule({
|
|
68
|
+
id: properties.rule.id,
|
|
69
|
+
score: newScore,
|
|
70
|
+
tags: properties.rule.tags
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
scoreChanged.value = true;
|
|
74
|
+
|
|
75
|
+
globalSettings.updateDataVersion();
|
|
76
|
+
}
|
|
47
77
|
</script>
|
package/src/inputs/Marker.vue
CHANGED
package/src/logic/enums.ts
CHANGED
|
@@ -58,15 +58,20 @@ export const LastEntriesPeriodProperties = new Map<LastEntriesPeriod, {text: str
|
|
|
58
58
|
export enum EntriesOrder {
|
|
59
59
|
Score = "score",
|
|
60
60
|
ScoreToZero = "score-to-zero",
|
|
61
|
+
ScoreBackward = "score-to-",
|
|
61
62
|
Published = "published",
|
|
62
63
|
Cataloged = "cataloged"
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
export const EntriesOrderProperties = new Map<
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
[EntriesOrder.
|
|
66
|
+
export const EntriesOrderProperties = new Map<
|
|
67
|
+
EntriesOrder,
|
|
68
|
+
{text: string; orderField: string; timeField: string; direction: number}
|
|
69
|
+
>([
|
|
70
|
+
[EntriesOrder.Score, {text: "score", orderField: "score", timeField: "catalogedAt", direction: 1}],
|
|
71
|
+
[EntriesOrder.ScoreToZero, {text: "score ~ 0", orderField: "scoreToZero", timeField: "catalogedAt", direction: 1}],
|
|
72
|
+
[EntriesOrder.ScoreBackward, {text: "score backward", orderField: "score", timeField: "catalogedAt", direction: -1}],
|
|
73
|
+
[EntriesOrder.Published, {text: "published", orderField: "publishedAt", timeField: "publishedAt", direction: 1}],
|
|
74
|
+
[EntriesOrder.Cataloged, {text: "cataloged", orderField: "catalogedAt", timeField: "catalogedAt", direction: 1}]
|
|
70
75
|
]);
|
|
71
76
|
|
|
72
77
|
export enum Marker {
|
package/src/main.ts
CHANGED
|
@@ -14,7 +14,6 @@ import ConfigSelector from "./components/ConfigSelector.vue";
|
|
|
14
14
|
import ConfigFlag from "./components/ConfigFlag.vue";
|
|
15
15
|
import EntryForList from "./components/EntryForList.vue";
|
|
16
16
|
import RuleConstructor from "./components/RuleConstructor.vue";
|
|
17
|
-
import RuleScoreUpdater from "./components/RuleScoreUpdater.vue";
|
|
18
17
|
import TagsFilter from "./components/TagsFilter.vue";
|
|
19
18
|
import DiscoveryForm from "./components/DiscoveryForm.vue";
|
|
20
19
|
import FeedInfo from "./components/FeedInfo.vue";
|
|
@@ -58,7 +57,6 @@ app.component("ConfigSelector", ConfigSelector);
|
|
|
58
57
|
app.component("ConfigFlag", ConfigFlag);
|
|
59
58
|
app.component("EntryForList", EntryForList);
|
|
60
59
|
app.component("RuleConstructor", RuleConstructor);
|
|
61
|
-
app.component("RuleScoreUpdater", RuleScoreUpdater);
|
|
62
60
|
app.component("TagsFilter", TagsFilter);
|
|
63
61
|
app.component("DiscoveryForm", DiscoveryForm);
|
|
64
62
|
app.component("FeedInfo", FeedInfo);
|
package/src/views/NewsView.vue
CHANGED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div>
|
|
3
|
-
<score-selector
|
|
4
|
-
:modelValue="currentScore"
|
|
5
|
-
@input="updateSelected" />
|
|
6
|
-
</div>
|
|
7
|
-
</template>
|
|
8
|
-
|
|
9
|
-
<script lang="ts" setup>
|
|
10
|
-
import {computed, ref} from "vue";
|
|
11
|
-
import * as api from "@/logic/api";
|
|
12
|
-
import type * as t from "@/logic/types";
|
|
13
|
-
|
|
14
|
-
const properties = defineProps<{
|
|
15
|
-
score: number;
|
|
16
|
-
ruleId: t.RuleId;
|
|
17
|
-
tags: string[];
|
|
18
|
-
}>();
|
|
19
|
-
|
|
20
|
-
const currentScore = ref(properties.score);
|
|
21
|
-
|
|
22
|
-
async function updateSelected(event: Event) {
|
|
23
|
-
const target = event.target as HTMLInputElement;
|
|
24
|
-
const newScore = Number(target.value);
|
|
25
|
-
await api.updateRule({
|
|
26
|
-
id: properties.ruleId,
|
|
27
|
-
score: newScore,
|
|
28
|
-
tags: properties.tags
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
</script>
|
|
32
|
-
|
|
33
|
-
<style scoped></style>
|