feeds-fun 1.15.0 → 1.16.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.
@@ -15,15 +15,6 @@
15
15
  </template>
16
16
 
17
17
  <template #side-menu-item-3>
18
- Show tags:
19
- <config-flag
20
- style="min-width: 2.5rem"
21
- v-model:flag="globalSettings.showEntriesTags"
22
- on-text="no"
23
- off-text="yes" />
24
- </template>
25
-
26
- <template #side-menu-item-4>
27
18
  Show read:
28
19
  <config-flag
29
20
  style="min-width: 2.5rem"
@@ -35,7 +26,7 @@
35
26
  <template #side-footer>
36
27
  <tags-filter
37
28
  :tags="tagsCount"
38
- @tag:stateChanged="onTagStateChanged" />
29
+ :show-create-rule="true" />
39
30
  </template>
40
31
 
41
32
  <template #main-header>
@@ -55,16 +46,14 @@
55
46
  <entries-list
56
47
  :entriesIds="entriesReport"
57
48
  :time-field="timeField"
58
- :show-tags="globalSettings.showEntriesTags"
59
49
  :tags-count="tagsCount"
60
50
  :showFromStart="25"
61
- :showPerPage="25"
62
- @entry:bodyVisibilityChanged="onBodyVisibilityChanged" />
51
+ :showPerPage="25" />
63
52
  </side-panel-layout>
64
53
  </template>
65
54
 
66
55
  <script lang="ts" setup>
67
- import {computed, ref, onUnmounted, watch} from "vue";
56
+ import {computed, ref, onUnmounted, watch, provide} from "vue";
68
57
  import {computedAsync} from "@vueuse/core";
69
58
  import * as api from "@/logic/api";
70
59
  import * as tagsFilterState from "@/logic/tagsFilterState";
@@ -79,67 +68,86 @@
79
68
 
80
69
  const tagsStates = ref<tagsFilterState.Storage>(new tagsFilterState.Storage());
81
70
 
71
+ provide("tagsStates", tagsStates);
72
+
82
73
  globalSettings.mainPanelMode = e.MainPanelMode.Entries;
83
74
 
84
75
  globalSettings.updateDataVersion();
85
76
 
86
77
  const entriesWithOpenedBody = ref<{[key: t.EntryId]: boolean}>({});
87
78
 
88
- const entriesReport = computed(() => {
79
+ const _sortedEntries = computed(() => {
89
80
  if (entriesStore.loadedEntriesReport === null) {
90
81
  return [];
91
82
  }
92
83
 
93
- let report = entriesStore.loadedEntriesReport.slice();
84
+ const orderProperties = e.EntriesOrderProperties.get(globalSettings.entriesOrder);
94
85
 
95
- if (!globalSettings.showRead) {
96
- report = report.filter((entryId) => {
97
- if (entriesWithOpenedBody.value[entryId]) {
98
- // always show read entries with open body
99
- // otherwise, they will hide right after opening it
100
- return true;
101
- }
102
- return !entriesStore.entries[entryId].hasMarker(e.Marker.Read);
103
- });
86
+ if (orderProperties === undefined) {
87
+ throw new Error(`Unknown order ${globalSettings.entriesOrder}`);
104
88
  }
105
89
 
106
- report = tagsStates.value.filterByTags(report, (entryId) => entriesStore.entries[entryId].tags);
107
-
108
- report = report.sort((a: t.EntryId, b: t.EntryId) => {
109
- const orderProperties = e.EntriesOrderProperties.get(globalSettings.entriesOrder);
90
+ const field = orderProperties.orderField;
91
+ const direction = orderProperties.direction;
110
92
 
111
- if (orderProperties === undefined) {
112
- throw new Error(`Unknown order ${globalSettings.entriesOrder}`);
113
- }
93
+ // let report = entriesStore.loadedEntriesReport.slice();
114
94
 
115
- const field = orderProperties.orderField;
116
-
117
- const valueA = _.get(entriesStore.entries[a], field, null);
118
- const valueB = _.get(entriesStore.entries[b], field, null);
95
+ // Pre-map to avoid repeated lookups in the comparator
96
+ const mapped = entriesStore.loadedEntriesReport.map((entryId) => {
97
+ // @ts-ignore
98
+ return {entryId, value: entriesStore.entries[entryId][field]};
99
+ });
119
100
 
120
- if (valueA === null && valueB === null) {
101
+ mapped.sort((a: {entryId: t.EntryId; value: any}, b: {entryId: t.EntryId; value: any}) => {
102
+ if (a.value === null && b.value === null) {
121
103
  return 0;
122
104
  }
123
105
 
124
- if (valueA === null) {
106
+ if (a.value === null) {
125
107
  return 1;
126
108
  }
127
109
 
128
- if (valueB === null) {
110
+ if (b.value === null) {
129
111
  return -1;
130
112
  }
131
113
 
132
- if (valueA < valueB) {
133
- return orderProperties.direction;
114
+ if (a.value < b.value) {
115
+ return direction;
134
116
  }
135
117
 
136
- if (valueA > valueB) {
137
- return -orderProperties.direction;
118
+ if (a.value > b.value) {
119
+ return -direction;
138
120
  }
139
121
 
140
122
  return 0;
141
123
  });
142
124
 
125
+ const report = mapped.map((x) => x.entryId);
126
+
127
+ return report;
128
+ });
129
+
130
+ const _visibleEntries = computed(() => {
131
+ let report = _sortedEntries.value.slice();
132
+
133
+ if (!globalSettings.showRead) {
134
+ report = report.filter((entryId) => {
135
+ if (entriesStore.displayedEntryId == entryId) {
136
+ // always show read entries with open body
137
+ // otherwise, they will hide right after opening it
138
+ return true;
139
+ }
140
+ return !entriesStore.entries[entryId].hasMarker(e.Marker.Read);
141
+ });
142
+ }
143
+
144
+ return report;
145
+ });
146
+
147
+ const entriesReport = computed(() => {
148
+ let report = _visibleEntries.value.slice();
149
+
150
+ report = tagsStates.value.filterByTags(report, (entryId) => entriesStore.entries[entryId].tags);
143
151
  return report;
144
152
  });
145
153
 
@@ -193,14 +201,6 @@
193
201
 
194
202
  return orderProperties.timeField;
195
203
  });
196
-
197
- function onTagStateChanged({tag, state}: {tag: string; state: tagsFilterState.State}) {
198
- tagsStates.value.onTagStateChanged({tag, state});
199
- }
200
-
201
- function onBodyVisibilityChanged({entryId, visible}: {entryId: t.EntryId; visible: boolean}) {
202
- entriesWithOpenedBody.value[entryId] = visible;
203
- }
204
204
  </script>
205
205
 
206
206
  <style></style>
@@ -13,11 +13,21 @@
13
13
  </template>
14
14
 
15
15
  <template #side-footer>
16
- <tags-filter
17
- :tags="tags"
18
- @tag:stateChanged="onTagStateChanged" />
16
+ <tags-filter :tags="tagsCount" />
19
17
  </template>
20
18
 
19
+ <div class="ffun-info-good">
20
+ <p
21
+ >You can create new rules on the
22
+ <a
23
+ href="#"
24
+ @click.prevent="goToNews()"
25
+ >news</a
26
+ >
27
+ tab.</p
28
+ >
29
+ </div>
30
+
21
31
  <rules-list
22
32
  v-if="rules"
23
33
  :rules="sortedRules" />
@@ -25,7 +35,8 @@
25
35
  </template>
26
36
 
27
37
  <script lang="ts" setup>
28
- import {computed, ref, onUnmounted, watch} from "vue";
38
+ import {computed, ref, onUnmounted, watch, provide} from "vue";
39
+ import {useRouter} from "vue-router";
29
40
  import {computedAsync} from "@vueuse/core";
30
41
  import {useGlobalSettingsStore} from "@/stores/globalSettings";
31
42
  import _ from "lodash";
@@ -34,19 +45,28 @@
34
45
  import type * as t from "@/logic/types";
35
46
  import * as e from "@/logic/enums";
36
47
  import * as tagsFilterState from "@/logic/tagsFilterState";
48
+
49
+ const router = useRouter();
50
+
37
51
  const tagsStates = ref<tagsFilterState.Storage>(new tagsFilterState.Storage());
38
52
 
53
+ provide("tagsStates", tagsStates);
54
+
39
55
  const globalSettings = useGlobalSettingsStore();
40
56
 
41
57
  globalSettings.mainPanelMode = e.MainPanelMode.Rules;
42
58
 
59
+ function goToNews() {
60
+ router.push({name: e.MainPanelMode.Entries, params: {}});
61
+ }
62
+
43
63
  const rules = computedAsync(async () => {
44
64
  // force refresh
45
65
  globalSettings.dataVersion;
46
66
  return await api.getRules();
47
67
  }, null);
48
68
 
49
- const tags = computed(() => {
69
+ const tagsCount = computed(() => {
50
70
  if (!rules.value) {
51
71
  return {};
52
72
  }
@@ -54,7 +74,11 @@
54
74
  const tags: {[key: string]: number} = {};
55
75
 
56
76
  for (const rule of rules.value) {
57
- for (const tag of rule.tags) {
77
+ for (const tag of rule.requiredTags) {
78
+ tags[tag] = (tags[tag] || 0) + 1;
79
+ }
80
+
81
+ for (const tag of rule.excludedTags) {
58
82
  tags[tag] = (tags[tag] || 0) + 1;
59
83
  }
60
84
  }
@@ -69,7 +93,7 @@
69
93
 
70
94
  let sorted = rules.value.slice();
71
95
 
72
- sorted = tagsStates.value.filterByTags(sorted, (rule) => rule.tags);
96
+ sorted = tagsStates.value.filterByTags(sorted, (rule) => rule.requiredTags.concat(rule.excludedTags));
73
97
 
74
98
  const orderProperties = e.RulesOrderProperties.get(globalSettings.rulesOrder);
75
99
 
@@ -86,14 +110,14 @@
86
110
 
87
111
  sorted = sorted.sort((a: t.Rule, b: t.Rule) => {
88
112
  if (globalSettings.rulesOrder === e.RulesOrder.Tags) {
89
- return utils.compareLexicographically(a.tags, b.tags);
113
+ return utils.compareLexicographically(a.allTags, b.allTags);
90
114
  }
91
115
 
92
116
  const valueA = _.get(a, orderField, null);
93
117
  const valueB = _.get(b, orderField, null);
94
118
 
95
119
  if (valueA === null && valueB === null) {
96
- return utils.compareLexicographically(a.tags, b.tags);
120
+ return utils.compareLexicographically(a.allTags, b.allTags);
97
121
  }
98
122
 
99
123
  if (valueA === null) {
@@ -112,13 +136,9 @@
112
136
  return -1 * direction;
113
137
  }
114
138
 
115
- return utils.compareLexicographically(a.tags, b.tags);
139
+ return utils.compareLexicographically(a.allTags, b.allTags);
116
140
  });
117
141
 
118
142
  return sorted;
119
143
  });
120
-
121
- function onTagStateChanged({tag, state}: {tag: string; state: tagsFilterState.State}) {
122
- tagsStates.value.onTagStateChanged({tag, state});
123
- }
124
144
  </script>