feeds-fun 1.16.6 → 1.17.1
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/public/news-filtering-example.png +0 -0
- 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 +191 -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
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="
|
|
3
|
-
<div class="
|
|
4
|
-
<
|
|
5
|
-
<
|
|
6
|
-
|
|
2
|
+
<div class="ffun-side-panel-layout">
|
|
3
|
+
<div class="ffun-side-panel">
|
|
4
|
+
<div class="ffun-page-header">
|
|
5
|
+
<div class="ffun-page-header-title">
|
|
6
|
+
<slot name="main-header"></slot>
|
|
7
|
+
</div>
|
|
8
|
+
</div>
|
|
7
9
|
|
|
8
10
|
<hr />
|
|
9
11
|
|
|
10
|
-
<ul class="
|
|
12
|
+
<ul class="ffun-side-panel-controls-list">
|
|
11
13
|
<li v-if="hasSideMenuItem(1)">
|
|
12
14
|
<slot name="side-menu-item-1"></slot>
|
|
13
15
|
</li>
|
|
@@ -32,7 +34,7 @@
|
|
|
32
34
|
<hr v-if="reloadButton" />
|
|
33
35
|
|
|
34
36
|
<a
|
|
35
|
-
class="ffun-
|
|
37
|
+
class="ffun-side-panel-refresh-button short"
|
|
36
38
|
v-if="reloadButton"
|
|
37
39
|
href="#"
|
|
38
40
|
@click="globalSettings.updateDataVersion()"
|
|
@@ -44,101 +46,43 @@
|
|
|
44
46
|
<slot name="side-footer"></slot>
|
|
45
47
|
</div>
|
|
46
48
|
|
|
47
|
-
<div class="
|
|
48
|
-
<
|
|
49
|
-
<div class="
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
<li class="">
|
|
70
|
-
<a
|
|
71
|
-
href="/api/docs"
|
|
72
|
-
target="_blank"
|
|
73
|
-
class="ffun-header-link"
|
|
74
|
-
style="text-decoration: none"
|
|
75
|
-
@click="events.socialLinkClicked({linkType: 'api'})"
|
|
76
|
-
>API</a
|
|
77
|
-
>
|
|
78
|
-
</li>
|
|
79
|
-
|
|
80
|
-
<li v-if="settings.blog">
|
|
81
|
-
<a
|
|
82
|
-
:href="settings.blog"
|
|
83
|
-
target="_blank"
|
|
84
|
-
class="ffun-header-link"
|
|
85
|
-
style="text-decoration: none"
|
|
86
|
-
@click="events.socialLinkClicked({linkType: 'blog'})"
|
|
87
|
-
>Blog</a
|
|
88
|
-
>
|
|
89
|
-
</li>
|
|
90
|
-
|
|
91
|
-
<li v-if="settings.redditSubreddit">
|
|
92
|
-
<a
|
|
93
|
-
:href="settings.redditSubreddit"
|
|
94
|
-
target="_blank"
|
|
95
|
-
class="ffun-header-link text-xl align-middle"
|
|
96
|
-
title="Reddit"
|
|
97
|
-
style="text-decoration: none"
|
|
98
|
-
@click="events.socialLinkClicked({linkType: 'reddit'})"
|
|
99
|
-
><i class="ti ti-brand-reddit"></i
|
|
100
|
-
></a>
|
|
101
|
-
</li>
|
|
102
|
-
|
|
103
|
-
<li v-if="settings.discordInvite">
|
|
104
|
-
<a
|
|
105
|
-
:href="settings.discordInvite"
|
|
106
|
-
target="_blank"
|
|
107
|
-
class="ffun-header-link text-xl align-middle"
|
|
108
|
-
title="Discord"
|
|
109
|
-
style="text-decoration: none"
|
|
110
|
-
@click="events.socialLinkClicked({linkType: 'discord'})"
|
|
111
|
-
><i class="ti ti-brand-discord"></i
|
|
112
|
-
></a>
|
|
113
|
-
</li>
|
|
114
|
-
|
|
115
|
-
<li v-if="settings.githubRepo">
|
|
116
|
-
<a
|
|
117
|
-
:href="settings.githubRepo"
|
|
118
|
-
target="_blank"
|
|
119
|
-
class="ffun-header-link text-xl align-middle"
|
|
120
|
-
title="GitHub"
|
|
121
|
-
style="text-decoration: none"
|
|
122
|
-
@click="events.socialLinkClicked({linkType: 'github'})">
|
|
123
|
-
<i class="ti ti-brand-github"></i
|
|
124
|
-
></a>
|
|
125
|
-
</li>
|
|
126
|
-
</ul>
|
|
49
|
+
<div class="ffun-body-panel">
|
|
50
|
+
<div class="ffun-page-header">
|
|
51
|
+
<div class="ffun-page-header-left-block">
|
|
52
|
+
<template
|
|
53
|
+
v-for="[mode, props] of e.MainPanelModeProperties"
|
|
54
|
+
:key="mode">
|
|
55
|
+
<a
|
|
56
|
+
v-if="globalSettings.mainPanelMode !== mode"
|
|
57
|
+
:href="router.resolve({name: mode, params: {}}).href"
|
|
58
|
+
class="ffun-page-header-link"
|
|
59
|
+
@click.prevent="router.push({name: mode, params: {}})">
|
|
60
|
+
{{ props.text }}
|
|
61
|
+
</a>
|
|
62
|
+
|
|
63
|
+
<span
|
|
64
|
+
class="ffun-page-header-link-disabled"
|
|
65
|
+
v-else
|
|
66
|
+
>{{ props.text }}</span
|
|
67
|
+
>
|
|
68
|
+
</template>
|
|
69
|
+
|
|
70
|
+
<page-header-external-links :show-api="true" />
|
|
127
71
|
</div>
|
|
128
72
|
|
|
129
|
-
<div class="
|
|
73
|
+
<div class="ffun-page-header-right-block">
|
|
130
74
|
<a
|
|
131
75
|
href="#"
|
|
132
|
-
class="ffun-header-link"
|
|
76
|
+
class="ffun-page-header-link"
|
|
133
77
|
@click.prevent="logout()"
|
|
134
78
|
>logout</a
|
|
135
79
|
>
|
|
136
80
|
</div>
|
|
137
|
-
</
|
|
81
|
+
</div>
|
|
138
82
|
|
|
139
83
|
<hr class="my-2 border-slate-400" />
|
|
140
84
|
|
|
141
|
-
<main class="mb-4">
|
|
85
|
+
<main class="mb-4 px-4 min-h-screen">
|
|
142
86
|
<slot></slot>
|
|
143
87
|
</main>
|
|
144
88
|
|
|
@@ -1,21 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="flex justify-center h-screen">
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
</h1>
|
|
8
|
-
</header>
|
|
9
|
-
|
|
10
|
-
<main>
|
|
11
|
-
<slot></slot>
|
|
12
|
-
</main>
|
|
13
|
-
|
|
14
|
-
<footer>
|
|
15
|
-
<slot name="footer"></slot>
|
|
16
|
-
</footer>
|
|
17
|
-
</div>
|
|
18
|
-
</div>
|
|
2
|
+
<!-- <div class="flex justify-center h-screen"> -->
|
|
3
|
+
<!-- <div class="flex flex-col justify-start items-center text-center p-4"> -->
|
|
4
|
+
<slot></slot>
|
|
5
|
+
<!-- </div> -->
|
|
6
|
+
<!-- </div> -->
|
|
19
7
|
</template>
|
|
20
8
|
|
|
21
9
|
<script lang="ts" setup></script>
|
package/src/logic/events.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as api from "@/logic/api";
|
|
|
2
2
|
import type * as t from "@/logic/types";
|
|
3
3
|
import type {State as TagState} from "@/logic/tagsFilterState";
|
|
4
4
|
|
|
5
|
-
export type TagChangeSource = "
|
|
5
|
+
export type TagChangeSource = "news_tags_filter" | "rules_tags_filter" | "entry_record" | "rule_record";
|
|
6
6
|
|
|
7
7
|
export async function newsLinkOpened({entryId}: {entryId: t.EntryId}) {
|
|
8
8
|
await api.trackEvent({name: "news_link_opened", entry_id: entryId});
|
package/src/logic/types.ts
CHANGED
|
@@ -261,7 +261,7 @@ export function ruleFromJSON({
|
|
|
261
261
|
id: toRuleId(id),
|
|
262
262
|
requiredTags: requiredTags,
|
|
263
263
|
excludedTags: excludedTags,
|
|
264
|
-
allTags: requiredTags.concat(excludedTags),
|
|
264
|
+
allTags: requiredTags.concat(excludedTags).sort(),
|
|
265
265
|
score: score,
|
|
266
266
|
createdAt: new Date(createdAt),
|
|
267
267
|
updatedAt: new Date(updatedAt)
|
|
@@ -344,12 +344,15 @@ export function noInfoTag(uid: string): TagInfo {
|
|
|
344
344
|
return {uid, name: uid, link: null, categories: []};
|
|
345
345
|
}
|
|
346
346
|
|
|
347
|
+
export function fakeTag({uid, name, link, categories}: TagInfo): TagInfo {
|
|
348
|
+
return {uid, name, link, categories};
|
|
349
|
+
}
|
|
350
|
+
|
|
347
351
|
export type UserSetting = {
|
|
348
352
|
readonly kind: string;
|
|
349
353
|
readonly type: string;
|
|
350
354
|
value: string | number | boolean;
|
|
351
355
|
readonly name: string;
|
|
352
|
-
readonly description: string;
|
|
353
356
|
};
|
|
354
357
|
|
|
355
358
|
export function userSettingFromJSON({
|
|
@@ -369,8 +372,7 @@ export function userSettingFromJSON({
|
|
|
369
372
|
kind,
|
|
370
373
|
type,
|
|
371
374
|
value: type === "decimal" ? parseFloat(value as string) : value,
|
|
372
|
-
name
|
|
373
|
-
description
|
|
375
|
+
name
|
|
374
376
|
};
|
|
375
377
|
}
|
|
376
378
|
|
|
@@ -413,25 +415,29 @@ export class Collection {
|
|
|
413
415
|
readonly name: string;
|
|
414
416
|
readonly description: string;
|
|
415
417
|
readonly feedsNumber: number;
|
|
418
|
+
readonly showOnMain: boolean;
|
|
416
419
|
|
|
417
420
|
constructor({
|
|
418
421
|
id,
|
|
419
422
|
guiOrder,
|
|
420
423
|
name,
|
|
421
424
|
description,
|
|
422
|
-
feedsNumber
|
|
425
|
+
feedsNumber,
|
|
426
|
+
showOnMain
|
|
423
427
|
}: {
|
|
424
428
|
id: CollectionId;
|
|
425
429
|
guiOrder: number;
|
|
426
430
|
name: string;
|
|
427
431
|
description: string;
|
|
428
432
|
feedsNumber: number;
|
|
433
|
+
showOnMain: boolean;
|
|
429
434
|
}) {
|
|
430
435
|
this.id = id;
|
|
431
436
|
this.guiOrder = guiOrder;
|
|
432
437
|
this.name = name;
|
|
433
438
|
this.description = description;
|
|
434
439
|
this.feedsNumber = feedsNumber;
|
|
440
|
+
this.showOnMain = showOnMain;
|
|
435
441
|
}
|
|
436
442
|
}
|
|
437
443
|
|
|
@@ -440,20 +446,23 @@ export function collectionFromJSON({
|
|
|
440
446
|
guiOrder,
|
|
441
447
|
name,
|
|
442
448
|
description,
|
|
443
|
-
feedsNumber
|
|
449
|
+
feedsNumber,
|
|
450
|
+
showOnMain
|
|
444
451
|
}: {
|
|
445
452
|
id: string;
|
|
446
453
|
guiOrder: number;
|
|
447
454
|
name: string;
|
|
448
455
|
description: string;
|
|
449
456
|
feedsNumber: number;
|
|
457
|
+
showOnMain: boolean;
|
|
450
458
|
}): Collection {
|
|
451
459
|
return {
|
|
452
460
|
id: toCollectionId(id),
|
|
453
461
|
guiOrder: guiOrder,
|
|
454
462
|
name: name,
|
|
455
463
|
description: description,
|
|
456
|
-
feedsNumber: feedsNumber
|
|
464
|
+
feedsNumber: feedsNumber,
|
|
465
|
+
showOnMain: showOnMain
|
|
457
466
|
};
|
|
458
467
|
}
|
|
459
468
|
|
package/src/logic/utils.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import _ from "lodash";
|
|
2
|
+
import DOMPurify from "dompurify";
|
|
2
3
|
|
|
3
4
|
export function timeSince(date: Date) {
|
|
4
5
|
const now = new Date();
|
|
@@ -67,3 +68,31 @@ export function faviconForUrl(url: string): string | null {
|
|
|
67
68
|
return null;
|
|
68
69
|
}
|
|
69
70
|
}
|
|
71
|
+
|
|
72
|
+
export function purifyTitle({raw, default_}: {raw: string | null; default_: string}) {
|
|
73
|
+
if (raw === null) {
|
|
74
|
+
return default_;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let title = DOMPurify.sanitize(raw, {ALLOWED_TAGS: []}).trim();
|
|
78
|
+
|
|
79
|
+
if (title.length === 0) {
|
|
80
|
+
return default_;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return title;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function purifyBody({raw, default_}: {raw: string | null; default_: string}) {
|
|
87
|
+
if (raw === null) {
|
|
88
|
+
return default_;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
let body = DOMPurify.sanitize(raw).trim();
|
|
92
|
+
|
|
93
|
+
if (body.length === 0) {
|
|
94
|
+
return default_;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return body;
|
|
98
|
+
}
|
package/src/main.ts
CHANGED
|
@@ -9,18 +9,15 @@ import "./style.css";
|
|
|
9
9
|
import FeedsList from "./components/FeedsList.vue";
|
|
10
10
|
import EntriesList from "./components/EntriesList.vue";
|
|
11
11
|
import RulesList from "./components/RulesList.vue";
|
|
12
|
-
import TagsList from "./components/TagsList.vue";
|
|
13
12
|
import ConfigSelector from "./components/ConfigSelector.vue";
|
|
14
13
|
import ConfigFlag from "./components/ConfigFlag.vue";
|
|
15
14
|
import EntryForList from "./components/EntryForList.vue";
|
|
16
15
|
import RuleConstructor from "./components/RuleConstructor.vue";
|
|
17
|
-
import TagsFilter from "./components/TagsFilter.vue";
|
|
18
16
|
import DiscoveryForm from "./components/DiscoveryForm.vue";
|
|
19
17
|
import FeedInfo from "./components/FeedInfo.vue";
|
|
20
18
|
import OpmlUpload from "./components/OPMLUpload.vue";
|
|
21
19
|
import FeedForList from "./components/FeedForList.vue";
|
|
22
20
|
import SupertokensLogin from "./components/SupertokensLogin.vue";
|
|
23
|
-
import FfunTag from "./components/FfunTag.vue";
|
|
24
21
|
import SimplePagination from "./components/SimplePagination.vue";
|
|
25
22
|
import UserSetting from "./components/UserSetting.vue";
|
|
26
23
|
import TokensCost from "./components/TokensCost.vue";
|
|
@@ -28,6 +25,16 @@ import FaviconElement from "./components/FaviconElement.vue";
|
|
|
28
25
|
import RuleForList from "./components/RuleForList.vue";
|
|
29
26
|
import UserSettingForNotification from "./components/UserSettingForNotification.vue";
|
|
30
27
|
|
|
28
|
+
import TagBase from "./components/tags/Base.vue";
|
|
29
|
+
import EntryTag from "./components/tags/EntryTag.vue";
|
|
30
|
+
import EntryTagsList from "./components/tags/EntryTagsList.vue";
|
|
31
|
+
import FilterTag from "./components/tags/FilterTag.vue";
|
|
32
|
+
import TagsFilter from "./components/tags/TagsFilter.vue";
|
|
33
|
+
import RuleTag from "./components/tags/RuleTag.vue";
|
|
34
|
+
import FakeTag from "./components/tags/FakeTag.vue";
|
|
35
|
+
|
|
36
|
+
import PageHeaderExternalLinks from "./components/page_header/ExternalLinks.vue";
|
|
37
|
+
|
|
31
38
|
import NotificationsApiKey from "./components/notifications/ApiKey.vue";
|
|
32
39
|
import NotificationsCreateRuleHelp from "./components/notifications/CreateRuleHelp.vue";
|
|
33
40
|
import Notifications from "./components/notifications/Block.vue";
|
|
@@ -41,13 +48,22 @@ import CollectionsSubscribingProgress from "./components/collections/Subscribing
|
|
|
41
48
|
import CollectionsFeedItem from "./components/collections/FeedItem.vue";
|
|
42
49
|
|
|
43
50
|
import ScoreSelector from "./inputs/ScoreSelector.vue";
|
|
44
|
-
import InputMarker from "./inputs/Marker.vue";
|
|
45
51
|
|
|
46
|
-
import
|
|
52
|
+
import ExternalUrl from "./values/ExternalUrl.vue";
|
|
47
53
|
import ValueFeedId from "./values/FeedId.vue";
|
|
48
54
|
import ValueDateTime from "./values/DateTime.vue";
|
|
49
55
|
import ValueScore from "./values/Score.vue";
|
|
50
56
|
|
|
57
|
+
import BodyListReverseTimeColumn from "./components/body_list/ReverseTimeColumn.vue";
|
|
58
|
+
import BodyListFaviconColumn from "./components/body_list/FaviconColumn.vue";
|
|
59
|
+
import BodyListEntryBody from "./components/body_list/EntryBody.vue";
|
|
60
|
+
|
|
61
|
+
import MainDescription from "./components/main/Description.vue";
|
|
62
|
+
import MainItem from "./components/main/Item.vue";
|
|
63
|
+
import MainNewsTitle from "./components/main/NewsTitle.vue";
|
|
64
|
+
import MainHeaderLine from "./components/main/HeaderLine.vue";
|
|
65
|
+
import MainBlock from "./components/main/Block.vue";
|
|
66
|
+
|
|
51
67
|
import WideLayout from "./layouts/WideLayout.vue";
|
|
52
68
|
import SidePanelLayout from "./layouts/SidePanelLayout.vue";
|
|
53
69
|
|
|
@@ -60,18 +76,15 @@ const app = createApp(App);
|
|
|
60
76
|
app.component("FeedsList", FeedsList);
|
|
61
77
|
app.component("EntriesList", EntriesList);
|
|
62
78
|
app.component("RulesList", RulesList);
|
|
63
|
-
app.component("TagsList", TagsList);
|
|
64
79
|
app.component("ConfigSelector", ConfigSelector);
|
|
65
80
|
app.component("ConfigFlag", ConfigFlag);
|
|
66
81
|
app.component("EntryForList", EntryForList);
|
|
67
82
|
app.component("RuleConstructor", RuleConstructor);
|
|
68
|
-
app.component("TagsFilter", TagsFilter);
|
|
69
83
|
app.component("DiscoveryForm", DiscoveryForm);
|
|
70
84
|
app.component("FeedInfo", FeedInfo);
|
|
71
85
|
app.component("OpmlUpload", OpmlUpload);
|
|
72
86
|
app.component("FeedForList", FeedForList);
|
|
73
87
|
app.component("SupertokensLogin", SupertokensLogin);
|
|
74
|
-
app.component("FfunTag", FfunTag);
|
|
75
88
|
app.component("SimplePagination", SimplePagination);
|
|
76
89
|
app.component("UserSetting", UserSetting);
|
|
77
90
|
app.component("TokensCost", TokensCost);
|
|
@@ -79,6 +92,16 @@ app.component("FaviconElement", FaviconElement);
|
|
|
79
92
|
app.component("RuleForList", RuleForList);
|
|
80
93
|
app.component("UserSettingForNotification", UserSettingForNotification);
|
|
81
94
|
|
|
95
|
+
app.component("TagBase", TagBase);
|
|
96
|
+
app.component("EntryTag", EntryTag);
|
|
97
|
+
app.component("EntryTagsList", EntryTagsList);
|
|
98
|
+
app.component("FilterTag", FilterTag);
|
|
99
|
+
app.component("TagsFilter", TagsFilter);
|
|
100
|
+
app.component("RuleTag", RuleTag);
|
|
101
|
+
app.component("FakeTag", FakeTag);
|
|
102
|
+
|
|
103
|
+
app.component("PageHeaderExternalLinks", PageHeaderExternalLinks);
|
|
104
|
+
|
|
82
105
|
app.component("NotificationsApiKey", NotificationsApiKey);
|
|
83
106
|
app.component("NotificationsCreateRuleHelp", NotificationsCreateRuleHelp);
|
|
84
107
|
app.component("Notifications", Notifications);
|
|
@@ -92,13 +115,22 @@ app.component("CollectionsSubscribingProgress", CollectionsSubscribingProgress);
|
|
|
92
115
|
app.component("CollectionsFeedItem", CollectionsFeedItem);
|
|
93
116
|
|
|
94
117
|
app.component("ScoreSelector", ScoreSelector);
|
|
95
|
-
app.component("InputMarker", InputMarker);
|
|
96
118
|
|
|
97
|
-
app.component("
|
|
119
|
+
app.component("ExternalUrl", ExternalUrl);
|
|
98
120
|
app.component("ValueFeedId", ValueFeedId);
|
|
99
121
|
app.component("ValueDateTime", ValueDateTime);
|
|
100
122
|
app.component("ValueScore", ValueScore);
|
|
101
123
|
|
|
124
|
+
app.component("BodyListReverseTimeColumn", BodyListReverseTimeColumn);
|
|
125
|
+
app.component("BodyListFaviconColumn", BodyListFaviconColumn);
|
|
126
|
+
app.component("BodyListEntryBody", BodyListEntryBody);
|
|
127
|
+
|
|
128
|
+
app.component("MainDescription", MainDescription);
|
|
129
|
+
app.component("MainItem", MainItem);
|
|
130
|
+
app.component("MainNewsTitle", MainNewsTitle);
|
|
131
|
+
app.component("MainHeaderLine", MainHeaderLine);
|
|
132
|
+
app.component("MainBlock", MainBlock);
|
|
133
|
+
|
|
102
134
|
app.component("WideLayout", WideLayout);
|
|
103
135
|
app.component("SidePanelLayout", SidePanelLayout);
|
|
104
136
|
|
package/src/style.css
CHANGED
|
@@ -1,102 +1,12 @@
|
|
|
1
1
|
@import url("https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/tabler-icons.min.css");
|
|
2
2
|
|
|
3
|
-
@
|
|
4
|
-
@
|
|
5
|
-
@
|
|
6
|
-
|
|
7
|
-
@
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
@apply text-3xl font-bold leading-tight my-4;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
h2 {
|
|
17
|
-
@apply text-2xl font-semibold leading-relaxed my-3;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
h3 {
|
|
21
|
-
@apply text-xl font-semibold leading-relaxed my-2;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
hr {
|
|
25
|
-
@apply border-slate-400 my-2;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
p,
|
|
29
|
-
ul,
|
|
30
|
-
ol,
|
|
31
|
-
table {
|
|
32
|
-
@apply mb-1;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
p a {
|
|
36
|
-
@apply text-blue-600 hover:text-blue-800 cursor-pointer;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.ffun-normalized-text ul {
|
|
40
|
-
@apply list-disc list-inside;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.ffun-normalized-text code {
|
|
44
|
-
@apply bg-slate-800 px-1 rounded bg-opacity-10 text-sm;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
.ffun-info-common {
|
|
48
|
-
@apply ffun-normalized-text border-2 p-2 my-1 rounded border-slate-200;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
.ffun-info-good {
|
|
52
|
-
@apply ffun-info-common bg-green-50;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
.ffun-info-bad {
|
|
56
|
-
@apply ffun-info-common bg-red-50;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
.ffun-info-warning {
|
|
60
|
-
@apply ffun-info-common bg-orange-50;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
.ffun-info-attention {
|
|
64
|
-
@apply ffun-info-common bg-purple-50;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
.ffun-header-link {
|
|
68
|
-
@apply text-blue-600 hover:text-blue-900 cursor-pointer text-lg;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
.ffun-normal-link {
|
|
72
|
-
@apply text-blue-600 hover:text-blue-800 cursor-pointer;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
.ffun-header-link-disabled {
|
|
76
|
-
@apply text-lg underline underline-offset-4;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
.ffun-input-common {
|
|
80
|
-
@apply border-2 rounded bg-slate-50 hover:bg-blue-50 enabled:hover:border-blue-400 px-1 disabled:bg-orange-50;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
.ffun-form-button {
|
|
84
|
-
@apply ffun-input-common border-blue-300 disabled:bg-blue-100/25 py-1;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
.ffun-file-button {
|
|
88
|
-
@apply file:border-2 file:rounded file:bg-slate-50 file:hover:bg-blue-50 file:enabled:hover:border-blue-400 file:px-1 file:disabled:bg-orange-50 file:border-blue-300 file:disabled:bg-blue-700/75 file:py-1 file:shadow-none file:border-solid text-slate-500;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
.ffun-config-flag {
|
|
92
|
-
@apply ffun-input-common border-blue-300 disabled:bg-blue-700/75 py-0;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
.ffun-input {
|
|
96
|
-
@apply ffun-input-common border-blue-200 focus:border-blue-300 focus:outline-none placeholder-gray-500 py-1;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
.ffun-checkbox {
|
|
100
|
-
@apply ffun-input-common h-4 w-4 align-middle;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
3
|
+
@import "tailwindcss/base";
|
|
4
|
+
@import "tailwindcss/components";
|
|
5
|
+
@import "tailwindcss/utilities";
|
|
6
|
+
|
|
7
|
+
@import "./css/base.css";
|
|
8
|
+
@import "./css/side_panel_layout.css";
|
|
9
|
+
@import "./css/tags.css";
|
|
10
|
+
@import "./css/inputs.css";
|
|
11
|
+
@import "./css/panels.css";
|
|
12
|
+
@import "./css/page_header.css";
|
package/src/values/DateTime.vue
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<a
|
|
3
|
-
:href="
|
|
3
|
+
:href="url"
|
|
4
4
|
target="_blank"
|
|
5
|
-
rel="noopener noreferrer"
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
rel="noopener noreferrer">
|
|
6
|
+
{{ renderedText }}
|
|
7
|
+
<i class="ti ti-external-link" />
|
|
8
|
+
</a>
|
|
8
9
|
</template>
|
|
9
10
|
|
|
10
11
|
<script lang="ts" setup>
|
|
11
12
|
import {computed} from "vue";
|
|
12
13
|
import type * as t from "@/logic/types";
|
|
13
14
|
|
|
14
|
-
const properties = defineProps<{
|
|
15
|
+
const properties = defineProps<{url: t.URL; text?: string | null}>();
|
|
15
16
|
|
|
16
17
|
const renderedText = computed(() => {
|
|
17
18
|
if (properties.text) {
|
|
18
19
|
return properties.text;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
return properties.
|
|
22
|
+
return properties.url;
|
|
22
23
|
});
|
|
23
24
|
</script>
|
|
24
25
|
|
|
@@ -2,12 +2,9 @@
|
|
|
2
2
|
<side-panel-layout :reload-button="false">
|
|
3
3
|
<template #main-header> Collections </template>
|
|
4
4
|
|
|
5
|
-
<div class="ffun-info-
|
|
6
|
-
<p
|
|
7
|
-
|
|
8
|
-
free of charge.</p
|
|
9
|
-
>
|
|
10
|
-
<p>Subscribe to some and enjoy the full power of Feeds Fun!</p>
|
|
5
|
+
<div class="ffun-info-common">
|
|
6
|
+
<p>We've prepared thematic collections just for you.</p>
|
|
7
|
+
<p>News from collections are always tagged, ensuring you get the full power of Feeds Fun!</p>
|
|
11
8
|
</div>
|
|
12
9
|
|
|
13
10
|
<div
|
|
@@ -8,27 +8,25 @@
|
|
|
8
8
|
:collections-notification_="false"
|
|
9
9
|
:collections-warning_="true" />
|
|
10
10
|
|
|
11
|
-
<
|
|
11
|
+
<h3>Load feeds from an OPML file</h3>
|
|
12
12
|
|
|
13
|
-
<div class="ffun-info-
|
|
13
|
+
<div class="ffun-info-common">
|
|
14
14
|
<p>
|
|
15
|
-
<
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
>OPML</a
|
|
19
|
-
>
|
|
15
|
+
<external-url
|
|
16
|
+
url="https://en.wikipedia.org/wiki/OPML"
|
|
17
|
+
text="OPML" />
|
|
20
18
|
is a widely-used format for transferring news feed lists between platforms.
|
|
21
19
|
</p>
|
|
22
20
|
|
|
23
21
|
<p
|
|
24
|
-
>Export your feeds from your old reader in OPML format and import them into
|
|
25
|
-
transition
|
|
22
|
+
>Export your feeds from your old reader in OPML format and import them into Feeds Fun to seamlessly
|
|
23
|
+
transition.</p
|
|
26
24
|
>
|
|
27
25
|
</div>
|
|
28
26
|
|
|
29
|
-
<opml-upload />
|
|
27
|
+
<opml-upload class="mt-4" />
|
|
30
28
|
|
|
31
|
-
<
|
|
29
|
+
<h3>Search for a feed</h3>
|
|
32
30
|
|
|
33
31
|
<discovery-form />
|
|
34
32
|
</side-panel-layout>
|