feeds-fun 1.16.6 → 1.17.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 +3 -5
- package/src/components/EntriesList.vue +1 -11
- package/src/components/EntryForList.vue +54 -67
- package/src/components/FeedForList.vue +29 -64
- package/src/components/FeedInfo.vue +12 -14
- package/src/components/FeedsList.vue +2 -1
- package/src/components/OPMLUpload.vue +3 -3
- package/src/components/RuleConstructor.vue +12 -6
- package/src/components/RuleForList.vue +25 -24
- package/src/components/RulesList.vue +2 -1
- package/src/components/SimplePagination.vue +2 -2
- package/src/components/SupertokensLogin.vue +5 -6
- package/src/components/UserSetting.vue +7 -12
- package/src/components/UserSettingForNotification.vue +4 -3
- package/src/components/body_list/EntryBody.vue +43 -0
- package/src/components/body_list/FaviconColumn.vue +24 -0
- package/src/components/body_list/ReverseTimeColumn.vue +28 -0
- package/src/components/collections/Block.vue +1 -1
- package/src/components/collections/BlockItem.vue +4 -3
- package/src/components/collections/DetailedItem.vue +4 -10
- package/src/components/collections/FeedItem.vue +31 -24
- package/src/components/collections/Notification.vue +6 -8
- package/src/components/collections/SubscribingProgress.vue +14 -17
- package/src/components/collections/Warning.vue +36 -38
- package/src/components/main/Block.vue +5 -0
- package/src/components/main/Description.vue +51 -0
- package/src/components/main/HeaderLine.vue +7 -0
- package/src/components/main/Item.vue +27 -0
- package/src/components/main/NewsTitle.vue +26 -0
- package/src/components/notifications/ApiKey.vue +14 -5
- package/src/components/notifications/CreateRuleHelp.vue +10 -11
- package/src/components/page_header/ExternalLinks.vue +58 -0
- package/src/components/tags/Base.vue +28 -0
- package/src/components/tags/EntryTag.vue +73 -0
- package/src/components/{TagsList.vue → tags/EntryTagsList.vue} +8 -10
- package/src/components/tags/FakeTag.vue +35 -0
- package/src/components/{FfunTag.vue → tags/FilterTag.vue} +36 -52
- package/src/components/tags/RuleTag.vue +67 -0
- package/src/components/{TagsFilter.vue → tags/TagsFilter.vue} +12 -8
- package/src/css/base.css +38 -0
- package/src/css/inputs.css +49 -0
- package/src/css/page_header.css +34 -0
- package/src/css/panels.css +49 -0
- package/src/css/side_panel_layout.css +34 -0
- package/src/css/tags.css +44 -0
- package/src/layouts/SidePanelLayout.vue +35 -91
- package/src/layouts/WideLayout.vue +5 -17
- package/src/logic/events.ts +1 -1
- package/src/logic/types.ts +16 -7
- package/src/logic/utils.ts +29 -0
- package/src/main.ts +42 -10
- package/src/style.css +10 -100
- package/src/values/DateTime.vue +1 -1
- package/src/values/{URL.vue → ExternalUrl.vue} +7 -6
- package/src/views/CollectionsView.vue +3 -6
- package/src/views/DiscoveryView.vue +9 -11
- package/src/views/FeedsView.vue +3 -2
- package/src/views/MainView.vue +189 -44
- package/src/views/NewsView.vue +2 -1
- package/src/views/RulesView.vue +6 -3
- package/src/views/SettingsView.vue +92 -33
- package/src/inputs/Marker.vue +0 -54
package/package.json
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
<p
|
|
20
20
|
v-if="searching"
|
|
21
|
-
class="ffun-info-
|
|
21
|
+
class="ffun-info-waiting mt-2"
|
|
22
22
|
>Searching for feeds…</p
|
|
23
23
|
>
|
|
24
24
|
|
|
@@ -26,10 +26,8 @@
|
|
|
26
26
|
|
|
27
27
|
<div
|
|
28
28
|
v-else-if="foundFeeds.length === 0"
|
|
29
|
-
class="ffun-info-
|
|
30
|
-
<p
|
|
31
|
-
class="ffun-info-error"
|
|
32
|
-
v-for="message in messages">
|
|
29
|
+
class="ffun-info-bad mt-2">
|
|
30
|
+
<p v-for="message in messages">
|
|
33
31
|
{{ message.message }}
|
|
34
32
|
</p>
|
|
35
33
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<li
|
|
6
6
|
v-for="entryId in entriesToShow"
|
|
7
7
|
:key="entryId"
|
|
8
|
-
class="
|
|
8
|
+
class="ffun-body-list-entry">
|
|
9
9
|
<entry-for-list
|
|
10
10
|
:entryId="entryId"
|
|
11
11
|
:time-field="timeField"
|
|
@@ -47,13 +47,3 @@
|
|
|
47
47
|
return properties.entriesIds.slice(0, showEntries.value);
|
|
48
48
|
});
|
|
49
49
|
</script>
|
|
50
|
-
|
|
51
|
-
<style scoped>
|
|
52
|
-
.entry-block {
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
.entry-block:not(:last-child) {
|
|
56
|
-
border-bottom-width: 1px;
|
|
57
|
-
@apply py-1;
|
|
58
|
-
}
|
|
59
|
-
</style>
|
|
@@ -1,28 +1,21 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
3
|
ref="entryTop"
|
|
4
|
-
class="flex text-lg">
|
|
5
|
-
<div
|
|
6
|
-
<
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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>
|
|
4
|
+
:class="['flex', 'text-lg', {'ml-8': isRead}]">
|
|
5
|
+
<div class="ffun-body-list-icon-column">
|
|
6
|
+
<a
|
|
7
|
+
v-if="isRead"
|
|
8
|
+
href="#"
|
|
9
|
+
@click.prevent="markUnread()"
|
|
10
|
+
title="Mark as unread"
|
|
11
|
+
class="text-green-700 ti ti-chevrons-left" />
|
|
12
|
+
|
|
13
|
+
<a
|
|
14
|
+
v-else
|
|
15
|
+
href="#"
|
|
16
|
+
@click.prevent="markRead()"
|
|
17
|
+
title="Mark as read"
|
|
18
|
+
class="text-orange-700 ti ti-chevrons-right" />
|
|
26
19
|
</div>
|
|
27
20
|
|
|
28
21
|
<div class="flex-shrink-0 w-8 text-center pr-1">
|
|
@@ -31,11 +24,7 @@
|
|
|
31
24
|
:entry-id="entry.id" />
|
|
32
25
|
</div>
|
|
33
26
|
|
|
34
|
-
<
|
|
35
|
-
<favicon-element
|
|
36
|
-
:url="entry.url"
|
|
37
|
-
class="w-5 h-5 align-text-bottom mx-1 inline" />
|
|
38
|
-
</div>
|
|
27
|
+
<body-list-favicon-column :url="entry.url" />
|
|
39
28
|
|
|
40
29
|
<div class="flex-grow">
|
|
41
30
|
<a
|
|
@@ -46,7 +35,7 @@
|
|
|
46
35
|
{{ purifiedTitle }}
|
|
47
36
|
</a>
|
|
48
37
|
|
|
49
|
-
<tags-list
|
|
38
|
+
<entry-tags-list
|
|
50
39
|
class="mt-0 pt-0"
|
|
51
40
|
:tags="entry.tags"
|
|
52
41
|
:tags-count="tagsCount"
|
|
@@ -55,34 +44,19 @@
|
|
|
55
44
|
:contributions="entry.scoreContributions" />
|
|
56
45
|
</div>
|
|
57
46
|
|
|
58
|
-
<
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
:value="timeFor"
|
|
62
|
-
:reversed="true" />
|
|
63
|
-
</div>
|
|
64
|
-
</div>
|
|
47
|
+
<body-list-reverse-time-column
|
|
48
|
+
:title="timeForTooltip"
|
|
49
|
+
:time="timeFor" />
|
|
65
50
|
</div>
|
|
66
51
|
|
|
67
|
-
<
|
|
52
|
+
<body-list-entry-body
|
|
68
53
|
v-if="showBody"
|
|
69
|
-
class="
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
@click="newsLinkOpenedEvent"
|
|
76
|
-
>{{ purifiedTitle }}</a
|
|
77
|
-
></h2
|
|
78
|
-
>
|
|
79
|
-
<p v-if="entry.body === null">loading...</p>
|
|
80
|
-
<div
|
|
81
|
-
v-if="entry.body !== null"
|
|
82
|
-
class="prose max-w-none"
|
|
83
|
-
v-html="purifiedBody" />
|
|
84
|
-
</div>
|
|
85
|
-
</div>
|
|
54
|
+
class="justify-center"
|
|
55
|
+
:url="entry.url"
|
|
56
|
+
:title="purifiedTitle"
|
|
57
|
+
:loading="entry.body === null"
|
|
58
|
+
:text="purifiedBody"
|
|
59
|
+
@body-title-clicked="newsLinkOpenedEvent" />
|
|
86
60
|
</template>
|
|
87
61
|
|
|
88
62
|
<script lang="ts" setup>
|
|
@@ -91,6 +65,7 @@
|
|
|
91
65
|
import type * as t from "@/logic/types";
|
|
92
66
|
import * as events from "@/logic/events";
|
|
93
67
|
import * as e from "@/logic/enums";
|
|
68
|
+
import * as utils from "@/logic/utils";
|
|
94
69
|
import {computedAsync} from "@vueuse/core";
|
|
95
70
|
import DOMPurify from "dompurify";
|
|
96
71
|
import {useEntriesStore} from "@/stores/entries";
|
|
@@ -129,30 +104,28 @@
|
|
|
129
104
|
return _.get(entry.value, properties.timeField, null);
|
|
130
105
|
});
|
|
131
106
|
|
|
132
|
-
const
|
|
107
|
+
const timeForTooltip = computed(() => {
|
|
133
108
|
if (entry.value === null) {
|
|
134
109
|
return "";
|
|
135
110
|
}
|
|
136
111
|
|
|
137
|
-
|
|
138
|
-
|
|
112
|
+
if (properties.timeField === "publishedAt") {
|
|
113
|
+
return "How long ago the news was published";
|
|
114
|
+
}
|
|
139
115
|
|
|
140
|
-
if (
|
|
141
|
-
|
|
116
|
+
if (properties.timeField === "catalogedAt") {
|
|
117
|
+
return "How long ago the news was collected";
|
|
142
118
|
}
|
|
143
119
|
|
|
144
|
-
return
|
|
120
|
+
return "";
|
|
145
121
|
});
|
|
146
122
|
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
123
|
+
const purifiedTitle = computed(() => {
|
|
124
|
+
return utils.purifyTitle({raw: entry.value.title, default_: "No title"});
|
|
125
|
+
});
|
|
151
126
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
return DOMPurify.sanitize(entry.value.body);
|
|
127
|
+
const purifiedBody = computed(() => {
|
|
128
|
+
return utils.purifyBody({raw: entry.value.body, default_: "No description"});
|
|
156
129
|
});
|
|
157
130
|
|
|
158
131
|
async function newsLinkOpenedEvent() {
|
|
@@ -191,4 +164,18 @@
|
|
|
191
164
|
onMounted(() => {
|
|
192
165
|
entriesStore.requestFullEntry({entryId: properties.entryId});
|
|
193
166
|
});
|
|
167
|
+
|
|
168
|
+
async function markUnread() {
|
|
169
|
+
await entriesStore.removeMarker({
|
|
170
|
+
entryId: properties.entryId,
|
|
171
|
+
marker: e.Marker.Read
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async function markRead() {
|
|
176
|
+
await entriesStore.setMarker({
|
|
177
|
+
entryId: properties.entryId,
|
|
178
|
+
marker: e.Marker.Read
|
|
179
|
+
});
|
|
180
|
+
}
|
|
194
181
|
</script>
|
|
@@ -1,57 +1,41 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
3
|
v-if="feed !== null"
|
|
4
|
-
class="flex
|
|
5
|
-
<div class="
|
|
4
|
+
class="flex text-lg">
|
|
5
|
+
<div class="ffun-body-list-icon-column">
|
|
6
6
|
<a
|
|
7
7
|
href="#"
|
|
8
|
-
class="
|
|
8
|
+
class="ti ti-x text-red-500 hover:text-red-600"
|
|
9
|
+
title="Unsubscribe"
|
|
9
10
|
@click.prevent="feedsStore.unsubscribe(feed.id)">
|
|
10
|
-
remove
|
|
11
11
|
</a>
|
|
12
12
|
</div>
|
|
13
13
|
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
<value-date-time
|
|
18
|
-
:value="feed.loadedAt"
|
|
19
|
-
:reversed="true" />
|
|
20
|
-
</div>
|
|
14
|
+
<body-list-reverse-time-column
|
|
15
|
+
title="How long ago the feed was last checked for news"
|
|
16
|
+
:time="feed.loadedAt" />
|
|
21
17
|
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
<value-date-time
|
|
26
|
-
:value="feed.linkedAt"
|
|
27
|
-
:reversed="true" />
|
|
28
|
-
</div>
|
|
18
|
+
<body-list-reverse-time-column
|
|
19
|
+
title="How long ago the feed was added"
|
|
20
|
+
:time="feed.linkedAt" />
|
|
29
21
|
|
|
30
|
-
<div class="
|
|
31
|
-
<
|
|
22
|
+
<div class="ffun-body-list-icon-column ml-3">
|
|
23
|
+
<i
|
|
32
24
|
v-if="feed.isOk"
|
|
33
25
|
title="everything is ok"
|
|
34
|
-
class="text-green-700
|
|
35
|
-
|
|
36
|
-
>
|
|
37
|
-
<span
|
|
26
|
+
class="text-green-700 ti ti-mood-smile"></i>
|
|
27
|
+
<i
|
|
38
28
|
v-else
|
|
39
29
|
:title="feed.lastError || 'unknown error'"
|
|
40
|
-
class="text-red-700
|
|
41
|
-
>⚠</span
|
|
42
|
-
>
|
|
30
|
+
class="text-red-700 ti ti-mood-sad align-middle"></i>
|
|
43
31
|
</div>
|
|
44
32
|
|
|
45
|
-
<
|
|
46
|
-
<favicon-element
|
|
47
|
-
:url="feed.url"
|
|
48
|
-
class="w-4 h-4 align-text-bottom mx-1 inline" />
|
|
49
|
-
</div>
|
|
33
|
+
<body-list-favicon-column :url="feed.url" />
|
|
50
34
|
|
|
51
35
|
<div class="flex-grow">
|
|
52
|
-
<
|
|
36
|
+
<external-url
|
|
53
37
|
class="ffun-normal-link"
|
|
54
|
-
:
|
|
38
|
+
:url="feed.url"
|
|
55
39
|
:text="purifiedTitle" />
|
|
56
40
|
|
|
57
41
|
<template v-if="feed.collectionIds.length > 0">
|
|
@@ -64,14 +48,16 @@
|
|
|
64
48
|
</template>
|
|
65
49
|
</span>
|
|
66
50
|
</template>
|
|
67
|
-
<template v-if="globalSettings.showFeedsDescriptions">
|
|
68
|
-
<br />
|
|
69
|
-
<div class="max-w-3xl flex-1 bg-slate-50 border-2 rounded p-4">
|
|
70
|
-
<div v-html="purifiedDescription" />
|
|
71
|
-
</div>
|
|
72
|
-
</template>
|
|
73
51
|
</div>
|
|
74
52
|
</div>
|
|
53
|
+
|
|
54
|
+
<body-list-entry-body
|
|
55
|
+
v-if="globalSettings.showFeedsDescriptions"
|
|
56
|
+
class="ml-56"
|
|
57
|
+
:url="null"
|
|
58
|
+
:title="null"
|
|
59
|
+
:loading="false"
|
|
60
|
+
:text="purifiedDescription" />
|
|
75
61
|
</template>
|
|
76
62
|
|
|
77
63
|
<script lang="ts" setup>
|
|
@@ -79,6 +65,7 @@
|
|
|
79
65
|
import type * as t from "@/logic/types";
|
|
80
66
|
import * as e from "@/logic/enums";
|
|
81
67
|
import * as api from "@/logic/api";
|
|
68
|
+
import * as utils from "@/logic/utils";
|
|
82
69
|
import {computedAsync} from "@vueuse/core";
|
|
83
70
|
import DOMPurify from "dompurify";
|
|
84
71
|
import {useGlobalSettingsStore} from "@/stores/globalSettings";
|
|
@@ -91,33 +78,11 @@
|
|
|
91
78
|
|
|
92
79
|
const properties = defineProps<{feed: t.Feed}>();
|
|
93
80
|
|
|
94
|
-
const noDescription = "No description";
|
|
95
|
-
|
|
96
81
|
const purifiedTitle = computed(() => {
|
|
97
|
-
|
|
98
|
-
return properties.feed.url;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
let title = DOMPurify.sanitize(properties.feed.title, {ALLOWED_TAGS: []}).trim();
|
|
102
|
-
|
|
103
|
-
if (title.length === 0) {
|
|
104
|
-
return properties.feed.url;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return title;
|
|
82
|
+
return utils.purifyTitle({raw: properties.feed.title, default_: properties.feed.url});
|
|
108
83
|
});
|
|
109
84
|
|
|
110
85
|
const purifiedDescription = computed(() => {
|
|
111
|
-
|
|
112
|
-
return noDescription;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
let description = DOMPurify.sanitize(properties.feed.description).trim();
|
|
116
|
-
|
|
117
|
-
if (description.length === 0) {
|
|
118
|
-
return noDescription;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return description;
|
|
86
|
+
return utils.purifyBody({raw: properties.feed.description, default_: "No description"});
|
|
122
87
|
});
|
|
123
88
|
</script>
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<
|
|
4
|
-
<
|
|
3
|
+
<h3>
|
|
4
|
+
<favicon-element
|
|
5
|
+
:url="feed.url"
|
|
6
|
+
class="w-5 h-5 mx-1 mb-1 inline align-middle" />
|
|
7
|
+
|
|
8
|
+
<external-url
|
|
5
9
|
class="ffun-normal-link"
|
|
6
|
-
:
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
{{ feed.title }}
|
|
10
|
-
</a>
|
|
11
|
-
</h2>
|
|
10
|
+
:url="feed.url"
|
|
11
|
+
:text="feed.title" />
|
|
12
|
+
</h3>
|
|
12
13
|
|
|
13
14
|
<p v-html="feed.description" />
|
|
14
15
|
|
|
@@ -16,13 +17,10 @@
|
|
|
16
17
|
<li
|
|
17
18
|
v-for="entry in feed.entries"
|
|
18
19
|
:key="entry.url">
|
|
19
|
-
<
|
|
20
|
+
<external-url
|
|
20
21
|
class="ffun-normal-link"
|
|
21
|
-
:
|
|
22
|
-
|
|
23
|
-
rel="noopener noreferrer">
|
|
24
|
-
{{ entry.title }}
|
|
25
|
-
</a>
|
|
22
|
+
:url="entry.url"
|
|
23
|
+
:text="entry.title" />
|
|
26
24
|
</li>
|
|
27
25
|
</ul>
|
|
28
26
|
</div>
|
|
@@ -18,19 +18,19 @@
|
|
|
18
18
|
|
|
19
19
|
<p
|
|
20
20
|
v-if="loading"
|
|
21
|
-
class="ffun-info-
|
|
21
|
+
class="ffun-info-waiting mt-2"
|
|
22
22
|
>Loading...</p
|
|
23
23
|
>
|
|
24
24
|
|
|
25
25
|
<p
|
|
26
26
|
v-if="loaded"
|
|
27
|
-
class="ffun-info-good"
|
|
27
|
+
class="ffun-info-good mt-4"
|
|
28
28
|
>Feeds added!</p
|
|
29
29
|
>
|
|
30
30
|
|
|
31
31
|
<p
|
|
32
32
|
v-if="error"
|
|
33
|
-
class="ffun-info-bad"
|
|
33
|
+
class="ffun-info-bad mt-4"
|
|
34
34
|
>Error occurred! Maybe you chose a wrong file?</p
|
|
35
35
|
>
|
|
36
36
|
</div>
|
|
@@ -17,12 +17,18 @@
|
|
|
17
17
|
>
|
|
18
18
|
</div>
|
|
19
19
|
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
<template v-else>
|
|
21
|
+
<p
|
|
22
|
+
v-if="showSuccess"
|
|
23
|
+
class="ffun-info-good"
|
|
24
|
+
>Rule created.</p
|
|
25
|
+
>
|
|
26
|
+
<p
|
|
27
|
+
v-else
|
|
28
|
+
class="ffun-info-common"
|
|
29
|
+
>Select tags to create a rule.</p
|
|
30
|
+
>
|
|
31
|
+
</template>
|
|
26
32
|
</div>
|
|
27
33
|
</template>
|
|
28
34
|
|
|
@@ -3,36 +3,27 @@
|
|
|
3
3
|
<div
|
|
4
4
|
v-if="rule !== null"
|
|
5
5
|
class="flex mb-1">
|
|
6
|
-
<div class="
|
|
6
|
+
<div class="ffun-body-list-icon-column">
|
|
7
7
|
<a
|
|
8
8
|
href="#"
|
|
9
|
-
class="
|
|
9
|
+
class="ti ti-x text-red-500 hover:text-red-600"
|
|
10
|
+
title="Remove this rule"
|
|
10
11
|
@click.prevent="deleteRule()">
|
|
11
|
-
remove
|
|
12
12
|
</a>
|
|
13
13
|
</div>
|
|
14
14
|
|
|
15
|
-
<
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
<div class="flex-shrink-0 min-w-fit mr-2">
|
|
16
|
+
<score-selector
|
|
17
|
+
:modelValue="rule.score"
|
|
18
|
+
@input="updateSelected" />
|
|
19
|
+
</div>
|
|
19
20
|
|
|
20
21
|
<div class="flex-grow">
|
|
21
|
-
<
|
|
22
|
-
v-for="tag of rule.
|
|
23
|
-
:key="tag"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
secondary-mode="positive" />
|
|
27
|
-
</template>
|
|
28
|
-
|
|
29
|
-
<template
|
|
30
|
-
v-for="tag of rule.excludedTags"
|
|
31
|
-
:key="tag">
|
|
32
|
-
<ffun-tag
|
|
33
|
-
:uid="tag"
|
|
34
|
-
secondary-mode="negative" />
|
|
35
|
-
</template>
|
|
22
|
+
<rule-tag
|
|
23
|
+
v-for="tag of rule.allTags"
|
|
24
|
+
:key="tag"
|
|
25
|
+
:uid="tag"
|
|
26
|
+
:css-modifier="cssModifiers[tag]" />
|
|
36
27
|
</div>
|
|
37
28
|
</div>
|
|
38
29
|
|
|
@@ -42,9 +33,9 @@
|
|
|
42
33
|
Score updated
|
|
43
34
|
<a
|
|
44
35
|
href="#"
|
|
45
|
-
class="
|
|
36
|
+
class=""
|
|
46
37
|
@click.prevent="scoreChanged = false"
|
|
47
|
-
>close</a
|
|
38
|
+
>[close]</a
|
|
48
39
|
>
|
|
49
40
|
</p>
|
|
50
41
|
</div>
|
|
@@ -85,4 +76,14 @@
|
|
|
85
76
|
|
|
86
77
|
globalSettings.updateDataVersion();
|
|
87
78
|
}
|
|
79
|
+
|
|
80
|
+
const cssModifiers: {[key: string]: string} = {};
|
|
81
|
+
|
|
82
|
+
for (const tag of properties.rule.allTags) {
|
|
83
|
+
if (properties.rule.excludedTags.includes(tag)) {
|
|
84
|
+
cssModifiers[tag] = "negative";
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
cssModifiers[tag] = "positive";
|
|
88
|
+
}
|
|
88
89
|
</script>
|
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
{{ realShowEntries }} of {{ total }}
|
|
4
4
|
|
|
5
5
|
<button
|
|
6
|
-
class="ffun-form-button ml-2"
|
|
6
|
+
class="ffun-form-button short ml-2"
|
|
7
7
|
v-if="canShowMore"
|
|
8
8
|
@click.prevent="showMore()">
|
|
9
9
|
next {{ realShowPerPage }}
|
|
10
10
|
</button>
|
|
11
11
|
|
|
12
12
|
<button
|
|
13
|
-
class="ffun-form-button ml-2"
|
|
13
|
+
class="ffun-form-button short ml-2"
|
|
14
14
|
v-if="canHide"
|
|
15
15
|
@click.prevent="hideAll()"
|
|
16
16
|
>hide</button
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div v-if="globalState.isLoggedIn">
|
|
3
|
-
<
|
|
3
|
+
<h3 class="">You have already logged in</h3>
|
|
4
4
|
<button
|
|
5
5
|
class="text-blue-600 hover:text-blue-800 text-xl pt-0"
|
|
6
6
|
@click.prevent="goToWorkspace()"
|
|
@@ -9,14 +9,13 @@
|
|
|
9
9
|
</div>
|
|
10
10
|
|
|
11
11
|
<div v-else>
|
|
12
|
+
<h2 class="my-0">Single e-mail to log in</h2>
|
|
12
13
|
<template v-if="!requested">
|
|
13
|
-
<p class="text-
|
|
14
|
-
|
|
15
|
-
<p class="text-left">If you don't have an account, one will be created.</p>
|
|
14
|
+
<p class="text-center">We'll send you an email with a login link, no password required.</p>
|
|
16
15
|
|
|
17
16
|
<form
|
|
18
17
|
@submit.prevent="login()"
|
|
19
|
-
class="w-full flex">
|
|
18
|
+
class="w-full flex justify-center">
|
|
20
19
|
<input
|
|
21
20
|
class="ffun-input flex-grow p-1 mr-2"
|
|
22
21
|
type="email"
|
|
@@ -26,7 +25,7 @@
|
|
|
26
25
|
<button
|
|
27
26
|
class="ffun-form-button"
|
|
28
27
|
type="submit"
|
|
29
|
-
>
|
|
28
|
+
>Log In</button
|
|
30
29
|
>
|
|
31
30
|
</form>
|
|
32
31
|
</template>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div
|
|
3
3
|
v-if="setting !== null"
|
|
4
4
|
class="mb-4">
|
|
5
|
-
<span class="
|
|
5
|
+
<span class="mr-1">{{ setting.name }}</span>
|
|
6
6
|
|
|
7
7
|
<input
|
|
8
8
|
class="ffun-input"
|
|
@@ -21,12 +21,12 @@
|
|
|
21
21
|
style="min-width: 2.5rem"
|
|
22
22
|
:flag="setting.value"
|
|
23
23
|
@update:flag="updateFlag($event)"
|
|
24
|
-
on-text="
|
|
25
|
-
off-text="
|
|
24
|
+
on-text="no"
|
|
25
|
+
off-text="yes" />
|
|
26
26
|
|
|
27
27
|
<template v-else-if="!editing">
|
|
28
28
|
<button
|
|
29
|
-
class="ffun-form-button ml-1"
|
|
29
|
+
class="ffun-form-button short ml-1"
|
|
30
30
|
@click.prevent="startEditing()"
|
|
31
31
|
>Edit</button
|
|
32
32
|
>
|
|
@@ -35,20 +35,15 @@
|
|
|
35
35
|
<template v-else>
|
|
36
36
|
<button
|
|
37
37
|
@click.prevent="save()"
|
|
38
|
-
class="ffun-form-button ml-1"
|
|
38
|
+
class="ffun-form-button short ml-1"
|
|
39
39
|
>Save</button
|
|
40
40
|
>
|
|
41
41
|
<button
|
|
42
42
|
@click.prevent="cancel()"
|
|
43
|
-
class="ffun-form-button ml-1"
|
|
43
|
+
class="ffun-form-button short ml-1"
|
|
44
44
|
>Cancel</button
|
|
45
45
|
>
|
|
46
46
|
</template>
|
|
47
|
-
|
|
48
|
-
<div
|
|
49
|
-
class="ffun-normalized-text"
|
|
50
|
-
v-if="setting.description"
|
|
51
|
-
v-html="setting.description" />
|
|
52
47
|
</div>
|
|
53
48
|
</template>
|
|
54
49
|
|
|
@@ -89,7 +84,7 @@
|
|
|
89
84
|
const type = setting.value.type;
|
|
90
85
|
|
|
91
86
|
if (type == "boolean") {
|
|
92
|
-
return v ? "
|
|
87
|
+
return v ? "yes" : "no";
|
|
93
88
|
}
|
|
94
89
|
|
|
95
90
|
if (v == null || v == "") {
|