feeds-fun 0.6.0 → 1.1.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 +25 -23
- package/postcss.config.js +6 -0
- package/src/components/ConfigFlag.vue +6 -14
- package/src/components/ConfigSelector.vue +3 -1
- package/src/components/DiscoveryForm.vue +9 -2
- package/src/components/EntriesList.vue +15 -4
- package/src/components/EntryForList.vue +76 -65
- package/src/components/FeedForList.vue +15 -32
- package/src/components/FeedInfo.vue +11 -4
- package/src/components/FeedsCollections.vue +23 -15
- package/src/components/FeedsList.vue +7 -18
- package/src/components/FfunTag.vue +6 -13
- package/src/components/NotificationCollections.vue +7 -0
- package/src/components/NotificationOpenaiApiKey.vue +28 -0
- package/src/components/Notifications.vue +32 -0
- package/src/components/OPMLUpload.vue +3 -0
- package/src/components/RuleConstructor.vue +16 -24
- package/src/components/RuleForList.vue +47 -0
- package/src/components/RulesList.vue +7 -43
- package/src/components/SimplePagination.vue +4 -6
- package/src/components/SupertokensLogin.vue +50 -25
- package/src/components/TagsFilter.vue +13 -25
- package/src/components/TagsList.vue +27 -25
- package/src/components/UserSetting.vue +41 -38
- package/src/components/UserSettingForNotification.vue +63 -0
- package/src/inputs/Marker.vue +3 -7
- package/src/inputs/ScoreSelector.vue +11 -12
- package/src/layouts/SidePanelLayout.vue +42 -96
- package/src/layouts/WideLayout.vue +2 -25
- package/src/logic/settings.ts +0 -9
- package/src/main.ts +12 -19
- package/src/stores/entries.ts +1 -6
- package/src/style.css +92 -0
- package/src/values/Score.vue +1 -10
- package/src/views/AuthView.vue +3 -7
- package/src/views/CollectionsView.vue +2 -0
- package/src/views/FeedsView.vue +8 -3
- package/src/views/MainView.vue +36 -83
- package/src/views/NewsView.vue +30 -13
- package/src/views/RulesView.vue +0 -2
- package/src/views/SettingsView.vue +35 -22
- package/tailwind.config.js +14 -0
- package/src/components/EntryInfo.vue +0 -23
- package/src/components/FfunGithubButtons.vue +0 -22
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "feeds-fun",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
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": [
|
|
@@ -32,37 +32,39 @@
|
|
|
32
32
|
"format-check": "prettier --check src/"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@chenfengyuan/vue-countdown": "^2.1.
|
|
36
|
-
"@sentry/vue": "^7.54.0",
|
|
35
|
+
"@chenfengyuan/vue-countdown": "^2.1.2",
|
|
37
36
|
"@vueuse/core": "^9.13.0",
|
|
38
|
-
"axios": "^1.
|
|
39
|
-
"dompurify": "^3.0.
|
|
40
|
-
"pinia": "^2.
|
|
37
|
+
"axios": "^1.5.1",
|
|
38
|
+
"dompurify": "^3.0.6",
|
|
39
|
+
"pinia": "^2.1.7",
|
|
41
40
|
"set-interval-async": "^3.0.3",
|
|
42
41
|
"supertokens-web-js": "^0.5.0",
|
|
43
42
|
"vue": "^3.2.47",
|
|
44
|
-
"vue-
|
|
45
|
-
"vue-router": "^4.1.6"
|
|
43
|
+
"vue-router": "^4.2.5"
|
|
46
44
|
},
|
|
47
45
|
"devDependencies": {
|
|
48
|
-
"@rushstack/eslint-patch": "^1.
|
|
49
|
-
"@
|
|
50
|
-
"@types/
|
|
51
|
-
"@types/
|
|
52
|
-
"@types/
|
|
53
|
-
"@
|
|
46
|
+
"@rushstack/eslint-patch": "^1.5.1",
|
|
47
|
+
"@tailwindcss/typography": "^0.5.10",
|
|
48
|
+
"@types/dompurify": "^3.0.3",
|
|
49
|
+
"@types/jsdom": "^21.1.3",
|
|
50
|
+
"@types/lodash": "^4.14.199",
|
|
51
|
+
"@types/node": "^18.18.5",
|
|
52
|
+
"@vitejs/plugin-vue": "^4.4.0",
|
|
54
53
|
"@vue/eslint-config-prettier": "^7.1.0",
|
|
55
|
-
"@vue/eslint-config-typescript": "^11.0.
|
|
56
|
-
"@vue/test-utils": "^2.
|
|
54
|
+
"@vue/eslint-config-typescript": "^11.0.3",
|
|
55
|
+
"@vue/test-utils": "^2.4.1",
|
|
57
56
|
"@vue/tsconfig": "^0.1.3",
|
|
58
|
-
"
|
|
59
|
-
"eslint
|
|
60
|
-
"
|
|
57
|
+
"autoprefixer": "^10.4.16",
|
|
58
|
+
"eslint": "^8.51.0",
|
|
59
|
+
"eslint-plugin-vue": "^9.17.0",
|
|
60
|
+
"jsdom": "^21.1.2",
|
|
61
61
|
"npm-run-all": "^4.1.5",
|
|
62
|
-
"
|
|
62
|
+
"postcss": "^8.4.31",
|
|
63
|
+
"prettier": "^2.8.8",
|
|
64
|
+
"tailwindcss": "^3.3.3",
|
|
63
65
|
"typescript": "~4.8.4",
|
|
64
|
-
"vite": "^4.
|
|
65
|
-
"vitest": "^0.29.
|
|
66
|
-
"vue-tsc": "^1.
|
|
66
|
+
"vite": "^4.4.11",
|
|
67
|
+
"vitest": "^0.29.8",
|
|
68
|
+
"vue-tsc": "^1.8.19"
|
|
67
69
|
}
|
|
68
70
|
}
|
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
>{{ onText }}</
|
|
7
|
-
>
|
|
8
|
-
<a
|
|
9
|
-
v-if="!flag"
|
|
10
|
-
href="#"
|
|
11
|
-
@click="emit('update:flag', true)"
|
|
12
|
-
>{{ offText }}</a
|
|
13
|
-
>
|
|
2
|
+
<button
|
|
3
|
+
class="ffun-config-flag"
|
|
4
|
+
@click="emit('update:flag', !flag)">
|
|
5
|
+
<span v-if="flag">{{ offText }}</span>
|
|
6
|
+
<span v-else>{{ onText }}</span>
|
|
7
|
+
</button>
|
|
14
8
|
</template>
|
|
15
9
|
|
|
16
10
|
<script setup lang="ts">
|
|
@@ -18,5 +12,3 @@
|
|
|
18
12
|
|
|
19
13
|
const emit = defineEmits(["update:flag"]);
|
|
20
14
|
</script>
|
|
21
|
-
|
|
22
|
-
<style scoped></style>
|
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
<div>
|
|
3
3
|
<input
|
|
4
4
|
type="text"
|
|
5
|
+
class="ffun-input mr-1"
|
|
5
6
|
v-model="search"
|
|
6
7
|
:disabled="loading"
|
|
7
8
|
placeholder="Search for feeds" />
|
|
8
9
|
|
|
9
10
|
<button
|
|
11
|
+
class="ffun-form-button"
|
|
10
12
|
:disabled="loading"
|
|
11
13
|
@click.prevent="searhedUrl = search">
|
|
12
14
|
Search
|
|
@@ -25,12 +27,17 @@
|
|
|
25
27
|
<feed-info :feed="feed" />
|
|
26
28
|
|
|
27
29
|
<button
|
|
30
|
+
class="ffun-form-button"
|
|
28
31
|
v-if="!addedFeeds[feed.url]"
|
|
29
32
|
@click.prevent="addFeed(feed.url)">
|
|
30
33
|
Add
|
|
31
34
|
</button>
|
|
32
|
-
|
|
33
|
-
<
|
|
35
|
+
|
|
36
|
+
<p
|
|
37
|
+
v-else
|
|
38
|
+
class="ffun-info-good"
|
|
39
|
+
>Feed added</p
|
|
40
|
+
>
|
|
34
41
|
</div>
|
|
35
42
|
</div>
|
|
36
43
|
</div>
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
3
|
<template v-if="entriesToShow.length > 0">
|
|
4
|
-
<ul
|
|
4
|
+
<ul>
|
|
5
5
|
<li
|
|
6
6
|
v-for="entryId in entriesToShow"
|
|
7
7
|
:key="entryId"
|
|
8
|
-
|
|
8
|
+
class="mb-1 entry-block">
|
|
9
9
|
<entry-for-list
|
|
10
10
|
:entryId="entryId"
|
|
11
11
|
:time-field="timeField"
|
|
12
12
|
:show-tags="showTags"
|
|
13
|
-
:tags-count="tagsCount"
|
|
13
|
+
:tags-count="tagsCount"
|
|
14
|
+
@entry:bodyVisibilityChanged="onBodyVisibilityChanged" />
|
|
14
15
|
</li>
|
|
15
16
|
</ul>
|
|
16
17
|
|
|
@@ -40,6 +41,8 @@
|
|
|
40
41
|
tagsCount: {[key: string]: number};
|
|
41
42
|
}>();
|
|
42
43
|
|
|
44
|
+
const emit = defineEmits(["entry:bodyVisibilityChanged"]);
|
|
45
|
+
|
|
43
46
|
const showEntries = ref(properties.showFromStart);
|
|
44
47
|
|
|
45
48
|
const entriesToShow = computed(() => {
|
|
@@ -48,6 +51,14 @@
|
|
|
48
51
|
}
|
|
49
52
|
return properties.entriesIds.slice(0, showEntries.value);
|
|
50
53
|
});
|
|
54
|
+
|
|
55
|
+
function onBodyVisibilityChanged({entryId, visible}: {entryId: t.EntryId; visible: boolean}) {
|
|
56
|
+
emit("entry:bodyVisibilityChanged", {entryId, visible});
|
|
57
|
+
}
|
|
51
58
|
</script>
|
|
52
59
|
|
|
53
|
-
<style
|
|
60
|
+
<style scoped>
|
|
61
|
+
.entry-block:not(:last-child) {
|
|
62
|
+
border-bottom-width: 1px;
|
|
63
|
+
}
|
|
64
|
+
</style>
|
|
@@ -1,71 +1,66 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="
|
|
3
|
-
<div
|
|
2
|
+
<div class="flex">
|
|
3
|
+
<div class="flex-shrink-0 w-8 text-right pr-1">
|
|
4
4
|
<value-score
|
|
5
5
|
:value="entry.score"
|
|
6
|
-
:entry-id="entry.id"
|
|
7
|
-
class="entity-for-list-score" />
|
|
6
|
+
:entry-id="entry.id" />
|
|
8
7
|
</div>
|
|
9
8
|
|
|
10
|
-
<div
|
|
11
|
-
<input-marker
|
|
12
|
-
:marker="e.Marker.Read"
|
|
13
|
-
:entry-id="entryId"
|
|
14
|
-
on-text="read"
|
|
15
|
-
off-text="new!" />
|
|
16
|
-
|
|
17
|
-
<a
|
|
18
|
-
href="#"
|
|
19
|
-
style="text-decoration: none; margin-left: 0.25rem"
|
|
20
|
-
v-if="!showBody"
|
|
21
|
-
@click.prevent="displayBody()"
|
|
22
|
-
>▼</a
|
|
23
|
-
>
|
|
24
|
-
<a
|
|
25
|
-
href="#"
|
|
26
|
-
style="text-decoration: none; margin-left: 0.25rem"
|
|
27
|
-
v-if="showBody"
|
|
28
|
-
@click.prevent="showBody = false"
|
|
29
|
-
>▲</a
|
|
30
|
-
>
|
|
31
|
-
|
|
9
|
+
<div class="flex-shrink-0 w-8 text-right pr-1">
|
|
32
10
|
<favicon-element
|
|
33
11
|
:url="entry.url"
|
|
34
|
-
|
|
12
|
+
class="w-4 h-4 align-text-bottom mx-1 inline" />
|
|
13
|
+
</div>
|
|
35
14
|
|
|
15
|
+
<div class="flex-grow">
|
|
36
16
|
<a
|
|
37
17
|
:href="entry.url"
|
|
38
18
|
target="_blank"
|
|
39
|
-
|
|
40
|
-
|
|
19
|
+
:class="[{'font-bold': isRead}, 'flex-grow', 'min-w-fit', 'line-clamp-1', 'pr-4', 'mb-0']"
|
|
20
|
+
@click="onTitleClick">
|
|
41
21
|
{{ purifiedTitle }}
|
|
42
22
|
</a>
|
|
43
23
|
|
|
44
|
-
<
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
24
|
+
<tags-list
|
|
25
|
+
v-if="showTags"
|
|
26
|
+
class="mt-0 pt-0"
|
|
27
|
+
:tags="entry.tags"
|
|
28
|
+
:tags-count="tagsCount"
|
|
29
|
+
:contributions="entry.scoreContributions" />
|
|
30
|
+
</div>
|
|
51
31
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
32
|
+
<div class="flex flex-shrink-0">
|
|
33
|
+
<input-marker
|
|
34
|
+
class="w-7 mr-2"
|
|
35
|
+
:marker="e.Marker.Read"
|
|
36
|
+
:entry-id="entryId"
|
|
37
|
+
on-text="read"
|
|
38
|
+
off-text="new" />
|
|
39
|
+
|
|
40
|
+
<div class="w-7">
|
|
41
|
+
<value-date-time
|
|
42
|
+
:value="timeFor"
|
|
43
|
+
:reversed="true" />
|
|
62
44
|
</div>
|
|
63
45
|
</div>
|
|
46
|
+
</div>
|
|
64
47
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
48
|
+
<div
|
|
49
|
+
v-if="showBody"
|
|
50
|
+
class="flex justify-center my-1">
|
|
51
|
+
<div class="max-w-3xl flex-1 bg-slate-50 border-2 rounded p-4">
|
|
52
|
+
<h2 class="mt-0"
|
|
53
|
+
><a
|
|
54
|
+
:href="entry.url"
|
|
55
|
+
target="_blank"
|
|
56
|
+
>{{ purifiedTitle }}</a
|
|
57
|
+
></h2
|
|
58
|
+
>
|
|
59
|
+
<p v-if="entry.body === null">loading...</p>
|
|
60
|
+
<div
|
|
61
|
+
v-if="entry.body !== null"
|
|
62
|
+
class="prose max-w-none"
|
|
63
|
+
v-html="purifiedBody" />
|
|
69
64
|
</div>
|
|
70
65
|
</div>
|
|
71
66
|
</template>
|
|
@@ -88,6 +83,8 @@
|
|
|
88
83
|
tagsCount: {[key: string]: number};
|
|
89
84
|
}>();
|
|
90
85
|
|
|
86
|
+
const emit = defineEmits(["entry:bodyVisibilityChanged"]);
|
|
87
|
+
|
|
91
88
|
const entry = computed(() => {
|
|
92
89
|
if (properties.entryId in entriesStore.entries) {
|
|
93
90
|
return entriesStore.entries[properties.entryId];
|
|
@@ -96,6 +93,10 @@
|
|
|
96
93
|
throw new Error(`Unknown entry: ${properties.entryId}`);
|
|
97
94
|
});
|
|
98
95
|
|
|
96
|
+
const isRead = computed(() => {
|
|
97
|
+
return !entriesStore.entries[entry.value.id].hasMarker(e.Marker.Read);
|
|
98
|
+
});
|
|
99
|
+
|
|
99
100
|
const showBody = ref(false);
|
|
100
101
|
|
|
101
102
|
const timeFor = computed(() => {
|
|
@@ -109,6 +110,8 @@
|
|
|
109
110
|
function displayBody() {
|
|
110
111
|
showBody.value = true;
|
|
111
112
|
|
|
113
|
+
emit("entry:bodyVisibilityChanged", {entryId: properties.entryId, visible: true});
|
|
114
|
+
|
|
112
115
|
if (entry.value === null) {
|
|
113
116
|
throw new Error("entry is null");
|
|
114
117
|
}
|
|
@@ -116,6 +119,11 @@
|
|
|
116
119
|
entriesStore.requestFullEntry({entryId: entry.value.id});
|
|
117
120
|
}
|
|
118
121
|
|
|
122
|
+
function hideBody() {
|
|
123
|
+
showBody.value = false;
|
|
124
|
+
emit("entry:bodyVisibilityChanged", {entryId: properties.entryId, visible: false});
|
|
125
|
+
}
|
|
126
|
+
|
|
119
127
|
const purifiedTitle = computed(() => {
|
|
120
128
|
if (entry.value === null) {
|
|
121
129
|
return "";
|
|
@@ -142,21 +150,24 @@
|
|
|
142
150
|
return DOMPurify.sanitize(entry.value.body);
|
|
143
151
|
});
|
|
144
152
|
|
|
145
|
-
async function onTitleClick() {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
</script>
|
|
153
|
+
async function onTitleClick(event: MouseEvent) {
|
|
154
|
+
if (!event.ctrlKey) {
|
|
155
|
+
event.preventDefault();
|
|
156
|
+
event.stopPropagation();
|
|
152
157
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
158
|
+
if (showBody.value) {
|
|
159
|
+
hideBody();
|
|
160
|
+
} else {
|
|
161
|
+
displayBody();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
157
164
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
165
|
+
// TODO: is it will be too slow?
|
|
166
|
+
if (showBody.value) {
|
|
167
|
+
await entriesStore.setMarker({
|
|
168
|
+
entryId: properties.entryId,
|
|
169
|
+
marker: e.Marker.Read
|
|
170
|
+
});
|
|
171
|
+
}
|
|
161
172
|
}
|
|
162
|
-
</
|
|
173
|
+
</script>
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
3
|
v-if="feed !== null"
|
|
4
|
-
class="
|
|
5
|
-
<div
|
|
4
|
+
class="flex mb-1">
|
|
5
|
+
<div class="flex-shrink-0 min-w-fit pr-2">
|
|
6
6
|
<a
|
|
7
7
|
href="#"
|
|
8
|
+
class="ffun-normal-link"
|
|
8
9
|
@click.prevent="unsubscribe()">
|
|
9
10
|
remove
|
|
10
11
|
</a>
|
|
11
12
|
</div>
|
|
12
13
|
|
|
13
14
|
<div
|
|
14
|
-
|
|
15
|
+
class="flex-shrink-0 w-12 pr-2 text-right cursor-default"
|
|
15
16
|
title="Time of last load">
|
|
16
17
|
<value-date-time
|
|
17
18
|
:value="feed.loadedAt"
|
|
@@ -19,34 +20,37 @@
|
|
|
19
20
|
</div>
|
|
20
21
|
|
|
21
22
|
<div
|
|
22
|
-
|
|
23
|
+
class="flex-shrink-0 w-12 pr-2 text-right cursor-default"
|
|
23
24
|
title="When was added">
|
|
24
25
|
<value-date-time
|
|
25
26
|
:value="feed.linkedAt"
|
|
26
27
|
:reversed="true" />
|
|
27
28
|
</div>
|
|
28
29
|
|
|
29
|
-
<div
|
|
30
|
+
<div class="flex-shrink-0 w-8 pr-1 text-right cursor-default">
|
|
30
31
|
<span
|
|
31
32
|
v-if="feed.isOk"
|
|
32
33
|
title="everything is ok"
|
|
33
|
-
class="
|
|
34
|
+
class="text-green-700 cursor-default"
|
|
34
35
|
>ok</span
|
|
35
36
|
>
|
|
36
37
|
<span
|
|
37
38
|
v-else
|
|
38
39
|
:title="feed.lastError || 'unknown error'"
|
|
39
|
-
class="
|
|
40
|
+
class="text-red-700 cursor-default"
|
|
40
41
|
>⚠</span
|
|
41
42
|
>
|
|
42
43
|
</div>
|
|
43
44
|
|
|
44
|
-
<
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
<div class="flex-shrink-0 w-8 text-right pr-1">
|
|
46
|
+
<favicon-element
|
|
47
|
+
:url="feed.url"
|
|
48
|
+
class="w-4 h-4 align-text-bottom mx-1 inline" />
|
|
49
|
+
</div>
|
|
47
50
|
|
|
48
|
-
<div
|
|
51
|
+
<div class="flex-grow">
|
|
49
52
|
<value-url
|
|
53
|
+
class="ffun-normal-link"
|
|
50
54
|
:value="feed.url"
|
|
51
55
|
:text="purifiedTitle" />
|
|
52
56
|
<template v-if="globalSettings.showFeedsDescriptions">
|
|
@@ -96,24 +100,3 @@
|
|
|
96
100
|
globalSettings.updateDataVersion();
|
|
97
101
|
}
|
|
98
102
|
</script>
|
|
99
|
-
|
|
100
|
-
<style scoped>
|
|
101
|
-
.container {
|
|
102
|
-
display: flex;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
.container :deep(img) {
|
|
106
|
-
max-width: 100%;
|
|
107
|
-
height: auto;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
.state-ok {
|
|
111
|
-
color: green;
|
|
112
|
-
cursor: default;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
.state-error {
|
|
116
|
-
color: red;
|
|
117
|
-
cursor: default;
|
|
118
|
-
}
|
|
119
|
-
</style>
|
|
@@ -1,21 +1,28 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<
|
|
3
|
+
<h2>
|
|
4
4
|
<a
|
|
5
|
+
class="ffun-normal-link"
|
|
5
6
|
:href="feed.url"
|
|
6
7
|
target="_blank"
|
|
7
8
|
rel="noopener noreferrer">
|
|
8
9
|
{{ feed.title }}
|
|
9
10
|
</a>
|
|
10
|
-
</
|
|
11
|
+
</h2>
|
|
11
12
|
|
|
12
13
|
<p v-html="feed.description" />
|
|
13
14
|
|
|
14
|
-
<ul>
|
|
15
|
+
<ul class="list-disc list-inside">
|
|
15
16
|
<li
|
|
16
17
|
v-for="entry in feed.entries"
|
|
17
18
|
:key="entry.url">
|
|
18
|
-
<
|
|
19
|
+
<a
|
|
20
|
+
class="ffun-normal-link"
|
|
21
|
+
:href="entry.url"
|
|
22
|
+
target="_blank"
|
|
23
|
+
rel="noopener noreferrer">
|
|
24
|
+
{{ entry.title }}
|
|
25
|
+
</a>
|
|
19
26
|
</li>
|
|
20
27
|
</ul>
|
|
21
28
|
</div>
|
|
@@ -1,20 +1,28 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
3
|
+
<ul class="mb-1">
|
|
4
|
+
<li v-for="item in collections">
|
|
5
|
+
<input
|
|
6
|
+
class="ffun-checkbox"
|
|
7
|
+
type="checkbox"
|
|
8
|
+
:id="item"
|
|
9
|
+
:name="item"
|
|
10
|
+
:value="item"
|
|
11
|
+
v-model="selectedCollections"
|
|
12
|
+
checked />
|
|
13
|
+
<label
|
|
14
|
+
class="ml-2"
|
|
15
|
+
:for="item"
|
|
16
|
+
>{{ item }}</label
|
|
17
|
+
>
|
|
18
|
+
</li>
|
|
19
|
+
</ul>
|
|
20
|
+
|
|
21
|
+
<button
|
|
22
|
+
@click="subscribe()"
|
|
23
|
+
class="ffun-form-button"
|
|
24
|
+
>Subscribe</button
|
|
25
|
+
>
|
|
18
26
|
</div>
|
|
19
27
|
</template>
|
|
20
28
|
|
|
@@ -1,20 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
<li
|
|
10
|
-
v-for="feed in feeds"
|
|
11
|
-
:key="feed.id"
|
|
12
|
-
style="margin-bottom: 0.25rem">
|
|
13
|
-
<feed-for-list :feed="feed" />
|
|
14
|
-
</li>
|
|
15
|
-
</ul>
|
|
16
|
-
</template>
|
|
17
|
-
</div>
|
|
2
|
+
<ul>
|
|
3
|
+
<li
|
|
4
|
+
v-for="feed in feeds"
|
|
5
|
+
:key="feed.id">
|
|
6
|
+
<feed-for-list :feed="feed" />
|
|
7
|
+
</li>
|
|
8
|
+
</ul>
|
|
18
9
|
</template>
|
|
19
10
|
|
|
20
11
|
<script lang="ts" setup>
|
|
@@ -23,5 +14,3 @@
|
|
|
23
14
|
|
|
24
15
|
const properties = defineProps<{feeds: Array<t.Feed>}>();
|
|
25
16
|
</script>
|
|
26
|
-
|
|
27
|
-
<style scoped></style>
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
:class="classes"
|
|
4
4
|
:title="tooltip"
|
|
5
5
|
@click.prevent="onClick()">
|
|
6
|
-
<slot name="start"> </slot>
|
|
7
|
-
|
|
8
6
|
<span v-if="countMode == 'prefix'">[{{ count }}]</span>
|
|
9
7
|
|
|
10
8
|
{{ tagInfo.name }}
|
|
@@ -14,7 +12,6 @@
|
|
|
14
12
|
:href="tagInfo.link"
|
|
15
13
|
target="_blank"
|
|
16
14
|
@click.stop=""
|
|
17
|
-
style="text-decoration: none"
|
|
18
15
|
rel="noopener noreferrer">
|
|
19
16
|
↗
|
|
20
17
|
</a>
|
|
@@ -75,30 +72,26 @@
|
|
|
75
72
|
|
|
76
73
|
<style scoped>
|
|
77
74
|
.tag {
|
|
78
|
-
|
|
79
|
-
cursor: pointer;
|
|
80
|
-
padding: 0.1rem;
|
|
81
|
-
margin-right: 0.2rem;
|
|
82
|
-
white-space: nowrap;
|
|
75
|
+
@apply inline-block cursor-pointer p-0 mr-2 whitespace-nowrap;
|
|
83
76
|
}
|
|
84
77
|
|
|
85
78
|
.tag.selected {
|
|
86
|
-
|
|
79
|
+
@apply font-bold text-purple-700;
|
|
87
80
|
}
|
|
88
81
|
|
|
89
82
|
.tag.required {
|
|
90
|
-
|
|
83
|
+
@apply text-green-700;
|
|
91
84
|
}
|
|
92
85
|
|
|
93
86
|
.tag.excluded {
|
|
94
|
-
|
|
87
|
+
@apply text-red-700;
|
|
95
88
|
}
|
|
96
89
|
|
|
97
90
|
.tag.positive {
|
|
98
|
-
|
|
91
|
+
@apply text-green-700;
|
|
99
92
|
}
|
|
100
93
|
|
|
101
94
|
.tag.negative {
|
|
102
|
-
|
|
95
|
+
@apply text-red-700;
|
|
103
96
|
}
|
|
104
97
|
</style>
|