arkaos 3.46.0 → 3.47.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/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.
|
|
1
|
+
3.47.0
|
|
@@ -54,20 +54,30 @@ function kindColor(kind: string): string {
|
|
|
54
54
|
</UButton>
|
|
55
55
|
|
|
56
56
|
<template #content>
|
|
57
|
-
<div class="p-2 border-b border-default flex items-center justify-between">
|
|
57
|
+
<div class="p-2 border-b border-default flex items-center justify-between gap-2">
|
|
58
58
|
<div>
|
|
59
59
|
<p class="text-sm font-semibold">Recent activity</p>
|
|
60
60
|
<p class="text-xs text-muted">
|
|
61
|
-
|
|
61
|
+
{{ feed.unreadCount.value }} unread ·
|
|
62
|
+
{{ feed.events.value.length }} total
|
|
62
63
|
</p>
|
|
63
64
|
</div>
|
|
64
|
-
<
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
65
|
+
<div class="flex items-center gap-1">
|
|
66
|
+
<UButton
|
|
67
|
+
v-if="feed.unreadCount.value > 0"
|
|
68
|
+
label="Mark all read"
|
|
69
|
+
variant="ghost"
|
|
70
|
+
size="xs"
|
|
71
|
+
@click="feed.markAllRead()"
|
|
72
|
+
/>
|
|
73
|
+
<UButton
|
|
74
|
+
v-if="feed.events.value.length > 0"
|
|
75
|
+
label="Clear"
|
|
76
|
+
variant="ghost"
|
|
77
|
+
size="xs"
|
|
78
|
+
@click="feed.clear()"
|
|
79
|
+
/>
|
|
80
|
+
</div>
|
|
71
81
|
</div>
|
|
72
82
|
<div class="max-h-80 overflow-y-auto">
|
|
73
83
|
<p
|
|
@@ -81,7 +91,9 @@ function kindColor(kind: string): string {
|
|
|
81
91
|
<li
|
|
82
92
|
v-for="ev in feed.events.value"
|
|
83
93
|
:key="ev.id"
|
|
84
|
-
class="px-3 py-2 hover:bg-elevated/40 transition-colors group"
|
|
94
|
+
class="px-3 py-2 hover:bg-elevated/40 transition-colors group cursor-pointer"
|
|
95
|
+
:class="{ 'bg-primary/5': !ev.read }"
|
|
96
|
+
@click="feed.markRead(ev.id)"
|
|
85
97
|
>
|
|
86
98
|
<component
|
|
87
99
|
:is="ev.to ? 'NuxtLink' : 'div'"
|
|
@@ -93,7 +105,16 @@ function kindColor(kind: string): string {
|
|
|
93
105
|
:class="['size-4 shrink-0 mt-0.5', kindColor(ev.kind)]"
|
|
94
106
|
/>
|
|
95
107
|
<div class="flex-1 min-w-0">
|
|
96
|
-
<p class="text-sm
|
|
108
|
+
<p class="text-sm flex items-center gap-1.5">
|
|
109
|
+
<span
|
|
110
|
+
v-if="!ev.read"
|
|
111
|
+
class="inline-block size-1.5 rounded-full bg-primary shrink-0"
|
|
112
|
+
aria-label="unread"
|
|
113
|
+
/>
|
|
114
|
+
<span :class="ev.read ? 'font-normal text-muted' : 'font-medium'" class="truncate">
|
|
115
|
+
{{ ev.title }}
|
|
116
|
+
</span>
|
|
117
|
+
</p>
|
|
97
118
|
<p v-if="ev.description" class="text-xs text-muted truncate">
|
|
98
119
|
{{ ev.description }}
|
|
99
120
|
</p>
|
|
@@ -13,6 +13,7 @@ export interface ActivityEvent {
|
|
|
13
13
|
title: string
|
|
14
14
|
description?: string
|
|
15
15
|
to?: string
|
|
16
|
+
read?: boolean
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
const STORAGE_KEY = 'arkaos_activity_feed'
|
|
@@ -21,7 +22,10 @@ const MAX_EVENTS = 50
|
|
|
21
22
|
const _useActivityFeed = () => {
|
|
22
23
|
const events = useState<ActivityEvent[]>('activityFeed', () => [])
|
|
23
24
|
const loaded = useState<boolean>('activityFeedLoaded', () => false)
|
|
24
|
-
|
|
25
|
+
// PR94a v3.47.0 — unread count is now derived from `read: false`.
|
|
26
|
+
const unreadCount = computed(
|
|
27
|
+
() => events.value.filter((e) => !e.read).length,
|
|
28
|
+
)
|
|
25
29
|
|
|
26
30
|
function _persist() {
|
|
27
31
|
if (typeof window === 'undefined') return
|
|
@@ -48,14 +52,39 @@ const _useActivityFeed = () => {
|
|
|
48
52
|
loaded.value = true
|
|
49
53
|
}
|
|
50
54
|
|
|
51
|
-
function push(entry: Omit<ActivityEvent, 'id' | 'ts'>) {
|
|
55
|
+
function push(entry: Omit<ActivityEvent, 'id' | 'ts' | 'read'>) {
|
|
52
56
|
load()
|
|
53
57
|
const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
|
|
54
58
|
const ts = new Date().toISOString()
|
|
55
|
-
|
|
59
|
+
// PR94a — every new event starts unread.
|
|
60
|
+
events.value = [{ id, ts, read: false, ...entry }, ...events.value].slice(0, MAX_EVENTS)
|
|
56
61
|
_persist()
|
|
57
62
|
}
|
|
58
63
|
|
|
64
|
+
function markRead(id: string) {
|
|
65
|
+
let changed = false
|
|
66
|
+
events.value = events.value.map((e) => {
|
|
67
|
+
if (e.id === id && !e.read) {
|
|
68
|
+
changed = true
|
|
69
|
+
return { ...e, read: true }
|
|
70
|
+
}
|
|
71
|
+
return e
|
|
72
|
+
})
|
|
73
|
+
if (changed) _persist()
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function markAllRead() {
|
|
77
|
+
let changed = false
|
|
78
|
+
events.value = events.value.map((e) => {
|
|
79
|
+
if (!e.read) {
|
|
80
|
+
changed = true
|
|
81
|
+
return { ...e, read: true }
|
|
82
|
+
}
|
|
83
|
+
return e
|
|
84
|
+
})
|
|
85
|
+
if (changed) _persist()
|
|
86
|
+
}
|
|
87
|
+
|
|
59
88
|
function clear() {
|
|
60
89
|
events.value = []
|
|
61
90
|
_persist()
|
|
@@ -66,7 +95,7 @@ const _useActivityFeed = () => {
|
|
|
66
95
|
_persist()
|
|
67
96
|
}
|
|
68
97
|
|
|
69
|
-
return { events, unreadCount, load, push, clear, remove }
|
|
98
|
+
return { events, unreadCount, load, push, clear, remove, markRead, markAllRead }
|
|
70
99
|
}
|
|
71
100
|
|
|
72
101
|
export const useActivityFeed = createSharedComposable(_useActivityFeed)
|
package/package.json
CHANGED