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.
Files changed (64) hide show
  1. package/package.json +1 -1
  2. package/public/news-filtering-example.png +0 -0
  3. package/src/components/DiscoveryForm.vue +3 -5
  4. package/src/components/EntriesList.vue +1 -11
  5. package/src/components/EntryForList.vue +54 -67
  6. package/src/components/FeedForList.vue +29 -64
  7. package/src/components/FeedInfo.vue +12 -14
  8. package/src/components/FeedsList.vue +2 -1
  9. package/src/components/OPMLUpload.vue +3 -3
  10. package/src/components/RuleConstructor.vue +12 -6
  11. package/src/components/RuleForList.vue +25 -24
  12. package/src/components/RulesList.vue +2 -1
  13. package/src/components/SimplePagination.vue +2 -2
  14. package/src/components/SupertokensLogin.vue +5 -6
  15. package/src/components/UserSetting.vue +7 -12
  16. package/src/components/UserSettingForNotification.vue +4 -3
  17. package/src/components/body_list/EntryBody.vue +43 -0
  18. package/src/components/body_list/FaviconColumn.vue +24 -0
  19. package/src/components/body_list/ReverseTimeColumn.vue +28 -0
  20. package/src/components/collections/Block.vue +1 -1
  21. package/src/components/collections/BlockItem.vue +4 -3
  22. package/src/components/collections/DetailedItem.vue +4 -10
  23. package/src/components/collections/FeedItem.vue +31 -24
  24. package/src/components/collections/Notification.vue +6 -8
  25. package/src/components/collections/SubscribingProgress.vue +14 -17
  26. package/src/components/collections/Warning.vue +36 -38
  27. package/src/components/main/Block.vue +5 -0
  28. package/src/components/main/Description.vue +51 -0
  29. package/src/components/main/HeaderLine.vue +7 -0
  30. package/src/components/main/Item.vue +27 -0
  31. package/src/components/main/NewsTitle.vue +26 -0
  32. package/src/components/notifications/ApiKey.vue +14 -5
  33. package/src/components/notifications/CreateRuleHelp.vue +10 -11
  34. package/src/components/page_header/ExternalLinks.vue +58 -0
  35. package/src/components/tags/Base.vue +28 -0
  36. package/src/components/tags/EntryTag.vue +73 -0
  37. package/src/components/{TagsList.vue → tags/EntryTagsList.vue} +8 -10
  38. package/src/components/tags/FakeTag.vue +35 -0
  39. package/src/components/{FfunTag.vue → tags/FilterTag.vue} +36 -52
  40. package/src/components/tags/RuleTag.vue +67 -0
  41. package/src/components/{TagsFilter.vue → tags/TagsFilter.vue} +12 -8
  42. package/src/css/base.css +38 -0
  43. package/src/css/inputs.css +49 -0
  44. package/src/css/page_header.css +34 -0
  45. package/src/css/panels.css +49 -0
  46. package/src/css/side_panel_layout.css +34 -0
  47. package/src/css/tags.css +44 -0
  48. package/src/layouts/SidePanelLayout.vue +35 -91
  49. package/src/layouts/WideLayout.vue +5 -17
  50. package/src/logic/events.ts +1 -1
  51. package/src/logic/types.ts +16 -7
  52. package/src/logic/utils.ts +29 -0
  53. package/src/main.ts +42 -10
  54. package/src/style.css +10 -100
  55. package/src/values/DateTime.vue +1 -1
  56. package/src/values/{URL.vue → ExternalUrl.vue} +7 -6
  57. package/src/views/CollectionsView.vue +3 -6
  58. package/src/views/DiscoveryView.vue +9 -11
  59. package/src/views/FeedsView.vue +3 -2
  60. package/src/views/MainView.vue +191 -44
  61. package/src/views/NewsView.vue +2 -1
  62. package/src/views/RulesView.vue +6 -3
  63. package/src/views/SettingsView.vue +92 -33
  64. package/src/inputs/Marker.vue +0 -54
@@ -0,0 +1,28 @@
1
+ <template>
2
+ <span>
3
+ {{ tagInfo.name }}
4
+
5
+ <a
6
+ v-if="tagInfo.link"
7
+ :href="tagInfo.link"
8
+ target="_blank"
9
+ @click.stop=""
10
+ rel="noopener noreferrer">
11
+ <i class="ti ti-external-link align-middle" />
12
+ </a>
13
+ </span>
14
+ </template>
15
+
16
+ <script lang="ts" setup>
17
+ import * as t from "@/logic/types";
18
+ import {computed, ref, inject} from "vue";
19
+ import type {Ref} from "vue";
20
+ import {useTagsStore} from "@/stores/tags";
21
+ import * as tagsFilterState from "@/logic/tagsFilterState";
22
+ import * as asserts from "@/logic/asserts";
23
+ import * as events from "@/logic/events";
24
+
25
+ const properties = defineProps<{
26
+ tagInfo: t.TagInfo;
27
+ }>();
28
+ </script>
@@ -0,0 +1,73 @@
1
+ <template>
2
+ <div
3
+ :class="classes"
4
+ :title="tooltip"
5
+ @click.prevent="onClick()">
6
+ <tag-base :tag-info="tagInfo" />
7
+ </div>
8
+ </template>
9
+
10
+ <script lang="ts" setup>
11
+ import * as t from "@/logic/types";
12
+ import {computed, ref, inject} from "vue";
13
+ import type {Ref} from "vue";
14
+ import {useTagsStore} from "@/stores/tags";
15
+ import * as tagsFilterState from "@/logic/tagsFilterState";
16
+ import * as asserts from "@/logic/asserts";
17
+ import * as events from "@/logic/events";
18
+
19
+ const tagsStore = useTagsStore();
20
+
21
+ const tagsStates = inject<Ref<tagsFilterState.Storage>>("tagsStates");
22
+
23
+ asserts.defined(tagsStates);
24
+
25
+ const properties = defineProps<{
26
+ uid: string;
27
+ cssModifier: string;
28
+ count: number;
29
+ }>();
30
+
31
+ const tagInfo = computed(() => {
32
+ const tagInfo = tagsStore.tags[properties.uid];
33
+
34
+ if (tagInfo) {
35
+ return tagInfo;
36
+ }
37
+
38
+ tagsStore.requestTagInfo({tagUid: properties.uid});
39
+
40
+ return t.noInfoTag(properties.uid);
41
+ });
42
+
43
+ const classes = computed(() => {
44
+ const result: {[key: string]: boolean} = {};
45
+
46
+ result[properties.cssModifier] = true;
47
+ result["ffun-entry-tag"] = true;
48
+
49
+ if (tagsStates.value.requiredTags[properties.uid]) {
50
+ result["required"] = true;
51
+ }
52
+
53
+ if (tagsStates.value.excludedTags[properties.uid]) {
54
+ result["excluded"] = true;
55
+ }
56
+
57
+ return result;
58
+ });
59
+
60
+ const changeSource = "entry_record";
61
+
62
+ async function onClick() {
63
+ asserts.defined(tagsStates);
64
+
65
+ let changeInfo = tagsStates.value.onTagClicked({tag: properties.uid});
66
+
67
+ await events.tagStateChanged({tag: properties.uid, source: changeSource, ...changeInfo});
68
+ }
69
+
70
+ const tooltip = computed(() => {
71
+ return `Articles with this tag: ${properties.count}`;
72
+ });
73
+ </script>
@@ -1,17 +1,15 @@
1
1
  <template>
2
2
  <div>
3
- <div class="text-base">
4
- <ffun-tag
3
+ <div class="overflow-y-auto max-h-36">
4
+ <entry-tag
5
5
  v-for="tag of displayedTags"
6
6
  :key="tag"
7
7
  :uid="tag"
8
- :count="tagsCount[tag]"
9
- :secondary-mode="tagMode(tag)"
10
- count-mode="tooltip"
11
- change-source="entry_record" />
8
+ :css-modifier="tagMode(tag)"
9
+ :count="tagsCount[tag]" />
12
10
 
13
11
  <a
14
- class=""
12
+ class="text-base whitespace-nowrap"
15
13
  title="Click on the news title to open it and see all tags"
16
14
  href="#"
17
15
  @click.prevent="emit('request-to-show-all')"
@@ -50,15 +48,15 @@
50
48
 
51
49
  function tagMode(tag: string) {
52
50
  if (!properties.contributions) {
53
- return null;
51
+ return "neurtral";
54
52
  }
55
53
 
56
54
  if (!(tag in properties.contributions)) {
57
- return null;
55
+ return "neurtral";
58
56
  }
59
57
 
60
58
  if (properties.contributions[tag] == 0) {
61
- return null;
59
+ return "neurtral";
62
60
  }
63
61
 
64
62
  if (properties.contributions[tag] > 0) {
@@ -0,0 +1,35 @@
1
+ <template>
2
+ <div :class="classes">
3
+ <tag-base :tag-info="tagInfo" />
4
+ </div>
5
+ </template>
6
+
7
+ <script lang="ts" setup>
8
+ import * as t from "@/logic/types";
9
+ import {computed, ref, inject} from "vue";
10
+ import type {Ref} from "vue";
11
+ import {useTagsStore} from "@/stores/tags";
12
+ import * as tagsFilterState from "@/logic/tagsFilterState";
13
+ import * as asserts from "@/logic/asserts";
14
+ import * as events from "@/logic/events";
15
+
16
+ const properties = defineProps<{
17
+ uid: string;
18
+ name: string;
19
+ link: string | null;
20
+ cssModifier: string;
21
+ }>();
22
+
23
+ const tagInfo = computed(() => {
24
+ return t.fakeTag({uid: properties.uid, name: properties.name, link: properties.link, categories: []});
25
+ });
26
+
27
+ const classes = computed(() => {
28
+ const result: {[key: string]: boolean} = {};
29
+
30
+ result[properties.cssModifier] = true;
31
+ result["ffun-entry-tag"] = true;
32
+
33
+ return result;
34
+ });
35
+ </script>
@@ -1,29 +1,25 @@
1
1
  <template>
2
- <div class="inline-block">
2
+ <div class="inline-block w-full">
3
3
  <a
4
4
  href="#"
5
5
  v-if="showSwitch"
6
- class="pr-1"
6
+ class="pr-1 ffun-tag-switch"
7
+ :title="switchTooltip"
7
8
  @click.prevent="onRevers()"
8
9
  >⇄</a
9
10
  >
10
- <div
11
+ <span
11
12
  :class="classes"
12
- :title="tooltip"
13
+ :title="tagTooltip"
13
14
  @click.prevent="onClick()">
14
- <span v-if="countMode == 'prefix'">[{{ count }}]</span>
15
-
16
- {{ tagInfo.name }}
17
-
18
- <a
19
- v-if="tagInfo.link"
20
- :href="tagInfo.link"
21
- target="_blank"
22
- @click.stop=""
23
- rel="noopener noreferrer">
24
- &#8599;
25
- </a>
26
- </div>
15
+ <span
16
+ v-if="showCount"
17
+ class="pr-1"
18
+ >[{{ count }}]</span
19
+ >
20
+
21
+ <tag-base :tag-info="tagInfo" />
22
+ </span>
27
23
  </div>
28
24
  </template>
29
25
 
@@ -45,10 +41,9 @@
45
41
  const properties = defineProps<{
46
42
  uid: string;
47
43
  count?: number | null;
48
- countMode?: string | null;
49
- secondaryMode?: string | null;
50
- showSwitch?: boolean | null;
51
- changeSource: events.TagChangeSource;
44
+ showCount: boolean;
45
+ showSwitch: boolean;
46
+ changeSource: "news_tags_filter" | "rules_tags_filter";
52
47
  }>();
53
48
 
54
49
  const tagInfo = computed(() => {
@@ -64,9 +59,11 @@
64
59
  });
65
60
 
66
61
  const classes = computed(() => {
67
- const result: {[key: string]: boolean} = {
68
- tag: true
69
- };
62
+ const result: {[key: string]: boolean} = {};
63
+
64
+ result["ffun-filter-tag"] = true;
65
+ result["inline-block"] = true;
66
+ result["w-full"] = true;
70
67
 
71
68
  if (tagsStates.value.requiredTags[properties.uid]) {
72
69
  result["required"] = true;
@@ -76,10 +73,6 @@
76
73
  result["excluded"] = true;
77
74
  }
78
75
 
79
- if (properties.secondaryMode) {
80
- result[properties.secondaryMode] = true;
81
- }
82
-
83
76
  return result;
84
77
  });
85
78
 
@@ -99,32 +92,23 @@
99
92
  await events.tagStateChanged({tag: properties.uid, source: properties.changeSource, ...changeInfo});
100
93
  }
101
94
 
102
- const tooltip = computed(() => {
103
- if (properties.countMode == "tooltip" && properties.count) {
104
- return `articles with this tag: ${properties.count}`;
95
+ const switchTooltip = computed(() => {
96
+ if (tagsStates.value.requiredTags[properties.uid]) {
97
+ return "Switch to show news without this tag";
105
98
  }
106
- return "";
107
- });
108
- </script>
109
-
110
- <style scoped>
111
- .tag {
112
- @apply inline-block cursor-pointer p-0 mr-2 whitespace-nowrap hover:bg-green-100 px-1 hover:rounded-lg;
113
- }
114
99
 
115
- .tag.required {
116
- @apply text-green-700 font-bold;
117
- }
100
+ if (tagsStates.value.excludedTags[properties.uid]) {
101
+ return "Switch to show news with this tag";
102
+ }
118
103
 
119
- .tag.excluded {
120
- @apply text-red-700 font-bold;
121
- }
104
+ return "Click to toggle";
105
+ });
122
106
 
123
- .tag.positive {
124
- @apply text-green-700;
125
- }
107
+ const tagTooltip = computed(() => {
108
+ if (!tagsStates.value.requiredTags[properties.uid] && !tagsStates.value.excludedTags[properties.uid]) {
109
+ return "Show news with this tag";
110
+ }
126
111
 
127
- .tag.negative {
128
- @apply text-red-700;
129
- }
130
- </style>
112
+ return "Stop filtering by this tag";
113
+ });
114
+ </script>
@@ -0,0 +1,67 @@
1
+ <template>
2
+ <div
3
+ :class="classes"
4
+ @click.prevent="onClick()">
5
+ <tag-base :tag-info="tagInfo" />
6
+ </div>
7
+ </template>
8
+
9
+ <script lang="ts" setup>
10
+ import * as t from "@/logic/types";
11
+ import {computed, ref, inject} from "vue";
12
+ import type {Ref} from "vue";
13
+ import {useTagsStore} from "@/stores/tags";
14
+ import * as tagsFilterState from "@/logic/tagsFilterState";
15
+ import * as asserts from "@/logic/asserts";
16
+ import * as events from "@/logic/events";
17
+
18
+ const tagsStore = useTagsStore();
19
+
20
+ const tagsStates = inject<Ref<tagsFilterState.Storage>>("tagsStates");
21
+
22
+ asserts.defined(tagsStates);
23
+
24
+ const properties = defineProps<{
25
+ uid: string;
26
+ cssModifier: string;
27
+ }>();
28
+
29
+ const tagInfo = computed(() => {
30
+ const tagInfo = tagsStore.tags[properties.uid];
31
+
32
+ if (tagInfo) {
33
+ return tagInfo;
34
+ }
35
+
36
+ tagsStore.requestTagInfo({tagUid: properties.uid});
37
+
38
+ return t.noInfoTag(properties.uid);
39
+ });
40
+
41
+ const classes = computed(() => {
42
+ const result: {[key: string]: boolean} = {};
43
+
44
+ result[properties.cssModifier] = true;
45
+ result["ffun-entry-tag"] = true;
46
+
47
+ if (tagsStates.value.requiredTags[properties.uid]) {
48
+ result["required"] = true;
49
+ }
50
+
51
+ if (tagsStates.value.excludedTags[properties.uid]) {
52
+ result["excluded"] = true;
53
+ }
54
+
55
+ return result;
56
+ });
57
+
58
+ const changeSource = "rule_record";
59
+
60
+ async function onClick() {
61
+ asserts.defined(tagsStates);
62
+
63
+ let changeInfo = tagsStates.value.onTagClicked({tag: properties.uid});
64
+
65
+ await events.tagStateChanged({tag: properties.uid, source: changeSource, ...changeInfo});
66
+ }
67
+ </script>
@@ -7,13 +7,12 @@
7
7
  v-for="tag of displayedSelectedTags"
8
8
  :key="tag"
9
9
  class="whitespace-nowrap line-clamp-1">
10
- <ffun-tag
11
- class="ml-1"
10
+ <filter-tag
12
11
  :uid="tag"
13
12
  :count="tags[tag] ?? 0"
14
13
  :show-switch="true"
15
- count-mode="no"
16
- change-source="tag_filter" />
14
+ :show-count="false"
15
+ :change-source="changeSource" />
17
16
  </li>
18
17
  </ul>
19
18
 
@@ -32,11 +31,12 @@
32
31
  v-for="tag of displayedTags"
33
32
  :key="tag"
34
33
  class="truncate">
35
- <ffun-tag
34
+ <filter-tag
36
35
  :uid="tag"
37
36
  :count="tags[tag]"
38
- count-mode="prefix"
39
- changeSource="tag_filter" />
37
+ :show-switch="false"
38
+ :show-count="true"
39
+ :change-source="changeSource" />
40
40
  </li>
41
41
  </ul>
42
42
 
@@ -69,7 +69,11 @@
69
69
  const tagsStates = inject<Ref<tagsFilterState.Storage>>("tagsStates");
70
70
  asserts.defined(tagsStates);
71
71
 
72
- const properties = defineProps<{tags: {[key: string]: number}; showCreateRule?: boolean}>();
72
+ const properties = defineProps<{
73
+ tags: {[key: string]: number};
74
+ showCreateRule?: boolean;
75
+ changeSource: "news_tags_filter" | "rules_tags_filter";
76
+ }>();
73
77
 
74
78
  const showFromStart = ref(25);
75
79
 
@@ -0,0 +1,38 @@
1
+ @layer base {
2
+ html {
3
+ @apply font-sans;
4
+ @apply bg-white;
5
+ }
6
+
7
+ h1 {
8
+ @apply text-3xl font-bold leading-tight my-4;
9
+ }
10
+
11
+ h2 {
12
+ @apply text-2xl font-semibold leading-relaxed my-3;
13
+ }
14
+
15
+ h3 {
16
+ @apply text-xl font-semibold leading-relaxed my-2;
17
+ }
18
+
19
+ hr {
20
+ @apply border-slate-400 my-2;
21
+ }
22
+
23
+ p,
24
+ ul,
25
+ ol,
26
+ table {
27
+ @apply mb-1;
28
+ }
29
+
30
+ p a {
31
+ @apply text-blue-600 hover:text-blue-800 cursor-pointer;
32
+ }
33
+
34
+ /* TODO: move somewhere or remove in the honor of more specialized classes */
35
+ .ffun-normal-link {
36
+ @apply text-blue-600 hover:text-blue-800 cursor-pointer;
37
+ }
38
+ }
@@ -0,0 +1,49 @@
1
+ @layer components {
2
+ .ffun-x-input-common {
3
+ @apply border border-slate-300 rounded px-2 py-1;
4
+ @apply bg-white text-slate-700;
5
+ @apply focus:border-blue-400 focus:outline-none focus:ring focus:ring-blue-100;
6
+ @apply hover:border-blue-400;
7
+ @apply disabled:bg-slate-100 disabled:text-slate-400 disabled:cursor-not-allowed;
8
+ @apply transition-colors duration-150;
9
+ }
10
+
11
+ .ffun-form-button {
12
+ @apply ffun-x-input-common font-semibold text-white;
13
+ @apply px-4 py-2;
14
+ @apply bg-blue-500 hover:bg-blue-600 focus:ring-0;
15
+ @apply disabled:bg-blue-300 disabled:text-slate-50;
16
+ }
17
+
18
+ .ffun-form-button.short {
19
+ @apply p-1 px-2;
20
+ }
21
+
22
+ .ffun-form-button.bad {
23
+ @apply bg-red-500 hover:bg-red-600;
24
+ @apply disabled:bg-red-300;
25
+ }
26
+
27
+ .ffun-file-button {
28
+ @apply text-slate-500;
29
+ @apply file:text-white file:font-semibold;
30
+ @apply file:border file:rounded file:px-4 file:py-2 file:shadow-none file:bg-blue-500 file:border-slate-300 file:border-solid file:outline-none;
31
+ @apply file:disabled:bg-blue-300 file:disabled:text-slate-400 file:disabled:cursor-not-allowed;
32
+ @apply file:enabled:hover:border-blue-400;
33
+ @apply file:focus:ring-0;
34
+ @apply file:cursor-pointer;
35
+ }
36
+
37
+ .ffun-config-flag {
38
+ @apply ffun-x-input-common px-2 py-0;
39
+ }
40
+
41
+ .ffun-input {
42
+ @apply ffun-x-input-common placeholder-gray-500;
43
+ }
44
+
45
+ .ffun-checkbox {
46
+ @apply ffun-x-input-common h-4 w-4 align-middle;
47
+ @apply bg-white;
48
+ }
49
+ }
@@ -0,0 +1,34 @@
1
+ @layer components {
2
+ .ffun-x-header-text {
3
+ @apply text-xl text-black px-2 py-1;
4
+ }
5
+
6
+ .ffun-page-header {
7
+ @apply px-4 pt-4 m-0 flex items-center cursor-default;
8
+ }
9
+
10
+ .ffun-page-header-left-block {
11
+ @apply items-center mr-auto m-0 p-0 flex space-x-2;
12
+ }
13
+
14
+ .ffun-page-header-right-block {
15
+ @apply items-center m-0 p-0 flex space-x-2;
16
+ }
17
+
18
+ .ffun-page-header-center-block {
19
+ @apply items-center mx-auto m-0 p-0 flex space-x-2;
20
+ }
21
+
22
+ .ffun-page-header-link {
23
+ @apply cursor-pointer no-underline ffun-x-header-text;
24
+ @apply underline-offset-4 hover:bg-blue-100 rounded;
25
+ }
26
+
27
+ .ffun-page-header-link-disabled {
28
+ @apply underline underline-offset-4 ffun-x-header-text;
29
+ }
30
+
31
+ .ffun-page-header-title {
32
+ @apply font-semibold ffun-x-header-text;
33
+ }
34
+ }
@@ -0,0 +1,49 @@
1
+ @layer components {
2
+ .ffun-x-panel ul {
3
+ @apply list-disc list-inside;
4
+ }
5
+
6
+ .ffun-x-panel ol {
7
+ @apply list-decimal list-inside;
8
+ }
9
+
10
+ .ffun-x-panel code {
11
+ @apply bg-slate-800 px-1 rounded bg-opacity-10 text-sm;
12
+ }
13
+
14
+ .ffun-x-panel a {
15
+ @apply text-red-600 hover:text-red-800;
16
+ }
17
+
18
+ .ffun-x-panel h4 {
19
+ @apply font-semibold text-lg mb-2;
20
+ }
21
+
22
+ .ffun-x-panel p:last-child {
23
+ @apply pb-0 mb-0;
24
+ }
25
+
26
+ .ffun-x-info {
27
+ @apply ffun-x-panel border p-4 rounded-md;
28
+ }
29
+
30
+ .ffun-info-settings {
31
+ @apply ffun-x-info;
32
+ }
33
+
34
+ .ffun-info-common {
35
+ @apply ffun-x-info bg-blue-50 border-blue-200 text-blue-800;
36
+ }
37
+
38
+ .ffun-info-good {
39
+ @apply ffun-x-info bg-green-50 border-green-200 text-green-800;
40
+ }
41
+
42
+ .ffun-info-bad {
43
+ @apply ffun-x-info bg-red-50 border-red-200 text-red-800;
44
+ }
45
+
46
+ .ffun-info-waiting {
47
+ @apply ffun-x-info bg-yellow-50 border-yellow-200 text-yellow-800;
48
+ }
49
+ }
@@ -0,0 +1,34 @@
1
+ @layer components {
2
+ .ffun-side-panel-layout {
3
+ @apply flex divide-x;
4
+
5
+ .ffun-side-panel {
6
+ @apply px-4 w-72 bg-slate-50 flex-shrink-0;
7
+
8
+ .ffun-side-panel-controls-list {
9
+ @apply space-y-2;
10
+ }
11
+
12
+ /* TODO: move this style our layout? */
13
+ .ffun-side-panel-refresh-button {
14
+ @apply ffun-form-button my-1 block w-full text-center;
15
+ }
16
+ }
17
+
18
+ .ffun-body-panel {
19
+ @apply flex-grow;
20
+ }
21
+ }
22
+
23
+ .ffun-body-list-entry {
24
+ @apply mb-1;
25
+ }
26
+
27
+ .ffun-body-list-entry:not(:last-child) {
28
+ @apply border-b py-1;
29
+ }
30
+
31
+ .ffun-body-list-icon-column {
32
+ @apply flex-shrink-0 mr-2 text-center cursor-default text-2xl;
33
+ }
34
+ }
@@ -0,0 +1,44 @@
1
+ @layer components {
2
+ .ffun-entry-tag {
3
+ @apply border inline-block cursor-pointer rounded whitespace-nowrap text-sm md:text-base;
4
+ @apply mr-1 mb-1 py-0.5 px-1.5 bg-slate-200 text-slate-800;
5
+ @apply hover:bg-slate-300;
6
+
7
+ &.positive {
8
+ @apply bg-green-50 text-green-800;
9
+ @apply hover:bg-green-100;
10
+ }
11
+
12
+ &.negative {
13
+ @apply bg-red-50 text-red-800;
14
+ @apply hover:bg-red-100;
15
+ }
16
+
17
+ &.required {
18
+ @apply border-orange-400;
19
+ }
20
+
21
+ &.excluded {
22
+ }
23
+ }
24
+
25
+ .ffun-filter-tag {
26
+ @apply inline-block cursor-pointer rounded whitespace-nowrap w-fit;
27
+ @apply py-0.5 px-1;
28
+ @apply hover:bg-blue-100;
29
+
30
+ &.required {
31
+ @apply font-bold text-green-700;
32
+ }
33
+
34
+ &.excluded {
35
+ @apply font-bold text-red-700;
36
+ }
37
+ }
38
+
39
+ .ffun-tag-switch {
40
+ @apply inline-block cursor-pointer rounded whitespace-nowrap w-fit;
41
+ @apply py-0.5 px-1;
42
+ @apply hover:bg-blue-100;
43
+ }
44
+ }