@igstack/app-catalog-frontend-core 6.11.0 → 6.12.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@igstack/app-catalog-frontend-core",
3
- "version": "6.11.0",
3
+ "version": "6.12.0",
4
4
  "description": "Frontend core library for App Catalog",
5
5
  "homepage": "https://github.com/lislon/app-catalog",
6
6
  "repository": {
@@ -118,7 +118,7 @@
118
118
  "tailwindcss": "^4.1.7",
119
119
  "tiptap-markdown": "^0.8.0",
120
120
  "tslib": "^2.3.0",
121
- "@igstack/app-catalog-shared-core": "6.11.0"
121
+ "@igstack/app-catalog-shared-core": "6.12.0"
122
122
  },
123
123
  "devDependencies": {
124
124
  "@tailwindcss/vite": "^4.0.5",
@@ -146,7 +146,7 @@
146
146
  "vite-plugin-static-copy": "^3.1.4",
147
147
  "vite-plugin-svgr": "^4.2.0",
148
148
  "vitest": "^4.1.2",
149
- "@igstack/app-catalog-backend-core": "6.11.0"
149
+ "@igstack/app-catalog-backend-core": "6.12.0"
150
150
  },
151
151
  "peerDependencies": {
152
152
  "@tanstack/react-router": "1.170.41",
@@ -156,7 +156,7 @@
156
156
  "vite": "^6.3.5",
157
157
  "vite-plugin-svgr": "^4.2.0"
158
158
  },
159
- "gitHead": "f4c72c2178cd9a3ec6695cfbb243ff3d0737ad1b",
159
+ "gitHead": "94ade32ef879b41d8c62f2121a41e4b35f46b2ee",
160
160
  "scripts": {
161
161
  "build": "vite build",
162
162
  "build:lenient": "vite build --mode lenient",
@@ -112,7 +112,17 @@ export function CommentsFeed({
112
112
  }),
113
113
  )
114
114
  const dismiss = useMutation(
115
- trpc.feedback.dismiss.mutationOptions({ onSuccess: () => void refresh() }),
115
+ trpc.feedback.dismiss.mutationOptions({
116
+ onSuccess: () => {
117
+ void refresh()
118
+ // A tool's row counts its comments.
119
+ if ('communityToolSlug' in target) {
120
+ void queryClient.invalidateQueries({
121
+ queryKey: trpc.communityTools.pathKey(),
122
+ })
123
+ }
124
+ },
125
+ }),
116
126
  )
117
127
  const saveEdit = (id: string) => {
118
128
  const body = editDraft.trim()
@@ -160,6 +160,12 @@ export function CommunityInput({
160
160
  void queryClient.invalidateQueries({
161
161
  queryKey: trpc.feedback.list.queryKey(target),
162
162
  })
163
+ // A tool's row counts its comments.
164
+ if ('communityToolSlug' in target) {
165
+ void queryClient.invalidateQueries({
166
+ queryKey: trpc.communityTools.pathKey(),
167
+ })
168
+ }
163
169
  },
164
170
  }),
165
171
  )
@@ -6,9 +6,9 @@ import type {
6
6
  import { Link } from '@tanstack/react-router'
7
7
  import {
8
8
  CornerDownLeft,
9
- ExternalLink,
10
9
  Eye,
11
10
  Globe,
11
+ MessageSquare,
12
12
  PanelRight,
13
13
  } from 'lucide-react'
14
14
  import { cn } from '~/lib/utils'
@@ -96,7 +96,7 @@ export interface FeedRowProps {
96
96
  tool: CommunityTool
97
97
  /** Shown in the ranked feed; search results have no rank. */
98
98
  rank?: number
99
- /** A date sort shows its date on the row. */
99
+ /** Recently updated shows when the site changed; every other sort, when it was added. */
100
100
  sort: FeedSort
101
101
  tokens: string[]
102
102
  /** Set while searching: which fields the query hit. */
@@ -124,8 +124,7 @@ const PANEL = 'w-[120px]'
124
124
  * One tool in the feed or the search results. Everything left of the end
125
125
  * panel (rank, picture, name, summary, meta) is one link that opens the site
126
126
  * in a new tab; the 120 px panel opens the card. The star sits in the meta
127
- * line as its own target, above that link. The bottom strip shows the address
128
- * the big click goes to, on hover or focus only.
127
+ * line as its own target, above that link.
129
128
  */
130
129
  export function FeedRow({
131
130
  tool,
@@ -144,12 +143,11 @@ export function FeedRow({
144
143
  const cell = optionId ? 'gridcell' : undefined
145
144
  const owners = tool.owners.map((o) => o.name).join(', ')
146
145
  const dated =
147
- sort === 'newest'
146
+ sort !== 'updated'
148
147
  ? `Added ${timeAgo(tool.createdAt)}`
149
- : sort === 'updated' && tool.siteUpdatedAt
148
+ : tool.siteUpdatedAt
150
149
  ? `Updated ${timeAgo(tool.siteUpdatedAt)}`
151
150
  : null
152
- const address = tool.url.replace(/^https?:\/\//, '').replace(/\/$/, '')
153
151
 
154
152
  return (
155
153
  <div
@@ -220,9 +218,9 @@ export function FeedRow({
220
218
  </div>
221
219
  )}
222
220
  </div>
223
- {/* Meta on the left, the address on the right, flush to the panel.
224
- The address keeps 150 px; a long author list gives way first.
225
- Clicks fall through to the row link, except on star and like. */}
221
+ {/* Meta on the left, the date on the right, flush to the panel. A
222
+ long author list gives way first. Clicks fall through to the row
223
+ link, except on star and like. */}
226
224
  <div
227
225
  className={cn(
228
226
  'pointer-events-none absolute right-[120px] bottom-0 z-[2] flex h-12 items-center gap-4',
@@ -255,32 +253,27 @@ export function FeedRow({
255
253
  {tool.views30d}
256
254
  <span className="sr-only"> views this month</span>
257
255
  </span>
258
- {dated && (
259
- <>
260
- <span aria-hidden="true" className="text-muted-foreground">
261
- ·
256
+ {tool.comments > 0 && (
257
+ <span
258
+ data-testid="feed-row-comments"
259
+ className="inline-flex items-center gap-1 text-muted-foreground"
260
+ >
261
+ <MessageSquare aria-hidden="true" className="size-[15px]" />
262
+ {tool.comments}
263
+ <span className="sr-only">
264
+ {tool.comments === 1 ? ' comment' : ' comments'}
262
265
  </span>
263
- <span
264
- data-testid="feed-row-date"
265
- className="text-muted-foreground"
266
- >
267
- {dated}
268
- </span>
269
- </>
270
- )}
271
- </div>
272
- <div
273
- aria-hidden="true"
274
- data-testid="feed-row-address"
275
- className={cn(
276
- 'flex h-full min-w-[150px] flex-1 items-center justify-end gap-1.5 px-4 font-mono text-[12.5px] text-muted-foreground opacity-0 transition-opacity',
277
- 'group-hover/row:text-foreground group-hover/row:opacity-100 group-has-[[data-site]:focus-visible]/row:opacity-100 group-has-[[data-details]:hover]/row:opacity-0 [@media(hover:none)]:opacity-100',
278
- selected && 'opacity-100',
266
+ </span>
279
267
  )}
280
- >
281
- <span className="min-w-0 truncate">{address}</span>
282
- <ExternalLink aria-hidden="true" className="size-3.5 shrink-0" />
283
268
  </div>
269
+ {dated && (
270
+ <span
271
+ data-testid="feed-row-date"
272
+ className="ml-auto shrink-0 pr-4 text-[13px] font-semibold whitespace-nowrap text-muted-foreground"
273
+ >
274
+ {dated}
275
+ </span>
276
+ )}
284
277
  </div>
285
278
  </div>
286
279
  <div role={cell} className="flex self-stretch">