feeds-fun 1.13.1 → 1.13.2
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 +30 -29
- package/src/components/EntryForList.vue +11 -1
- package/src/layouts/SidePanelLayout.vue +7 -1
- package/src/logic/api.ts +8 -1
- package/src/logic/events.ts +14 -0
- package/src/stores/feeds.ts +10 -4
- package/tsconfig.app.json +1 -1
- package/tsconfig.node.json +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "feeds-fun",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.2",
|
|
4
4
|
"author": "Aliaksei Yaletski (Tiendil) <a.eletsky@gmail.com> (https://tiendil.org/)",
|
|
5
5
|
"description": "Frontend for the Feeds Fun — web-based news reader",
|
|
6
6
|
"keywords": [
|
|
@@ -33,38 +33,39 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@chenfengyuan/vue-countdown": "^2.1.2",
|
|
36
|
-
"@vueuse/core": "^
|
|
37
|
-
"axios": "^1.
|
|
38
|
-
"dompurify": "^3.
|
|
39
|
-
"pinia": "^2.
|
|
36
|
+
"@vueuse/core": "^11.2.0",
|
|
37
|
+
"axios": "^1.7.7",
|
|
38
|
+
"dompurify": "^3.1.7",
|
|
39
|
+
"pinia": "^2.2.6",
|
|
40
40
|
"set-interval-async": "^3.0.3",
|
|
41
41
|
"supertokens-web-js": "^0.5.0",
|
|
42
|
-
"vue": "^3.
|
|
43
|
-
"vue-router": "^4.
|
|
42
|
+
"vue": "^3.5.12",
|
|
43
|
+
"vue-router": "^4.4.5",
|
|
44
|
+
"lodash": "^4.17.21"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
46
|
-
"@rushstack/eslint-patch": "^1.
|
|
47
|
-
"@tailwindcss/typography": "^0.5.
|
|
48
|
-
"@types/dompurify": "^3.0.
|
|
49
|
-
"@types/jsdom": "^21.1.
|
|
50
|
-
"@types/lodash": "^4.
|
|
51
|
-
"@types/node": "^
|
|
52
|
-
"@vitejs/plugin-vue": "^
|
|
53
|
-
"@vue/eslint-config-prettier": "^
|
|
54
|
-
"@vue/eslint-config-typescript": "^
|
|
55
|
-
"@vue/test-utils": "^2.4.
|
|
56
|
-
"@vue/tsconfig": "^0.1
|
|
57
|
-
"autoprefixer": "^10.4.
|
|
58
|
-
"eslint": "^
|
|
59
|
-
"eslint-plugin-vue": "^9.
|
|
60
|
-
"jsdom": "^
|
|
47
|
+
"@rushstack/eslint-patch": "^1.10.4",
|
|
48
|
+
"@tailwindcss/typography": "^0.5.15",
|
|
49
|
+
"@types/dompurify": "^3.0.5",
|
|
50
|
+
"@types/jsdom": "^21.1.7",
|
|
51
|
+
"@types/lodash": "^4.17.13",
|
|
52
|
+
"@types/node": "^22.9.0",
|
|
53
|
+
"@vitejs/plugin-vue": "^5.1.4",
|
|
54
|
+
"@vue/eslint-config-prettier": "^10.1.0",
|
|
55
|
+
"@vue/eslint-config-typescript": "^14.1.3",
|
|
56
|
+
"@vue/test-utils": "^2.4.6",
|
|
57
|
+
"@vue/tsconfig": "^0.5.1",
|
|
58
|
+
"autoprefixer": "^10.4.20",
|
|
59
|
+
"eslint": "^9.14.0",
|
|
60
|
+
"eslint-plugin-vue": "^9.30.0",
|
|
61
|
+
"jsdom": "^25.0.1",
|
|
61
62
|
"npm-run-all": "^4.1.5",
|
|
62
|
-
"postcss": "^8.4.
|
|
63
|
-
"prettier": "^
|
|
64
|
-
"tailwindcss": "^3.
|
|
65
|
-
"typescript": "~
|
|
66
|
-
"vite": "^
|
|
67
|
-
"vitest": "^
|
|
68
|
-
"vue-tsc": "^1.
|
|
63
|
+
"postcss": "^8.4.47",
|
|
64
|
+
"prettier": "^3.3.3",
|
|
65
|
+
"tailwindcss": "^3.4.14",
|
|
66
|
+
"typescript": "~5.6.3",
|
|
67
|
+
"vite": "^5.4.10",
|
|
68
|
+
"vitest": "^2.1.4",
|
|
69
|
+
"vue-tsc": "^2.1.10"
|
|
69
70
|
}
|
|
70
71
|
}
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
><a
|
|
56
56
|
:href="entry.url"
|
|
57
57
|
target="_blank"
|
|
58
|
+
@click="newsLinkOpenedEvent"
|
|
58
59
|
>{{ purifiedTitle }}</a
|
|
59
60
|
></h2
|
|
60
61
|
>
|
|
@@ -71,6 +72,7 @@
|
|
|
71
72
|
import _ from "lodash";
|
|
72
73
|
import {computed, ref} from "vue";
|
|
73
74
|
import type * as t from "@/logic/types";
|
|
75
|
+
import * as events from "@/logic/events";
|
|
74
76
|
import * as e from "@/logic/enums";
|
|
75
77
|
import {computedAsync} from "@vueuse/core";
|
|
76
78
|
import DOMPurify from "dompurify";
|
|
@@ -109,7 +111,7 @@
|
|
|
109
111
|
return _.get(entry.value, properties.timeField, null);
|
|
110
112
|
});
|
|
111
113
|
|
|
112
|
-
function displayBody() {
|
|
114
|
+
async function displayBody() {
|
|
113
115
|
showBody.value = true;
|
|
114
116
|
|
|
115
117
|
emit("entry:bodyVisibilityChanged", {entryId: properties.entryId, visible: true});
|
|
@@ -119,6 +121,8 @@
|
|
|
119
121
|
}
|
|
120
122
|
|
|
121
123
|
entriesStore.requestFullEntry({entryId: entry.value.id});
|
|
124
|
+
|
|
125
|
+
await events.newsBodyOpened({entryId: entry.value.id});
|
|
122
126
|
}
|
|
123
127
|
|
|
124
128
|
function hideBody() {
|
|
@@ -152,6 +156,10 @@
|
|
|
152
156
|
return DOMPurify.sanitize(entry.value.body);
|
|
153
157
|
});
|
|
154
158
|
|
|
159
|
+
async function newsLinkOpenedEvent() {
|
|
160
|
+
await events.newsLinkOpened({entryId: entry.value.id});
|
|
161
|
+
}
|
|
162
|
+
|
|
155
163
|
async function onTitleClick(event: MouseEvent) {
|
|
156
164
|
if (!event.ctrlKey) {
|
|
157
165
|
event.preventDefault();
|
|
@@ -162,6 +170,8 @@
|
|
|
162
170
|
} else {
|
|
163
171
|
displayBody();
|
|
164
172
|
}
|
|
173
|
+
} else {
|
|
174
|
+
await newsLinkOpenedEvent();
|
|
165
175
|
}
|
|
166
176
|
|
|
167
177
|
// TODO: is it will be too slow?
|
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
target="_blank"
|
|
73
73
|
class="ffun-header-link"
|
|
74
74
|
style="text-decoration: none"
|
|
75
|
+
@click="events.socialLinkClicked({linkType: 'api'})"
|
|
75
76
|
>API</a
|
|
76
77
|
>
|
|
77
78
|
</li>
|
|
@@ -82,6 +83,7 @@
|
|
|
82
83
|
target="_blank"
|
|
83
84
|
class="ffun-header-link"
|
|
84
85
|
style="text-decoration: none"
|
|
86
|
+
@click="events.socialLinkClicked({linkType: 'blog'})"
|
|
85
87
|
>Blog</a
|
|
86
88
|
>
|
|
87
89
|
</li>
|
|
@@ -93,6 +95,7 @@
|
|
|
93
95
|
class="ffun-header-link text-xl align-middle"
|
|
94
96
|
title="Reddit"
|
|
95
97
|
style="text-decoration: none"
|
|
98
|
+
@click="events.socialLinkClicked({linkType: 'reddit'})"
|
|
96
99
|
><i class="ti ti-brand-reddit"></i
|
|
97
100
|
></a>
|
|
98
101
|
</li>
|
|
@@ -104,6 +107,7 @@
|
|
|
104
107
|
class="ffun-header-link text-xl align-middle"
|
|
105
108
|
title="Discord"
|
|
106
109
|
style="text-decoration: none"
|
|
110
|
+
@click="events.socialLinkClicked({linkType: 'discord'})"
|
|
107
111
|
><i class="ti ti-brand-discord"></i
|
|
108
112
|
></a>
|
|
109
113
|
</li>
|
|
@@ -114,7 +118,8 @@
|
|
|
114
118
|
target="_blank"
|
|
115
119
|
class="ffun-header-link text-xl align-middle"
|
|
116
120
|
title="GitHub"
|
|
117
|
-
style="text-decoration: none"
|
|
121
|
+
style="text-decoration: none"
|
|
122
|
+
@click="events.socialLinkClicked({linkType: 'github'})">
|
|
118
123
|
<i class="ti ti-brand-github"></i
|
|
119
124
|
></a>
|
|
120
125
|
</li>
|
|
@@ -150,6 +155,7 @@
|
|
|
150
155
|
import {useGlobalSettingsStore} from "@/stores/globalSettings";
|
|
151
156
|
import {useGlobalState} from "@/stores/globalState";
|
|
152
157
|
import {useSupertokens} from "@/stores/supertokens";
|
|
158
|
+
import * as events from "@/logic/events";
|
|
153
159
|
import * as e from "@/logic/enums";
|
|
154
160
|
import * as settings from "@/logic/settings";
|
|
155
161
|
|
package/src/logic/api.ts
CHANGED
|
@@ -28,6 +28,7 @@ const API_GET_USER_SETTINGS = `${ENTRY_POINT}/get-user-settings`;
|
|
|
28
28
|
const API_SET_USER_SETTING = `${ENTRY_POINT}/set-user-setting`;
|
|
29
29
|
const API_GET_RESOURCE_HISTORY = `${ENTRY_POINT}/get-resource-history`;
|
|
30
30
|
const API_GET_INFO = `${ENTRY_POINT}/get-info`;
|
|
31
|
+
const API_TRACK_EVENT = `${ENTRY_POINT}/track-event`;
|
|
31
32
|
|
|
32
33
|
let _onSessionLost: () => void = () => {};
|
|
33
34
|
|
|
@@ -176,7 +177,9 @@ export async function discoverFeeds({url}: {url: string}) {
|
|
|
176
177
|
}
|
|
177
178
|
|
|
178
179
|
export async function addFeed({url}: {url: string}) {
|
|
179
|
-
await post({url: API_ADD_FEED, data: {url: url}});
|
|
180
|
+
const response = await post({url: API_ADD_FEED, data: {url: url}});
|
|
181
|
+
|
|
182
|
+
return t.feedFromJSON(response.feed);
|
|
180
183
|
}
|
|
181
184
|
|
|
182
185
|
export async function addOPML({content}: {content: string}) {
|
|
@@ -275,3 +278,7 @@ export async function getInfo() {
|
|
|
275
278
|
|
|
276
279
|
return response;
|
|
277
280
|
}
|
|
281
|
+
|
|
282
|
+
export async function trackEvent(data: {[key: string]: string | number | null}) {
|
|
283
|
+
await post({url: API_TRACK_EVENT, data: {event: data}});
|
|
284
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as api from "@/logic/api";
|
|
2
|
+
import type * as t from "@/logic/types";
|
|
3
|
+
|
|
4
|
+
export async function newsLinkOpened({entryId}: {entryId: t.EntryId}) {
|
|
5
|
+
await api.trackEvent({name: "news_link_opened", entry_id: entryId});
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export async function newsBodyOpened({entryId}: {entryId: t.EntryId}) {
|
|
9
|
+
await api.trackEvent({name: "news_body_opened", entry_id: entryId});
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function socialLinkClicked({linkType}: {linkType: string}) {
|
|
13
|
+
await api.trackEvent({name: "social_link_clicked", link_type: linkType});
|
|
14
|
+
}
|
package/src/stores/feeds.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {computed, ref, watch} from "vue";
|
|
1
|
+
import {computed, ref, watch, triggerRef} from "vue";
|
|
2
2
|
import {useRouter} from "vue-router";
|
|
3
3
|
import {defineStore} from "pinia";
|
|
4
4
|
|
|
@@ -30,19 +30,25 @@ export const useFeedsStore = defineStore("feedsStore", () => {
|
|
|
30
30
|
async function unsubscribe(feedId: t.FeedId) {
|
|
31
31
|
await api.unsubscribe({feedId: feedId});
|
|
32
32
|
|
|
33
|
-
// Attention, do not
|
|
33
|
+
// Attention, do not update globalSettings.updateDataVersion here
|
|
34
34
|
// it cause a lot of unnecessary requests to the server without any benefit
|
|
35
35
|
// we just remove feed from frontend
|
|
36
36
|
|
|
37
37
|
delete feeds.value[feedId];
|
|
38
|
+
|
|
39
|
+
triggerRef(feeds);
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
async function subscribe(url: t.URL) {
|
|
41
|
-
await api.addFeed({
|
|
43
|
+
const newFeed = await api.addFeed({
|
|
42
44
|
url: url
|
|
43
45
|
});
|
|
44
46
|
|
|
45
|
-
globalSettings.updateDataVersion()
|
|
47
|
+
// Attention, do not update globalSettings.updateDataVersion here (see above)
|
|
48
|
+
|
|
49
|
+
feeds.value[newFeed.id] = newFeed;
|
|
50
|
+
|
|
51
|
+
triggerRef(feeds);
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
return {
|
package/tsconfig.app.json
CHANGED
package/tsconfig.node.json
CHANGED