@wakastellar/ui 2.1.2 → 2.3.2

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 (123) hide show
  1. package/dist/blocks/apm-overview/index.d.ts +58 -0
  2. package/dist/blocks/cicd-builder/index.d.ts +47 -0
  3. package/dist/blocks/cloud-cost-dashboard/index.d.ts +49 -0
  4. package/dist/blocks/container-orchestrator/index.d.ts +63 -0
  5. package/dist/blocks/database-admin/index.d.ts +84 -0
  6. package/dist/blocks/gitops-sync-status/index.d.ts +45 -0
  7. package/dist/blocks/incident-manager/index.d.ts +44 -0
  8. package/dist/blocks/index.d.ts +10 -0
  9. package/dist/blocks/infrastructure-map/index.d.ts +32 -0
  10. package/dist/blocks/on-call-schedule/index.d.ts +43 -0
  11. package/dist/blocks/release-notes/index.d.ts +49 -0
  12. package/dist/components/index.d.ts +34 -0
  13. package/dist/components/waka-ad-banner/index.d.ts +36 -0
  14. package/dist/components/waka-ad-fallback/index.d.ts +33 -0
  15. package/dist/components/waka-ad-inline/index.d.ts +15 -0
  16. package/dist/components/waka-ad-interstitial/index.d.ts +26 -0
  17. package/dist/components/waka-ad-placeholder/index.d.ts +17 -0
  18. package/dist/components/waka-ad-provider/index.d.ts +103 -0
  19. package/dist/components/waka-ad-sidebar/index.d.ts +18 -0
  20. package/dist/components/waka-ad-sticky-footer/index.d.ts +17 -0
  21. package/dist/components/waka-alert-panel/index.d.ts +45 -0
  22. package/dist/components/waka-artifact-list/index.d.ts +32 -0
  23. package/dist/components/waka-build-matrix/index.d.ts +36 -0
  24. package/dist/components/waka-config-comparator/index.d.ts +37 -0
  25. package/dist/components/waka-container-list/index.d.ts +51 -0
  26. package/dist/components/waka-content-recommendation/index.d.ts +23 -0
  27. package/dist/components/waka-database-card/index.d.ts +46 -0
  28. package/dist/components/waka-dependency-tree/index.d.ts +38 -0
  29. package/dist/components/waka-env-var-editor/index.d.ts +30 -0
  30. package/dist/components/waka-feature-flag-row/index.d.ts +45 -0
  31. package/dist/components/waka-kubernetes-overview/index.d.ts +98 -0
  32. package/dist/components/waka-log-viewer/index.d.ts +38 -0
  33. package/dist/components/waka-migration-list/index.d.ts +36 -0
  34. package/dist/components/waka-outstream-video/index.d.ts +24 -0
  35. package/dist/components/waka-pod-card/index.d.ts +73 -0
  36. package/dist/components/waka-query-explain/index.d.ts +48 -0
  37. package/dist/components/waka-secret-card/index.d.ts +43 -0
  38. package/dist/components/waka-security-scan-result/index.d.ts +45 -0
  39. package/dist/components/waka-service-graph/index.d.ts +44 -0
  40. package/dist/components/waka-sponsored-badge/index.d.ts +20 -0
  41. package/dist/components/waka-sponsored-card/index.d.ts +25 -0
  42. package/dist/components/waka-sponsored-feed/index.d.ts +31 -0
  43. package/dist/components/waka-test-report/index.d.ts +60 -0
  44. package/dist/components/waka-trace-viewer/index.d.ts +36 -0
  45. package/dist/components/waka-video-ad/index.d.ts +32 -0
  46. package/dist/components/waka-video-overlay/index.d.ts +26 -0
  47. package/dist/index.cjs.js +251 -200
  48. package/dist/index.d.ts +1 -0
  49. package/dist/index.es.js +47315 -35823
  50. package/dist/utils/security.d.ts +96 -0
  51. package/package.json +4 -4
  52. package/src/blocks/apm-overview/index.tsx +672 -0
  53. package/src/blocks/cicd-builder/index.tsx +738 -0
  54. package/src/blocks/cloud-cost-dashboard/index.tsx +597 -0
  55. package/src/blocks/container-orchestrator/index.tsx +729 -0
  56. package/src/blocks/database-admin/index.tsx +679 -0
  57. package/src/blocks/gitops-sync-status/index.tsx +557 -0
  58. package/src/blocks/incident-manager/index.tsx +586 -0
  59. package/src/blocks/index.ts +119 -0
  60. package/src/blocks/infrastructure-map/index.tsx +638 -0
  61. package/src/blocks/on-call-schedule/index.tsx +615 -0
  62. package/src/blocks/release-notes/index.tsx +643 -0
  63. package/src/blocks/sidebar/index.tsx +6 -6
  64. package/src/components/DataTable/templates/index.tsx +3 -2
  65. package/src/components/index.ts +283 -0
  66. package/src/components/waka-3d-pie-chart/index.tsx +11 -11
  67. package/src/components/waka-achievement-unlock/index.tsx +16 -16
  68. package/src/components/waka-ad-banner/index.tsx +275 -0
  69. package/src/components/waka-ad-fallback/index.tsx +181 -0
  70. package/src/components/waka-ad-inline/index.tsx +103 -0
  71. package/src/components/waka-ad-interstitial/index.tsx +278 -0
  72. package/src/components/waka-ad-placeholder/index.tsx +84 -0
  73. package/src/components/waka-ad-provider/index.tsx +329 -0
  74. package/src/components/waka-ad-sidebar/index.tsx +113 -0
  75. package/src/components/waka-ad-sticky-footer/index.tsx +125 -0
  76. package/src/components/waka-alert-panel/index.tsx +493 -0
  77. package/src/components/waka-artifact-list/index.tsx +416 -0
  78. package/src/components/waka-badge-showcase/index.tsx +12 -11
  79. package/src/components/waka-build-matrix/index.tsx +396 -0
  80. package/src/components/waka-command-bar/index.tsx +2 -1
  81. package/src/components/waka-config-comparator/index.tsx +416 -0
  82. package/src/components/waka-container-list/index.tsx +475 -0
  83. package/src/components/waka-content-recommendation/index.tsx +294 -0
  84. package/src/components/waka-cost-breakdown/index.tsx +10 -10
  85. package/src/components/waka-database-card/index.tsx +473 -0
  86. package/src/components/waka-dependency-tree/index.tsx +542 -0
  87. package/src/components/waka-env-var-editor/index.tsx +417 -0
  88. package/src/components/waka-feature-flag-row/index.tsx +386 -0
  89. package/src/components/waka-funnel-chart/index.tsx +8 -8
  90. package/src/components/waka-health-pulse/index.tsx +6 -6
  91. package/src/components/waka-kubernetes-overview/index.tsx +536 -0
  92. package/src/components/waka-leaderboard/index.tsx +9 -9
  93. package/src/components/waka-log-viewer/index.tsx +386 -0
  94. package/src/components/waka-loot-box/index.tsx +20 -20
  95. package/src/components/waka-migration-list/index.tsx +487 -0
  96. package/src/components/waka-outstream-video/index.tsx +240 -0
  97. package/src/components/waka-player-card/index.tsx +5 -5
  98. package/src/components/waka-pod-card/index.tsx +528 -0
  99. package/src/components/waka-query-explain/index.tsx +657 -0
  100. package/src/components/waka-quota-bar/index.tsx +4 -4
  101. package/src/components/waka-radar-score/index.tsx +10 -10
  102. package/src/components/waka-scratch-card/index.tsx +5 -4
  103. package/src/components/waka-secret-card/index.tsx +371 -0
  104. package/src/components/waka-security-scan-result/index.tsx +473 -0
  105. package/src/components/waka-server-rack/index.tsx +28 -27
  106. package/src/components/waka-service-graph/index.tsx +445 -0
  107. package/src/components/waka-sponsored-badge/index.tsx +97 -0
  108. package/src/components/waka-sponsored-card/index.tsx +275 -0
  109. package/src/components/waka-sponsored-feed/index.tsx +127 -0
  110. package/src/components/waka-spotlight/index.tsx +2 -1
  111. package/src/components/waka-success-explosion/index.tsx +4 -4
  112. package/src/components/waka-test-report/index.tsx +469 -0
  113. package/src/components/waka-trace-viewer/index.tsx +490 -0
  114. package/src/components/waka-video-ad/index.tsx +406 -0
  115. package/src/components/waka-video-overlay/index.tsx +257 -0
  116. package/src/components/waka-xp-bar/index.tsx +13 -13
  117. package/src/styles/base.css +16 -0
  118. package/src/styles/tailwind.preset.js +12 -0
  119. package/src/styles/themes/forest.css +16 -0
  120. package/src/styles/themes/monochrome.css +16 -0
  121. package/src/styles/themes/perpetuity.css +16 -0
  122. package/src/styles/themes/sunset.css +16 -0
  123. package/src/styles/themes/twilight.css +16 -0
@@ -0,0 +1,294 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { useRef, useEffect, useState } from "react"
5
+ import { cn } from "../../utils/cn"
6
+ import { useAdContext, useAdVisibility, type CustomAd } from "../waka-ad-provider"
7
+ import { WakaSponsoredBadge } from "../waka-sponsored-badge"
8
+ import { ExternalLink, ChevronLeft, ChevronRight } from "lucide-react"
9
+
10
+ export type RecommendationLayout = "grid" | "carousel" | "list"
11
+
12
+ export interface WakaContentRecommendationProps {
13
+ /** Widget title */
14
+ title?: string
15
+ /** Slot IDs for recommendations */
16
+ slotIds: string[]
17
+ /** Layout style */
18
+ layout?: RecommendationLayout
19
+ /** Number of columns for grid layout */
20
+ columns?: 2 | 3 | 4
21
+ /** Show navigation arrows for carousel */
22
+ showArrows?: boolean
23
+ /** Auto-scroll carousel */
24
+ autoScroll?: boolean
25
+ /** Auto-scroll interval (seconds) */
26
+ autoScrollInterval?: number
27
+ /** Custom class name */
28
+ className?: string
29
+ /** Callback when item is clicked */
30
+ onItemClick?: (slotId: string) => void
31
+ }
32
+
33
+ export function WakaContentRecommendation({
34
+ title = "You May Also Like",
35
+ slotIds,
36
+ layout = "grid",
37
+ columns = 3,
38
+ showArrows = true,
39
+ autoScroll = false,
40
+ autoScrollInterval = 5,
41
+ className,
42
+ onItemClick,
43
+ }: WakaContentRecommendationProps) {
44
+ const containerRef = useRef<HTMLDivElement>(null)
45
+ const carouselRef = useRef<HTMLDivElement>(null)
46
+ const { config, isReady, hasConsent, getCustomAd, trackEvent } = useAdContext()
47
+ const { isVisible } = useAdVisibility(containerRef)
48
+
49
+ const [ads, setAds] = useState<Map<string, CustomAd>>(new Map())
50
+ const [isLoading, setIsLoading] = useState(true)
51
+ const [currentSlide, setCurrentSlide] = useState(0)
52
+
53
+ // Load all ads
54
+ useEffect(() => {
55
+ if (!isReady || !isVisible || hasConsent === false) return
56
+
57
+ const loadAds = async () => {
58
+ setIsLoading(true)
59
+ const loadedAds = new Map<string, CustomAd>()
60
+
61
+ await Promise.all(
62
+ slotIds.map(async (slotId) => {
63
+ try {
64
+ const ad = await getCustomAd(slotId)
65
+ if (ad) {
66
+ loadedAds.set(slotId, ad)
67
+ trackEvent({ type: "loaded", slotId, timestamp: new Date() })
68
+
69
+ // Fire impression tracking
70
+ if (ad.impressionUrl) {
71
+ fetch(ad.impressionUrl, { mode: "no-cors" }).catch(() => {})
72
+ }
73
+ }
74
+ } catch {
75
+ // Ignore errors for individual slots
76
+ }
77
+ })
78
+ )
79
+
80
+ setAds(loadedAds)
81
+ setIsLoading(false)
82
+ }
83
+
84
+ loadAds()
85
+ }, [isReady, isVisible, hasConsent, slotIds, getCustomAd, trackEvent])
86
+
87
+ // Track viewability for loaded ads
88
+ useEffect(() => {
89
+ if (isVisible && ads.size > 0) {
90
+ ads.forEach((_, slotId) => {
91
+ trackEvent({ type: "viewable", slotId, timestamp: new Date() })
92
+ })
93
+ }
94
+ }, [isVisible, ads, trackEvent])
95
+
96
+ // Auto-scroll for carousel
97
+ useEffect(() => {
98
+ if (layout !== "carousel" || !autoScroll || ads.size === 0) return
99
+
100
+ const interval = setInterval(() => {
101
+ setCurrentSlide((prev) => (prev + 1) % ads.size)
102
+ }, autoScrollInterval * 1000)
103
+
104
+ return () => clearInterval(interval)
105
+ }, [layout, autoScroll, autoScrollInterval, ads.size])
106
+
107
+ // Scroll carousel to current slide
108
+ useEffect(() => {
109
+ if (layout !== "carousel" || !carouselRef.current) return
110
+
111
+ const slideWidth = carouselRef.current.offsetWidth / Math.min(columns, ads.size)
112
+ carouselRef.current.scrollTo({
113
+ left: currentSlide * slideWidth,
114
+ behavior: "smooth",
115
+ })
116
+ }, [currentSlide, layout, columns, ads.size])
117
+
118
+ const handleItemClick = (slotId: string, ad: CustomAd) => {
119
+ trackEvent({ type: "click", slotId, timestamp: new Date() })
120
+ onItemClick?.(slotId)
121
+
122
+ if (ad.clickUrl) {
123
+ fetch(ad.clickUrl, { mode: "no-cors" }).catch(() => {})
124
+ }
125
+ if (ad.targetUrl) {
126
+ window.open(ad.targetUrl, "_blank", "noopener,noreferrer")
127
+ }
128
+ }
129
+
130
+ const handlePrev = () => {
131
+ setCurrentSlide((prev) => (prev - 1 + ads.size) % ads.size)
132
+ }
133
+
134
+ const handleNext = () => {
135
+ setCurrentSlide((prev) => (prev + 1) % ads.size)
136
+ }
137
+
138
+ if (ads.size === 0 && !isLoading) {
139
+ return null
140
+ }
141
+
142
+ const columnClasses = {
143
+ 2: "grid-cols-1 sm:grid-cols-2",
144
+ 3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
145
+ 4: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4",
146
+ }
147
+
148
+ const renderItem = (slotId: string, ad: CustomAd) => (
149
+ <button
150
+ key={slotId}
151
+ onClick={() => handleItemClick(slotId, ad)}
152
+ className="group flex-shrink-0 w-full text-left rounded-lg overflow-hidden bg-card border hover:shadow-md transition-shadow"
153
+ >
154
+ {ad.imageUrl && (
155
+ <div className="relative aspect-video bg-muted overflow-hidden">
156
+ <img
157
+ src={ad.imageUrl}
158
+ alt=""
159
+ className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
160
+ />
161
+ </div>
162
+ )}
163
+
164
+ <div className="p-3">
165
+ <h4 className="font-medium text-sm line-clamp-2 mb-1 group-hover:text-primary transition-colors">
166
+ {ad.title}
167
+ </h4>
168
+
169
+ <div className="flex items-center justify-between">
170
+ <span className="text-xs text-muted-foreground">
171
+ {ad.sponsor || "Sponsored"}
172
+ </span>
173
+ <ExternalLink className="h-3 w-3 text-muted-foreground" />
174
+ </div>
175
+ </div>
176
+ </button>
177
+ )
178
+
179
+ return (
180
+ <div
181
+ ref={containerRef}
182
+ className={cn("relative", className)}
183
+ >
184
+ {/* Header */}
185
+ <div className="flex items-center justify-between mb-4">
186
+ <div className="flex items-center gap-3">
187
+ <h3 className="font-semibold text-lg">{title}</h3>
188
+ <WakaSponsoredBadge size="sm" showIcon={false} />
189
+ </div>
190
+
191
+ {layout === "carousel" && showArrows && ads.size > columns && (
192
+ <div className="flex items-center gap-2">
193
+ <button
194
+ onClick={handlePrev}
195
+ className="p-1.5 rounded-full bg-muted hover:bg-muted-foreground/20 transition-colors"
196
+ aria-label="Previous"
197
+ >
198
+ <ChevronLeft className="h-4 w-4" />
199
+ </button>
200
+ <button
201
+ onClick={handleNext}
202
+ className="p-1.5 rounded-full bg-muted hover:bg-muted-foreground/20 transition-colors"
203
+ aria-label="Next"
204
+ >
205
+ <ChevronRight className="h-4 w-4" />
206
+ </button>
207
+ </div>
208
+ )}
209
+ </div>
210
+
211
+ {/* Content */}
212
+ {isLoading ? (
213
+ <div className={cn("grid gap-4", columnClasses[columns])}>
214
+ {slotIds.slice(0, columns).map((_, i) => (
215
+ <div
216
+ key={i}
217
+ className="rounded-lg border bg-muted animate-pulse aspect-[4/3]"
218
+ />
219
+ ))}
220
+ </div>
221
+ ) : layout === "grid" ? (
222
+ <div className={cn("grid gap-4", columnClasses[columns])}>
223
+ {Array.from(ads.entries()).map(([slotId, ad]) => renderItem(slotId, ad))}
224
+ </div>
225
+ ) : layout === "carousel" ? (
226
+ <div
227
+ ref={carouselRef}
228
+ className="flex gap-4 overflow-x-auto scrollbar-hide snap-x snap-mandatory"
229
+ style={{ scrollbarWidth: "none", msOverflowStyle: "none" }}
230
+ >
231
+ {Array.from(ads.entries()).map(([slotId, ad]) => (
232
+ <div
233
+ key={slotId}
234
+ className="snap-start"
235
+ style={{ minWidth: `calc((100% - ${(columns - 1) * 16}px) / ${columns})` }}
236
+ >
237
+ {renderItem(slotId, ad)}
238
+ </div>
239
+ ))}
240
+ </div>
241
+ ) : (
242
+ <div className="space-y-3">
243
+ {Array.from(ads.entries()).map(([slotId, ad]) => (
244
+ <button
245
+ key={slotId}
246
+ onClick={() => handleItemClick(slotId, ad)}
247
+ className="group w-full flex gap-3 p-2 rounded-lg border hover:bg-accent/50 transition-colors text-left"
248
+ >
249
+ {ad.imageUrl && (
250
+ <div className="w-20 h-20 flex-shrink-0 rounded-md overflow-hidden bg-muted">
251
+ <img
252
+ src={ad.imageUrl}
253
+ alt=""
254
+ className="w-full h-full object-cover"
255
+ />
256
+ </div>
257
+ )}
258
+
259
+ <div className="flex-1 min-w-0">
260
+ <h4 className="font-medium text-sm line-clamp-2 mb-1 group-hover:text-primary transition-colors">
261
+ {ad.title}
262
+ </h4>
263
+ <span className="text-xs text-muted-foreground">
264
+ {ad.sponsor || "Sponsored"}
265
+ </span>
266
+ </div>
267
+ </button>
268
+ ))}
269
+ </div>
270
+ )}
271
+
272
+ {/* Pagination dots for carousel */}
273
+ {layout === "carousel" && ads.size > columns && (
274
+ <div className="flex justify-center gap-1.5 mt-4">
275
+ {Array.from({ length: Math.ceil(ads.size / columns) }).map((_, i) => (
276
+ <button
277
+ key={i}
278
+ onClick={() => setCurrentSlide(i * columns)}
279
+ className={cn(
280
+ "w-2 h-2 rounded-full transition-colors",
281
+ Math.floor(currentSlide / columns) === i
282
+ ? "bg-primary"
283
+ : "bg-muted-foreground/30"
284
+ )}
285
+ aria-label={`Go to slide ${i + 1}`}
286
+ />
287
+ ))}
288
+ </div>
289
+ )}
290
+ </div>
291
+ )
292
+ }
293
+
294
+ export default WakaContentRecommendation
@@ -48,16 +48,16 @@ export interface WakaCostBreakdownProps {
48
48
  // ============================================================================
49
49
 
50
50
  const defaultColors = [
51
- "#3b82f6", // blue
52
- "#ef4444", // red
53
- "#22c55e", // green
54
- "#f59e0b", // amber
55
- "#8b5cf6", // violet
56
- "#ec4899", // pink
57
- "#14b8a6", // teal
58
- "#f97316", // orange
59
- "#6366f1", // indigo
60
- "#84cc16", // lime
51
+ "hsl(var(--chart-1))",
52
+ "hsl(var(--chart-2))",
53
+ "hsl(var(--chart-3))",
54
+ "hsl(var(--chart-4))",
55
+ "hsl(var(--chart-5))",
56
+ "hsl(var(--primary))",
57
+ "hsl(var(--info))",
58
+ "hsl(var(--warning))",
59
+ "hsl(var(--success))",
60
+ "hsl(var(--destructive))",
61
61
  ]
62
62
 
63
63
  // ============================================================================