@igstack/app-catalog-frontend-core 6.12.0 → 6.12.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 (39) hide show
  1. package/dist/esm/api/infra/trpc.d.ts +27 -0
  2. package/dist/esm/modules/appCatalog/ui/catalog/AppDetailPanel.js +0 -1
  3. package/dist/esm/modules/appCatalog/ui/catalog/AppDetailPanel.js.map +1 -1
  4. package/dist/esm/modules/appCatalog/ui/detail/AppDetails.js +0 -1
  5. package/dist/esm/modules/appCatalog/ui/detail/AppDetails.js.map +1 -1
  6. package/dist/esm/modules/communityTools/siteOpen.d.ts +10 -0
  7. package/dist/esm/modules/communityTools/siteOpen.js +18 -0
  8. package/dist/esm/modules/communityTools/siteOpen.js.map +1 -0
  9. package/dist/esm/modules/communityTools/timeAgo.d.ts +2 -0
  10. package/dist/esm/modules/communityTools/timeAgo.js +11 -0
  11. package/dist/esm/modules/communityTools/timeAgo.js.map +1 -1
  12. package/dist/esm/modules/communityTools/ui/CardScreenshot.js +10 -12
  13. package/dist/esm/modules/communityTools/ui/CardScreenshot.js.map +1 -1
  14. package/dist/esm/modules/communityTools/ui/CardTitleBlock.d.ts +1 -1
  15. package/dist/esm/modules/communityTools/ui/CardTitleBlock.js +5 -13
  16. package/dist/esm/modules/communityTools/ui/CardTitleBlock.js.map +1 -1
  17. package/dist/esm/modules/communityTools/ui/CommunityPage.js +2 -4
  18. package/dist/esm/modules/communityTools/ui/CommunityPage.js.map +1 -1
  19. package/dist/esm/modules/communityTools/ui/FeedRow.d.ts +6 -3
  20. package/dist/esm/modules/communityTools/ui/FeedRow.js +14 -8
  21. package/dist/esm/modules/communityTools/ui/FeedRow.js.map +1 -1
  22. package/dist/esm/modules/communityTools/ui/ShelfTile.js +4 -7
  23. package/dist/esm/modules/communityTools/ui/ShelfTile.js.map +1 -1
  24. package/dist/esm/modules/communityTools/ui/ToolCard.js +15 -3
  25. package/dist/esm/modules/communityTools/ui/ToolCard.js.map +1 -1
  26. package/dist/esm/modules/communityTools/ui/ToolFormDialog.js +0 -1
  27. package/dist/esm/modules/communityTools/ui/ToolFormDialog.js.map +1 -1
  28. package/dist/esm/modules/communityTools/useCommunityTools.d.ts +2 -0
  29. package/dist/esm/modules/communityTools/useCommunityTools.js +0 -1
  30. package/dist/esm/modules/communityTools/useCommunityTools.js.map +1 -1
  31. package/package.json +4 -4
  32. package/src/modules/communityTools/siteOpen.ts +20 -0
  33. package/src/modules/communityTools/timeAgo.ts +12 -0
  34. package/src/modules/communityTools/ui/CardScreenshot.tsx +21 -9
  35. package/src/modules/communityTools/ui/CardTitleBlock.tsx +4 -9
  36. package/src/modules/communityTools/ui/CommunityPage.tsx +2 -5
  37. package/src/modules/communityTools/ui/FeedRow.tsx +19 -15
  38. package/src/modules/communityTools/ui/ShelfTile.tsx +4 -5
  39. package/src/modules/communityTools/ui/ToolCard.tsx +11 -1
@@ -13,7 +13,8 @@ import {
13
13
  } from 'lucide-react'
14
14
  import { cn } from '~/lib/utils'
15
15
  import { highlightTokens } from '~/util/highlightMatches'
16
- import { timeAgo } from '../timeAgo'
16
+ import { recordSiteOpen } from '../siteOpen'
17
+ import { exactDate, timeAgo } from '../timeAgo'
17
18
  import { LifecycleBadge, UnreviewedBadge } from './LifecycleBadge'
18
19
  import { LikeButton } from './LikeButton'
19
20
  import { PinButton } from './PinButton'
@@ -96,7 +97,10 @@ export interface FeedRowProps {
96
97
  tool: CommunityTool
97
98
  /** Shown in the ranked feed; search results have no rank. */
98
99
  rank?: number
99
- /** Recently updated shows when the site changed; every other sort, when it was added. */
100
+ /**
101
+ * Newest shows when it was added, Recently updated when the site changed;
102
+ * every other sort the site's date, or when it was added if that is unknown.
103
+ */
100
104
  sort: FeedSort
101
105
  tokens: string[]
102
106
  /** Set while searching: which fields the query hit. */
@@ -122,8 +126,8 @@ const PANEL = 'w-[120px]'
122
126
 
123
127
  /**
124
128
  * One tool in the feed or the search results. Everything left of the end
125
- * panel (rank, picture, name, summary, meta) is one link that opens the site
126
- * in a new tab; the 120 px panel opens the card. The star sits in the meta
129
+ * panel (rank, picture, name, summary, meta) is one link that opens the
130
+ * site; the 120 px panel opens the card. The star sits in the meta
127
131
  * line as its own target, above that link.
128
132
  */
129
133
  export function FeedRow({
@@ -142,12 +146,12 @@ export function FeedRow({
142
146
  const archived = tool.lifecycle.state === 'archived'
143
147
  const cell = optionId ? 'gridcell' : undefined
144
148
  const owners = tool.owners.map((o) => o.name).join(', ')
145
- const dated =
146
- sort !== 'updated'
147
- ? `Added ${timeAgo(tool.createdAt)}`
148
- : tool.siteUpdatedAt
149
- ? `Updated ${timeAgo(tool.siteUpdatedAt)}`
150
- : null
149
+ const siteUpdatedAt = sort !== 'newest' ? tool.siteUpdatedAt : null
150
+ const dated = siteUpdatedAt
151
+ ? { label: 'Updated', at: siteUpdatedAt }
152
+ : sort !== 'updated'
153
+ ? { label: 'Added', at: tool.createdAt }
154
+ : null
151
155
 
152
156
  return (
153
157
  <div
@@ -182,11 +186,10 @@ export function FeedRow({
182
186
  <div className="flex items-center gap-2.5 text-[15.5px] font-extrabold">
183
187
  <a
184
188
  href={tool.url}
185
- target="_blank"
186
- rel="noopener noreferrer"
189
+ onClick={() => recordSiteOpen(tool.slug)}
187
190
  data-site
188
191
  data-testid="feed-row-name"
189
- aria-label={`${tool.name}, opens ${tool.host} in a new tab`}
192
+ aria-label={`${tool.name}, opens ${tool.host}`}
190
193
  className={cn(
191
194
  'truncate decoration-1 underline-offset-[3px] after:absolute after:inset-y-0 after:left-0 after:right-[120px] after:z-[1] after:rounded-l-[13px] focus-visible:outline-none focus-visible:after:outline-2 focus-visible:after:-outline-offset-[3px] focus-visible:after:outline-ring',
192
195
  'group-hover/row:underline group-has-[[data-details]:hover]/row:no-underline',
@@ -269,9 +272,10 @@ export function FeedRow({
269
272
  {dated && (
270
273
  <span
271
274
  data-testid="feed-row-date"
272
- className="ml-auto shrink-0 pr-4 text-[13px] font-semibold whitespace-nowrap text-muted-foreground"
275
+ title={exactDate(dated.at)}
276
+ className="pointer-events-auto ml-auto shrink-0 pr-4 text-[13px] font-semibold whitespace-nowrap text-muted-foreground"
273
277
  >
274
- {dated}
278
+ {dated.label} {timeAgo(dated.at)}
275
279
  </span>
276
280
  )}
277
281
  </div>
@@ -1,7 +1,8 @@
1
1
  import type { CommunityTool } from '@igstack/app-catalog-shared-core'
2
- import { ExternalLink, GripVertical } from 'lucide-react'
2
+ import { GripVertical } from 'lucide-react'
3
3
  import { cn } from '~/lib/utils'
4
4
  import { PersonAvatar, ToolThumb } from './FeedRow'
5
+ import { recordSiteOpen } from '../siteOpen'
5
6
  import { PinButton } from './PinButton'
6
7
 
7
8
  /**
@@ -35,8 +36,7 @@ export function ShelfTile({
35
36
  >
36
37
  <a
37
38
  href={tool.url}
38
- target="_blank"
39
- rel="noopener noreferrer"
39
+ onClick={() => recordSiteOpen(tool.slug)}
40
40
  aria-keyshortcuts="Alt+ArrowUp Alt+ArrowDown"
41
41
  onKeyDown={(e) => {
42
42
  if (!e.altKey) return
@@ -49,8 +49,7 @@ export function ShelfTile({
49
49
  >
50
50
  <span className="relative block aspect-[16/9.5] border-b border-border">
51
51
  <ToolThumb tool={tool} size={512} className="size-full border-0" />
52
- <span className="absolute right-2.5 bottom-2.5 inline-flex items-center gap-1.5 rounded-lg bg-primary px-3 py-1.5 text-sm font-extrabold text-primary-foreground opacity-0 shadow-sm transition-opacity group-hover:opacity-100 group-focus-within:opacity-100">
53
- <ExternalLink aria-hidden="true" className="size-4" />
52
+ <span className="absolute right-2.5 bottom-2.5 rounded-lg bg-primary px-3 py-1.5 text-sm font-extrabold text-primary-foreground opacity-0 shadow-sm transition-opacity group-hover:opacity-100 group-focus-within:opacity-100">
54
53
  Open site
55
54
  </span>
56
55
  </span>
@@ -26,6 +26,8 @@ import { Skeleton } from '~/ui/skeleton'
26
26
  import { CardScreenshot, formatCardDate } from './CardScreenshot'
27
27
  import { CardTitleBlock } from './CardTitleBlock'
28
28
  import { PersonAvatar } from './FeedRow'
29
+ import { openSite } from '../siteOpen'
30
+ import { exactDate, timeAgo } from '../timeAgo'
29
31
  import { useTimeUp } from '../useTimeUp'
30
32
  import { PinButton } from './PinButton'
31
33
  import { TagChip, tagKey, tagLabel } from './TagRow'
@@ -184,7 +186,7 @@ export function ToolCard({
184
186
  // that opens the site.
185
187
  if (target.closest('a, button')) return
186
188
  e.preventDefault()
187
- window.open(tool.url, '_blank', 'noopener,noreferrer')
189
+ openSite(tool)
188
190
  }
189
191
  }
190
192
 
@@ -296,6 +298,14 @@ export function ToolCard({
296
298
  </b>{' '}
297
299
  all time
298
300
  </span>
301
+ {tool.siteUpdatedAt && (
302
+ <span
303
+ data-testid="card-site-updated"
304
+ title={exactDate(tool.siteUpdatedAt)}
305
+ >
306
+ Site updated {timeAgo(tool.siteUpdatedAt)}
307
+ </span>
308
+ )}
299
309
  </p>
300
310
  )}
301
311
  {/* Who to ask, up here with the facts: below the screenshot