aboutsummaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorMax Nanis2025-06-09 04:44:45 +0700
committerMax Nanis2025-06-09 04:44:45 +0700
commita674d2e03de3bd048714d9c06e4bba9d9ecdb328 (patch)
tree130a07e0cc631a81b560c847ed7794d470c25e22 /src/lib
parent438585f6e6cdebc3089739ddf77382aebe09fac1 (diff)
downloadpanel-ui-a674d2e03de3bd048714d9c06e4bba9d9ecdb328.tar.gz
panel-ui-a674d2e03de3bd048714d9c06e4bba9d9ecdb328.zip
Offerwall page - using datatables to show the bucket contents, setting up tabs to allow overview and detail insights of buckets, formatting of height and layout, playing with iqr, connection to conditionally eligible sidebar
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/snippets.tsx80
-rw-r--r--src/lib/utils.ts26
2 files changed, 105 insertions, 1 deletions
diff --git a/src/lib/snippets.tsx b/src/lib/snippets.tsx
new file mode 100644
index 0000000..5e95cd2
--- /dev/null
+++ b/src/lib/snippets.tsx
@@ -0,0 +1,80 @@
+import React from "react";
+
+type IQRData = {
+ min: number;
+ q1: number;
+ median: number;
+ q3: number;
+ max: number;
+};
+
+type IQRBoxPlotProps = {
+ data: IQRData;
+};
+
+export const IQRBoxPlot: React.FC<IQRBoxPlotProps> = ({data}) => {
+ const {min, q1, median, q3, max} = data;
+
+ const scale = (value: number): number =>
+ ((value - min) / (max - min)) * 100;
+
+ return (
+ <div className="w-full p-4">
+ <div className="text-sm mb-2 text-muted-foreground">Box Plot</div>
+ <svg viewBox="0 0 100 20" className="w-full h-12">
+ <line
+ x1={scale(min)}
+ x2={scale(q1)}
+ y1={10}
+ y2={10}
+ stroke="#999"
+ strokeWidth={1}
+ />
+
+ <line
+ x1={scale(q3)}
+ x2={scale(max)}
+ y1={10}
+ y2={10}
+ stroke="#999"
+ strokeWidth={1}
+ />
+
+ <rect
+ x={scale(q1)}
+ y={5}
+ width={scale(q3) - scale(q1)}
+ height={10}
+ fill="#e2e8f0"
+ stroke="#64748b"
+ strokeWidth={1}
+ />
+
+ <line
+ x1={scale(median)}
+ x2={scale(median)}
+ y1={5}
+ y2={15}
+ stroke="#1e293b"
+ stroke-width={1.5}
+ />
+
+ <line
+ x1={scale(min)}
+ x2={scale(min)}
+ y1={7}
+ y2={13}
+ stroke="#666"
+ strokeWidth={1}/>
+
+ <line
+ x1={scale(max)}
+ x2={scale(max)}
+ y1={7}
+ y2={13}
+ stroke="#666"
+ strokeWidth={1}/>
+ </svg>
+ </div>
+ )
+}; \ No newline at end of file
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index 8525468..b1cd120 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -1,5 +1,6 @@
import {type ClassValue, clsx} from "clsx"
import {twMerge} from "tailwind-merge"
+import React from "react";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
@@ -9,4 +10,27 @@ export function assert(condition: any, msg?: string): asserts condition {
if (!condition) {
throw new Error(msg);
}
-} \ No newline at end of file
+}
+
+export function formatSecondsVerbose(seconds: number): string {
+ const mins = Math.floor(seconds / 60)
+ const secs = seconds % 60
+ const parts = []
+ if (mins > 0) parts.push(`${mins} min`)
+ if (secs > 0 || mins === 0) parts.push(`${secs} sec`)
+ return parts.join(" ")
+}
+
+export function formatSeconds(seconds: number): string {
+ const mins = Math.floor(seconds / 60)
+ const secs = seconds % 60
+ const paddedSecs = secs.toString().padStart(2, '0')
+ return `${mins}:${paddedSecs}`
+}
+
+export function formatCentsToUSD(cents: number): string {
+ return new Intl.NumberFormat('en-US', {
+ style: 'currency',
+ currency: 'USD',
+ }).format(cents / 100)
+}