1+ import { Node } from "../model/mod.ts" ;
2+ import { InlineFrame } from "../com/iframe.tsx" ;
3+
4+ function tryFields ( n : Node , fields : string [ ] ) : any | null {
5+ for ( const field of fields ) {
6+ const value = n . componentField ( field ) ;
7+ if ( value ) {
8+ return value ;
9+ }
10+ }
11+ return null ;
12+ }
13+
14+ export default {
15+ view ( { attrs : { workbench, path} } ) {
16+ const node = path . node ;
17+ return (
18+ < div class = "cards-view flex flex-row" style = { { gap : "1rem" , paddingBottom : "1rem" , flexWrap : "wrap" } } >
19+ { node . children . map ( n => {
20+ const linkURL = tryFields ( n , [ "linkURL" ] ) ;
21+ const dateTime = tryFields ( n , [ "updatedAt" , "createdAt" ] ) ;
22+ const userName = tryFields ( n , [ "updatedBy" , "createdBy" , "username" ] ) ;
23+ const thumbnailURL = tryFields ( n , [ "thumbnailURL" , "coverURL" ] ) ;
24+ const frame = n . getComponent ( InlineFrame ) ;
25+
26+ let thumbnail = < img style = { {
27+ objectFit : "fill" ,
28+ objectPosition : "center" ,
29+ width : "12rem" ,
30+ height : "9rem"
31+ } } src = { thumbnailURL } /> ;
32+ if ( frame ) {
33+ thumbnail = (
34+ < div style = { {
35+ width : "120rem" ,
36+ height : "90rem" ,
37+ transform : "scale(0.1)" ,
38+ pointerEvents : "none" ,
39+ transformOrigin : "0 0"
40+ } } >
41+ < iframe src = { frame . url } style = { {
42+ border : "0" ,
43+ width : "100%" ,
44+ height : "100%"
45+ } } > </ iframe >
46+ </ div >
47+ )
48+ }
49+ return (
50+ < div style = { { border : "1px solid gray" , overflow : "hidden" , borderRadius : "0.5rem" , paddingBottom : "0.5rem" , width : "12rem" } } >
51+ < div style = { { position : "relative" , overflow : "hidden" , width : "12rem" , height : "9rem" } } >
52+ { ( linkURL )
53+ ? < a href = { linkURL } > { thumbnail } </ a >
54+ : thumbnail
55+ }
56+ </ div >
57+ < div style = { { padding : "0.5rem" , paddingBottom : "0.25rem" } } >
58+ { ( linkURL )
59+ ? < a href = { linkURL } > { n . name } </ a >
60+ : n . name }
61+ </ div >
62+ { userName && < div style = { { padding : "0.5rem" , paddingTop : "0" , paddingBottom : "0.75rem" , color : "#aaa" } } >
63+ { userName }
64+ </ div > }
65+ { dateTime && < div style = { { padding : "0.5rem" , paddingTop : "0" , paddingBottom : "0.75rem" , color : "#aaa" } } >
66+ { timeAgo ( dateTime ) }
67+ </ div > }
68+ </ div >
69+ ) } ) }
70+ </ div >
71+ )
72+ }
73+ }
74+
75+ function timeAgo ( date ) {
76+ if ( ! ( date instanceof Date ) ) {
77+ throw new Error ( "Input must be a valid Date object." ) ;
78+ }
79+
80+ const now = new Date ( ) ;
81+ const seconds = Math . floor ( ( now . getTime ( ) - date . getTime ( ) ) / 1000 ) ;
82+
83+ const intervals = {
84+ year : 31536000 ,
85+ month : 2592000 ,
86+ week : 604800 ,
87+ day : 86400 ,
88+ hour : 3600 ,
89+ minute : 60 ,
90+ second : 1
91+ } ;
92+
93+ for ( const [ unit , secondsInUnit ] of Object . entries ( intervals ) ) {
94+ const count = Math . floor ( seconds / secondsInUnit ) ;
95+ if ( count > 0 ) {
96+ return `${ count } ${ unit } ${ count > 1 ? 's' : '' } ago` ;
97+ }
98+ }
99+
100+ return 'just now' ;
101+ }
0 commit comments