feeds-fun 0.1.0 → 0.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/README.md +2 -0
- package/package.json +2 -1
- package/src/components/RulesList.vue +3 -1
- package/src/components/TagsFilter.vue +20 -0
- package/src/logic/enums.ts +14 -0
- package/src/logic/types.ts +9 -3
- package/src/logic/utils.ts +20 -0
- package/src/stores/globalSettings.ts +5 -1
- package/src/views/RulesView.vue +66 -3
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
@tag:deselected="onTagDeselected" />
|
|
14
14
|
</ul>
|
|
15
15
|
|
|
16
|
+
<input
|
|
17
|
+
type="text"
|
|
18
|
+
placeholder="Input part of tag..."
|
|
19
|
+
v-model="tagNameFilter" />
|
|
20
|
+
|
|
16
21
|
<ul
|
|
17
22
|
v-if="displayedTags.length > 0"
|
|
18
23
|
style="list-style: none; padding: 0; margin: 0">
|
|
@@ -39,6 +44,9 @@
|
|
|
39
44
|
|
|
40
45
|
<script lang="ts" setup>
|
|
41
46
|
import {computed, ref} from "vue";
|
|
47
|
+
import {useTagsStore} from "@/stores/tags";
|
|
48
|
+
|
|
49
|
+
const tagsStore = useTagsStore();
|
|
42
50
|
|
|
43
51
|
const selectedTags = ref<{[key: string]: boolean}>({});
|
|
44
52
|
|
|
@@ -48,6 +56,8 @@
|
|
|
48
56
|
|
|
49
57
|
const showEntries = ref(showFromStart.value);
|
|
50
58
|
|
|
59
|
+
const tagNameFilter = ref("");
|
|
60
|
+
|
|
51
61
|
function tagComparator(a: string, b: string) {
|
|
52
62
|
const aCount = properties.tags[a];
|
|
53
63
|
const bCount = properties.tags[b];
|
|
@@ -101,6 +111,16 @@
|
|
|
101
111
|
return selectedTags.value[tag] !== true;
|
|
102
112
|
});
|
|
103
113
|
|
|
114
|
+
values = values.filter((tag) => {
|
|
115
|
+
const tagInfo = tagsStore.tags[tag];
|
|
116
|
+
|
|
117
|
+
if (tagInfo === undefined || tagInfo.name === null) {
|
|
118
|
+
return tag.includes(tagNameFilter.value);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return tagInfo.name.includes(tagNameFilter.value);
|
|
122
|
+
});
|
|
123
|
+
|
|
104
124
|
values.sort(tagComparator);
|
|
105
125
|
|
|
106
126
|
values = values.slice(0, showEntries.value);
|
package/src/logic/enums.ts
CHANGED
|
@@ -90,3 +90,17 @@ export const FeedsOrderProperties = new Map<FeedsOrder, {text: string; orderFiel
|
|
|
90
90
|
[FeedsOrder.Loaded, {text: "loaded", orderField: "loadedAt", orderDirection: "desc"}],
|
|
91
91
|
[FeedsOrder.Linked, {text: "added", orderField: "linkedAt", orderDirection: "desc"}]
|
|
92
92
|
]);
|
|
93
|
+
|
|
94
|
+
export enum RulesOrder {
|
|
95
|
+
Tags = "tags",
|
|
96
|
+
Score = "score",
|
|
97
|
+
Created = "created",
|
|
98
|
+
Updated = "updated"
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export const RulesOrderProperties = new Map<RulesOrder, {text: string; orderField: string; orderDirection: string}>([
|
|
102
|
+
[RulesOrder.Tags, {text: "tags", orderField: "tags", orderDirection: "asc"}],
|
|
103
|
+
[RulesOrder.Score, {text: "score", orderField: "score", orderDirection: "desc"}],
|
|
104
|
+
[RulesOrder.Created, {text: "created", orderField: "createdAt", orderDirection: "desc"}],
|
|
105
|
+
[RulesOrder.Updated, {text: "updated", orderField: "updatedAt", orderDirection: "desc"}]
|
|
106
|
+
]);
|
package/src/logic/types.ts
CHANGED
|
@@ -221,24 +221,30 @@ export type Rule = {
|
|
|
221
221
|
readonly tags: string[];
|
|
222
222
|
readonly score: number;
|
|
223
223
|
readonly createdAt: Date;
|
|
224
|
+
readonly updatedAt: Date;
|
|
224
225
|
};
|
|
225
226
|
|
|
226
227
|
export function ruleFromJSON({
|
|
227
228
|
id,
|
|
228
229
|
tags,
|
|
229
230
|
score,
|
|
230
|
-
createdAt
|
|
231
|
+
createdAt,
|
|
232
|
+
updatedAt
|
|
231
233
|
}: {
|
|
232
234
|
id: string;
|
|
233
235
|
tags: string[];
|
|
234
236
|
score: number;
|
|
235
237
|
createdAt: string;
|
|
238
|
+
updatedAt: string;
|
|
236
239
|
}): Rule {
|
|
240
|
+
tags = tags.sort();
|
|
241
|
+
|
|
237
242
|
return {
|
|
238
243
|
id: toRuleId(id),
|
|
239
244
|
tags: tags,
|
|
240
245
|
score: score,
|
|
241
|
-
createdAt: new Date(createdAt)
|
|
246
|
+
createdAt: new Date(createdAt),
|
|
247
|
+
updatedAt: new Date(updatedAt)
|
|
242
248
|
};
|
|
243
249
|
}
|
|
244
250
|
|
|
@@ -311,7 +317,7 @@ export function tagInfoFromJSON({
|
|
|
311
317
|
}
|
|
312
318
|
|
|
313
319
|
export function noInfoTag(uid: string): TagInfo {
|
|
314
|
-
return {uid, name:
|
|
320
|
+
return {uid, name: uid, link: null, categories: []};
|
|
315
321
|
}
|
|
316
322
|
|
|
317
323
|
export type UserSetting = {
|
package/src/logic/utils.ts
CHANGED
|
@@ -37,3 +37,23 @@ export function timeSince(date: Date) {
|
|
|
37
37
|
|
|
38
38
|
return `${yearsPast}y`;
|
|
39
39
|
}
|
|
40
|
+
|
|
41
|
+
export function compareLexicographically(a: string[], b: string[]) {
|
|
42
|
+
for (let i = 0; i < Math.min(a.length, b.length); i++) {
|
|
43
|
+
const comparison = a[i].localeCompare(b[i]);
|
|
44
|
+
|
|
45
|
+
if (comparison !== 0) {
|
|
46
|
+
return comparison;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (a.length > b.length) {
|
|
51
|
+
return 1;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (a.length < b.length) {
|
|
55
|
+
return -1;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return 0;
|
|
59
|
+
}
|
|
@@ -26,6 +26,9 @@ export const useGlobalSettingsStore = defineStore("globalSettings", () => {
|
|
|
26
26
|
const feedsOrder = ref(e.FeedsOrder.Title);
|
|
27
27
|
const failedFeedsFirst = ref(false);
|
|
28
28
|
|
|
29
|
+
// Rules
|
|
30
|
+
const rulesOrder = ref(e.RulesOrder.Tags);
|
|
31
|
+
|
|
29
32
|
watch(mainPanelMode, (newValue, oldValue) => {
|
|
30
33
|
router.push({name: mainPanelMode.value, params: {}});
|
|
31
34
|
});
|
|
@@ -69,6 +72,7 @@ export const useGlobalSettingsStore = defineStore("globalSettings", () => {
|
|
|
69
72
|
userSettings,
|
|
70
73
|
info,
|
|
71
74
|
feedsOrder,
|
|
72
|
-
failedFeedsFirst
|
|
75
|
+
failedFeedsFirst,
|
|
76
|
+
rulesOrder
|
|
73
77
|
};
|
|
74
78
|
});
|
package/src/views/RulesView.vue
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<side-panel-layout :reload-button="
|
|
2
|
+
<side-panel-layout :reload-button="true">
|
|
3
3
|
<template #main-header>
|
|
4
4
|
Rules
|
|
5
5
|
<span v-if="rules">[{{ rules.length }}]</span>
|
|
6
6
|
</template>
|
|
7
7
|
|
|
8
|
+
<template #side-menu-item-2>
|
|
9
|
+
Sorted by
|
|
10
|
+
<config-selector
|
|
11
|
+
:values="e.RulesOrderProperties"
|
|
12
|
+
v-model:property="globalSettings.rulesOrder" />
|
|
13
|
+
</template>
|
|
14
|
+
|
|
8
15
|
<rules-list
|
|
9
16
|
v-if="rules"
|
|
10
|
-
:rules="
|
|
17
|
+
:rules="sortedRules" />
|
|
11
18
|
</side-panel-layout>
|
|
12
19
|
</template>
|
|
13
20
|
|
|
@@ -15,8 +22,10 @@
|
|
|
15
22
|
import {computed, ref, onUnmounted, watch} from "vue";
|
|
16
23
|
import {computedAsync} from "@vueuse/core";
|
|
17
24
|
import {useGlobalSettingsStore} from "@/stores/globalSettings";
|
|
25
|
+
import _ from "lodash";
|
|
26
|
+
import * as utils from "@/logic/utils";
|
|
18
27
|
import * as api from "@/logic/api";
|
|
19
|
-
import * as t from "@/logic/types";
|
|
28
|
+
import type * as t from "@/logic/types";
|
|
20
29
|
import * as e from "@/logic/enums";
|
|
21
30
|
|
|
22
31
|
const globalSettings = useGlobalSettingsStore();
|
|
@@ -28,6 +37,60 @@
|
|
|
28
37
|
globalSettings.dataVersion;
|
|
29
38
|
return await api.getRules();
|
|
30
39
|
}, null);
|
|
40
|
+
|
|
41
|
+
const sortedRules = computed(() => {
|
|
42
|
+
if (!rules.value) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const orderProperties = e.RulesOrderProperties.get(globalSettings.rulesOrder);
|
|
47
|
+
|
|
48
|
+
if (!orderProperties) {
|
|
49
|
+
throw new Error(`Invalid order properties: ${globalSettings.rulesOrder}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const orderField = orderProperties.orderField;
|
|
53
|
+
const direction = {asc: -1, desc: 1}[orderProperties.orderDirection];
|
|
54
|
+
|
|
55
|
+
if (direction === undefined) {
|
|
56
|
+
throw new Error(`Invalid order direction: ${orderProperties.orderDirection}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
let sorted = rules.value.slice();
|
|
60
|
+
|
|
61
|
+
sorted = sorted.sort((a: t.Rule, b: t.Rule) => {
|
|
62
|
+
if (globalSettings.rulesOrder === e.RulesOrder.Tags) {
|
|
63
|
+
return utils.compareLexicographically(a.tags, b.tags);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const valueA = _.get(a, orderField, null);
|
|
67
|
+
const valueB = _.get(b, orderField, null);
|
|
68
|
+
|
|
69
|
+
if (valueA === null && valueB === null) {
|
|
70
|
+
return 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (valueA === null) {
|
|
74
|
+
return 1 * direction;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (valueB === null) {
|
|
78
|
+
return -1 * direction;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (valueA < valueB) {
|
|
82
|
+
return 1 * direction;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (valueA > valueB) {
|
|
86
|
+
return -1 * direction;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return 0;
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
return sorted;
|
|
93
|
+
});
|
|
31
94
|
</script>
|
|
32
95
|
|
|
33
96
|
<style></style>
|