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.
Files changed (63) hide show
  1. package/package.json +1 -1
  2. package/src/components/DiscoveryForm.vue +3 -5
  3. package/src/components/EntriesList.vue +1 -11
  4. package/src/components/EntryForList.vue +54 -67
  5. package/src/components/FeedForList.vue +29 -64
  6. package/src/components/FeedInfo.vue +12 -14
  7. package/src/components/FeedsList.vue +2 -1
  8. package/src/components/OPMLUpload.vue +3 -3
  9. package/src/components/RuleConstructor.vue +12 -6
  10. package/src/components/RuleForList.vue +25 -24
  11. package/src/components/RulesList.vue +2 -1
  12. package/src/components/SimplePagination.vue +2 -2
  13. package/src/components/SupertokensLogin.vue +5 -6
  14. package/src/components/UserSetting.vue +7 -12
  15. package/src/components/UserSettingForNotification.vue +4 -3
  16. package/src/components/body_list/EntryBody.vue +43 -0
  17. package/src/components/body_list/FaviconColumn.vue +24 -0
  18. package/src/components/body_list/ReverseTimeColumn.vue +28 -0
  19. package/src/components/collections/Block.vue +1 -1
  20. package/src/components/collections/BlockItem.vue +4 -3
  21. package/src/components/collections/DetailedItem.vue +4 -10
  22. package/src/components/collections/FeedItem.vue +31 -24
  23. package/src/components/collections/Notification.vue +6 -8
  24. package/src/components/collections/SubscribingProgress.vue +14 -17
  25. package/src/components/collections/Warning.vue +36 -38
  26. package/src/components/main/Block.vue +5 -0
  27. package/src/components/main/Description.vue +51 -0
  28. package/src/components/main/HeaderLine.vue +7 -0
  29. package/src/components/main/Item.vue +27 -0
  30. package/src/components/main/NewsTitle.vue +26 -0
  31. package/src/components/notifications/ApiKey.vue +14 -5
  32. package/src/components/notifications/CreateRuleHelp.vue +10 -11
  33. package/src/components/page_header/ExternalLinks.vue +58 -0
  34. package/src/components/tags/Base.vue +28 -0
  35. package/src/components/tags/EntryTag.vue +73 -0
  36. package/src/components/{TagsList.vue → tags/EntryTagsList.vue} +8 -10
  37. package/src/components/tags/FakeTag.vue +35 -0
  38. package/src/components/{FfunTag.vue → tags/FilterTag.vue} +36 -52
  39. package/src/components/tags/RuleTag.vue +67 -0
  40. package/src/components/{TagsFilter.vue → tags/TagsFilter.vue} +12 -8
  41. package/src/css/base.css +38 -0
  42. package/src/css/inputs.css +49 -0
  43. package/src/css/page_header.css +34 -0
  44. package/src/css/panels.css +49 -0
  45. package/src/css/side_panel_layout.css +34 -0
  46. package/src/css/tags.css +44 -0
  47. package/src/layouts/SidePanelLayout.vue +35 -91
  48. package/src/layouts/WideLayout.vue +5 -17
  49. package/src/logic/events.ts +1 -1
  50. package/src/logic/types.ts +16 -7
  51. package/src/logic/utils.ts +29 -0
  52. package/src/main.ts +42 -10
  53. package/src/style.css +10 -100
  54. package/src/values/DateTime.vue +1 -1
  55. package/src/values/{URL.vue → ExternalUrl.vue} +7 -6
  56. package/src/views/CollectionsView.vue +3 -6
  57. package/src/views/DiscoveryView.vue +9 -11
  58. package/src/views/FeedsView.vue +3 -2
  59. package/src/views/MainView.vue +189 -44
  60. package/src/views/NewsView.vue +2 -1
  61. package/src/views/RulesView.vue +6 -3
  62. package/src/views/SettingsView.vue +92 -33
  63. package/src/inputs/Marker.vue +0 -54
@@ -1,13 +1,15 @@
1
1
  <template>
2
- <div class="flex divide-x">
3
- <div class="p-4 w-60 bg-slate-200 flex-shrink-0">
4
- <h2 class="leading-8 my-0">
5
- <slot name="main-header"></slot>
6
- </h2>
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="space-y-2">
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-form-button p-1 my-1 block w-full text-center"
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="flex-grow p-4">
48
- <header class="flex items-center leading-8">
49
- <div class="display:flex items-center mr-auto">
50
- <ul class="list-none m-0 p-0 flex space-x-2">
51
- <li
52
- v-for="[mode, props] of e.MainPanelModeProperties"
53
- :key="mode">
54
- <a
55
- v-if="globalSettings.mainPanelMode !== mode"
56
- :href="router.resolve({name: mode, params: {}}).href"
57
- class="ffun-header-link"
58
- @click.prevent="router.push({name: mode, params: {}})">
59
- {{ props.text }}
60
- </a>
61
-
62
- <span
63
- class="ffun-header-link-disabled cursor-default"
64
- v-else
65
- >{{ props.text }}</span
66
- >
67
- </li>
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="flex items-center ml-4">
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
- </header>
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
- <div class="flex flex-col justify-start items-center text-center p-4">
4
- <header>
5
- <h1>
6
- <slot name="header"></slot>
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>
@@ -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 = "tag_filter" | "entry_record";
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});
@@ -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
 
@@ -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 ValueUrl from "./values/URL.vue";
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("ValueUrl", ValueUrl);
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
- @tailwind base;
4
- @tailwind components;
5
- @tailwind utilities;
6
-
7
- @layer base {
8
- html {
9
- @apply font-serif bg-slate-100;
10
- }
11
-
12
- h1 {
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";
@@ -1,5 +1,5 @@
1
1
  <template>
2
- {{ text }}
2
+ <span>{{ text }}</span>
3
3
  </template>
4
4
 
5
5
  <script lang="ts" setup>
@@ -1,24 +1,25 @@
1
1
  <template>
2
2
  <a
3
- :href="value"
3
+ :href="url"
4
4
  target="_blank"
5
- rel="noopener noreferrer"
6
- >{{ renderedText }}</a
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<{value: t.URL; text?: string | null}>();
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.value;
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-attention">
6
- <p
7
- >We've prepared some ready-to-use thematic collections just for you. All the feeds in them are fully tagged
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
- <h2>Load feeds from an OPML file</h2>
11
+ <h3>Load feeds from an OPML file</h3>
12
12
 
13
- <div class="ffun-info-good">
13
+ <div class="ffun-info-common">
14
14
  <p>
15
- <a
16
- href="https://en.wikipedia.org/wiki/OPML"
17
- target="_blank"
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 our reader to seamlessly
25
- transition!</p
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
- <h2>Search for a feed</h2>
29
+ <h3>Search for a feed</h3>
32
30
 
33
31
  <discovery-form />
34
32
  </side-panel-layout>