feeds-fun 1.16.2 → 1.16.4
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/EntryForList.vue +40 -12
- package/src/inputs/Marker.vue +8 -20
- package/src/stores/entries.ts +32 -3
- package/src/style.css +1 -1
- package/src/values/Score.vue +2 -1
- package/src/views/DiscoveryView.vue +1 -1
- package/src/views/NewsView.vue +10 -1
package/package.json
CHANGED
|
@@ -2,7 +2,30 @@
|
|
|
2
2
|
<div
|
|
3
3
|
ref="entryTop"
|
|
4
4
|
class="flex text-lg">
|
|
5
|
-
<div class="flex-shrink-0
|
|
5
|
+
<div :class="['flex-shrink-0', 'text-right', {'ml-8': isRead}]">
|
|
6
|
+
<input-marker
|
|
7
|
+
class="w-7 mr-2"
|
|
8
|
+
:marker="e.Marker.Read"
|
|
9
|
+
:entry-id="entryId">
|
|
10
|
+
<template v-slot:marked>
|
|
11
|
+
<span
|
|
12
|
+
class="text-green-700 no-underline"
|
|
13
|
+
title="Mark as unread">
|
|
14
|
+
<i class="ti ti-chevrons-left" />
|
|
15
|
+
</span>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<template v-slot:unmarked>
|
|
19
|
+
<span
|
|
20
|
+
class="text-orange-700 no-underline"
|
|
21
|
+
title="Mark as read">
|
|
22
|
+
<i class="ti ti-chevrons-right" />
|
|
23
|
+
</span>
|
|
24
|
+
</template>
|
|
25
|
+
</input-marker>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div class="flex-shrink-0 w-8 text-center pr-1">
|
|
6
29
|
<value-score
|
|
7
30
|
:value="entry.score"
|
|
8
31
|
:entry-id="entry.id" />
|
|
@@ -14,15 +37,6 @@
|
|
|
14
37
|
class="w-5 h-5 align-text-bottom mx-1 inline" />
|
|
15
38
|
</div>
|
|
16
39
|
|
|
17
|
-
<div class="flex-shrink-0 text-right">
|
|
18
|
-
<input-marker
|
|
19
|
-
class="w-7 mr-2"
|
|
20
|
-
:marker="e.Marker.Read"
|
|
21
|
-
:entry-id="entryId"
|
|
22
|
-
on-text="read"
|
|
23
|
-
off-text="new" />
|
|
24
|
-
</div>
|
|
25
|
-
|
|
26
40
|
<div class="flex-grow">
|
|
27
41
|
<a
|
|
28
42
|
:href="entry.url"
|
|
@@ -73,7 +87,7 @@
|
|
|
73
87
|
|
|
74
88
|
<script lang="ts" setup>
|
|
75
89
|
import _ from "lodash";
|
|
76
|
-
import {computed, ref, useTemplateRef} from "vue";
|
|
90
|
+
import {computed, ref, useTemplateRef, onMounted} from "vue";
|
|
77
91
|
import type * as t from "@/logic/types";
|
|
78
92
|
import * as events from "@/logic/events";
|
|
79
93
|
import * as e from "@/logic/enums";
|
|
@@ -156,11 +170,25 @@
|
|
|
156
170
|
await entriesStore.displayEntry({entryId: entry.value.id});
|
|
157
171
|
|
|
158
172
|
if (topElement.value) {
|
|
159
|
-
topElement.value.
|
|
173
|
+
const rect = topElement.value.getBoundingClientRect();
|
|
174
|
+
|
|
175
|
+
const isVisible =
|
|
176
|
+
rect.top >= 0 &&
|
|
177
|
+
rect.left >= 0 &&
|
|
178
|
+
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
|
|
179
|
+
rect.right <= (window.innerWidth || document.documentElement.clientWidth);
|
|
180
|
+
|
|
181
|
+
if (!isVisible) {
|
|
182
|
+
topElement.value.scrollIntoView({behavior: "instant"});
|
|
183
|
+
}
|
|
160
184
|
}
|
|
161
185
|
}
|
|
162
186
|
} else {
|
|
163
187
|
await newsLinkOpenedEvent();
|
|
164
188
|
}
|
|
165
189
|
}
|
|
190
|
+
|
|
191
|
+
onMounted(() => {
|
|
192
|
+
entriesStore.requestFullEntry({entryId: properties.entryId});
|
|
193
|
+
});
|
|
166
194
|
</script>
|
package/src/inputs/Marker.vue
CHANGED
|
@@ -3,19 +3,17 @@
|
|
|
3
3
|
<template v-if="hasMarker">
|
|
4
4
|
<a
|
|
5
5
|
href="#"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
>
|
|
6
|
+
@click.prevent="unmark()">
|
|
7
|
+
<slot name="marked" />
|
|
8
|
+
</a>
|
|
10
9
|
</template>
|
|
11
10
|
|
|
12
11
|
<template v-else>
|
|
13
12
|
<a
|
|
14
13
|
href="#"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
>
|
|
14
|
+
@click.prevent="mark()">
|
|
15
|
+
<slot name="unmarked" />
|
|
16
|
+
</a>
|
|
19
17
|
</template>
|
|
20
18
|
</div>
|
|
21
19
|
</template>
|
|
@@ -23,7 +21,7 @@
|
|
|
23
21
|
<script lang="ts" setup>
|
|
24
22
|
import {computed, ref} from "vue";
|
|
25
23
|
import * as api from "@/logic/api";
|
|
26
|
-
import
|
|
24
|
+
import * as e from "@/logic/enums";
|
|
27
25
|
import type * as t from "@/logic/types";
|
|
28
26
|
import {useEntriesStore} from "@/stores/entries";
|
|
29
27
|
|
|
@@ -32,8 +30,6 @@
|
|
|
32
30
|
const properties = defineProps<{
|
|
33
31
|
marker: e.Marker;
|
|
34
32
|
entryId: t.EntryId;
|
|
35
|
-
onText: string;
|
|
36
|
-
offText: string;
|
|
37
33
|
}>();
|
|
38
34
|
|
|
39
35
|
const hasMarker = computed(() => {
|
|
@@ -55,12 +51,4 @@
|
|
|
55
51
|
}
|
|
56
52
|
</script>
|
|
57
53
|
|
|
58
|
-
<style scoped>
|
|
59
|
-
.marked {
|
|
60
|
-
@apply text-green-700 no-underline;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
.unmarked {
|
|
64
|
-
@apply text-orange-700 font-bold no-underline;
|
|
65
|
-
}
|
|
66
|
-
</style>
|
|
54
|
+
<style scoped></style>
|
package/src/stores/entries.ts
CHANGED
|
@@ -16,6 +16,9 @@ export const useEntriesStore = defineStore("entriesStore", () => {
|
|
|
16
16
|
const entries = ref<{[key: t.EntryId]: t.Entry}>({});
|
|
17
17
|
const requestedEntries = ref<{[key: t.EntryId]: boolean}>({});
|
|
18
18
|
const displayedEntryId = ref<t.EntryId | null>(null);
|
|
19
|
+
const readHistory = ref<t.EntryId[]>([]);
|
|
20
|
+
|
|
21
|
+
const canUndoMarkRead = computed(() => readHistory.value.length > 0);
|
|
19
22
|
|
|
20
23
|
function registerEntry(entry: t.Entry) {
|
|
21
24
|
if (entry.id in entries.value) {
|
|
@@ -82,19 +85,33 @@ export const useEntriesStore = defineStore("entriesStore", () => {
|
|
|
82
85
|
requestedEntriesTimer.start();
|
|
83
86
|
|
|
84
87
|
async function setMarker({entryId, marker}: {entryId: t.EntryId; marker: e.Marker}) {
|
|
85
|
-
|
|
88
|
+
if (marker === e.Marker.Read) {
|
|
89
|
+
readHistory.value.push(entryId);
|
|
90
|
+
}
|
|
86
91
|
|
|
92
|
+
// This code must be before the actual API request
|
|
93
|
+
// to guarantee smooth UI transition to the new state
|
|
94
|
+
// otherwise the UI will be updated two times which leads to flickering
|
|
87
95
|
if (entryId in entries.value) {
|
|
88
96
|
entries.value[entryId].setMarker(marker);
|
|
89
97
|
}
|
|
98
|
+
|
|
99
|
+
await api.setMarker({entryId: entryId, marker: marker});
|
|
90
100
|
}
|
|
91
101
|
|
|
92
102
|
async function removeMarker({entryId, marker}: {entryId: t.EntryId; marker: e.Marker}) {
|
|
93
|
-
|
|
103
|
+
if (marker === e.Marker.Read) {
|
|
104
|
+
_.pull(readHistory.value, entryId);
|
|
105
|
+
|
|
106
|
+
hideEntry({entryId: entryId});
|
|
107
|
+
}
|
|
94
108
|
|
|
109
|
+
// This code must be before the actual API request, see comment above
|
|
95
110
|
if (entryId in entries.value) {
|
|
96
111
|
entries.value[entryId].removeMarker(marker);
|
|
97
112
|
}
|
|
113
|
+
|
|
114
|
+
await api.removeMarker({entryId: entryId, marker: marker});
|
|
98
115
|
}
|
|
99
116
|
|
|
100
117
|
async function displayEntry({entryId}: {entryId: t.EntryId}) {
|
|
@@ -118,6 +135,16 @@ export const useEntriesStore = defineStore("entriesStore", () => {
|
|
|
118
135
|
}
|
|
119
136
|
}
|
|
120
137
|
|
|
138
|
+
function undoMarkRead() {
|
|
139
|
+
if (readHistory.value.length === 0) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const entryId = readHistory.value.pop() as t.EntryId;
|
|
144
|
+
|
|
145
|
+
removeMarker({entryId: entryId, marker: e.Marker.Read});
|
|
146
|
+
}
|
|
147
|
+
|
|
121
148
|
return {
|
|
122
149
|
entries,
|
|
123
150
|
requestFullEntry,
|
|
@@ -126,6 +153,8 @@ export const useEntriesStore = defineStore("entriesStore", () => {
|
|
|
126
153
|
loadedEntriesReport,
|
|
127
154
|
displayedEntryId,
|
|
128
155
|
displayEntry,
|
|
129
|
-
hideEntry
|
|
156
|
+
hideEntry,
|
|
157
|
+
undoMarkRead,
|
|
158
|
+
canUndoMarkRead
|
|
130
159
|
};
|
|
131
160
|
});
|
package/src/style.css
CHANGED
package/src/values/Score.vue
CHANGED
package/src/views/NewsView.vue
CHANGED
|
@@ -15,12 +15,21 @@
|
|
|
15
15
|
</template>
|
|
16
16
|
|
|
17
17
|
<template #side-menu-item-3>
|
|
18
|
-
Show read
|
|
18
|
+
Show read
|
|
19
|
+
|
|
19
20
|
<config-flag
|
|
20
21
|
style="min-width: 2.5rem"
|
|
21
22
|
v-model:flag="globalSettings.showRead"
|
|
22
23
|
on-text="no"
|
|
23
24
|
off-text="yes" />
|
|
25
|
+
|
|
26
|
+
<button
|
|
27
|
+
class="ffun-form-button py-0 ml-1"
|
|
28
|
+
title='Undo last "mark read" operation'
|
|
29
|
+
:disabled="!entriesStore.canUndoMarkRead"
|
|
30
|
+
@click="entriesStore.undoMarkRead()">
|
|
31
|
+
↶
|
|
32
|
+
</button>
|
|
24
33
|
</template>
|
|
25
34
|
|
|
26
35
|
<template #side-footer>
|