@braintwopoint0/playback-commons 0.1.10 → 0.1.12

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/dist/ui/index.js CHANGED
@@ -15,7 +15,7 @@ function cn(...inputs) {
15
15
  // src/ui/button.tsx
16
16
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
17
17
  var buttonVariants = cva(
18
- "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
18
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium cursor-pointer ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
19
19
  {
20
20
  variants: {
21
21
  variant: {
@@ -899,14 +899,555 @@ var Highlight = ({
899
899
  );
900
900
  };
901
901
 
902
- // src/ui/chart.tsx
902
+ // src/ui/popover.tsx
903
903
  import * as React10 from "react";
904
+ import * as PopoverPrimitive from "@radix-ui/react-popover";
905
+ import { jsx as jsx12 } from "react/jsx-runtime";
906
+ var Popover = PopoverPrimitive.Root;
907
+ var PopoverTrigger = PopoverPrimitive.Trigger;
908
+ var PopoverAnchor = PopoverPrimitive.Anchor;
909
+ var PopoverContent = React10.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx12(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx12(
910
+ PopoverPrimitive.Content,
911
+ {
912
+ ref,
913
+ align,
914
+ sideOffset,
915
+ className: cn(
916
+ "z-50 w-72 rounded-md border border-zinc-800 bg-zinc-950 p-4 text-zinc-50 shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-popover-content-transform-origin]",
917
+ className
918
+ ),
919
+ ...props
920
+ }
921
+ ) }));
922
+ PopoverContent.displayName = PopoverPrimitive.Content.displayName;
923
+
924
+ // src/ui/calendar.tsx
925
+ import * as React11 from "react";
926
+ import {
927
+ ChevronDownIcon,
928
+ ChevronLeftIcon,
929
+ ChevronRightIcon
930
+ } from "lucide-react";
931
+ import { DayPicker, getDefaultClassNames } from "react-day-picker";
932
+ import { jsx as jsx13 } from "react/jsx-runtime";
933
+ function Calendar({
934
+ className,
935
+ classNames,
936
+ showOutsideDays = true,
937
+ captionLayout = "label",
938
+ buttonVariant = "ghost",
939
+ formatters,
940
+ components,
941
+ ...props
942
+ }) {
943
+ const defaultClassNames = getDefaultClassNames();
944
+ return /* @__PURE__ */ jsx13(
945
+ DayPicker,
946
+ {
947
+ showOutsideDays,
948
+ className: cn(
949
+ "bg-zinc-950 group/calendar p-3 [--cell-size:2rem] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",
950
+ String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
951
+ String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
952
+ className
953
+ ),
954
+ captionLayout,
955
+ formatters: {
956
+ formatMonthDropdown: (date) => date.toLocaleString("default", { month: "short" }),
957
+ ...formatters
958
+ },
959
+ classNames: {
960
+ root: cn("w-fit", defaultClassNames.root),
961
+ months: cn(
962
+ "relative flex flex-col gap-4 md:flex-row",
963
+ defaultClassNames.months
964
+ ),
965
+ month: cn("flex w-full flex-col gap-4", defaultClassNames.month),
966
+ nav: cn(
967
+ "absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1",
968
+ defaultClassNames.nav
969
+ ),
970
+ button_previous: cn(
971
+ buttonVariants({ variant: buttonVariant }),
972
+ "h-[--cell-size] w-[--cell-size] select-none p-0 aria-disabled:opacity-50",
973
+ defaultClassNames.button_previous
974
+ ),
975
+ button_next: cn(
976
+ buttonVariants({ variant: buttonVariant }),
977
+ "h-[--cell-size] w-[--cell-size] select-none p-0 aria-disabled:opacity-50",
978
+ defaultClassNames.button_next
979
+ ),
980
+ month_caption: cn(
981
+ "flex h-[--cell-size] w-full items-center justify-center px-[--cell-size]",
982
+ defaultClassNames.month_caption
983
+ ),
984
+ dropdowns: cn(
985
+ "flex h-[--cell-size] w-full items-center justify-center gap-1.5 text-sm font-medium",
986
+ defaultClassNames.dropdowns
987
+ ),
988
+ dropdown_root: cn(
989
+ "has-focus:border-zinc-300 border-zinc-800 shadow-xs has-focus:ring-zinc-300/50 has-focus:ring-[3px] relative rounded-md border",
990
+ defaultClassNames.dropdown_root
991
+ ),
992
+ dropdown: cn("absolute inset-0 opacity-0", defaultClassNames.dropdown),
993
+ caption_label: cn(
994
+ "select-none font-medium",
995
+ captionLayout === "label" ? "text-sm" : "[&>svg]:text-zinc-400 flex h-8 items-center gap-1 rounded-md pl-2 pr-1 text-sm [&>svg]:size-3.5",
996
+ defaultClassNames.caption_label
997
+ ),
998
+ table: "w-full border-collapse",
999
+ weekdays: cn("flex", defaultClassNames.weekdays),
1000
+ weekday: cn(
1001
+ "text-zinc-400 flex-1 select-none rounded-md text-[0.8rem] font-normal",
1002
+ defaultClassNames.weekday
1003
+ ),
1004
+ week: cn("mt-2 flex w-full", defaultClassNames.week),
1005
+ week_number_header: cn(
1006
+ "w-[--cell-size] select-none",
1007
+ defaultClassNames.week_number_header
1008
+ ),
1009
+ week_number: cn(
1010
+ "text-zinc-400 select-none text-[0.8rem]",
1011
+ defaultClassNames.week_number
1012
+ ),
1013
+ day: cn(
1014
+ "group/day relative aspect-square h-full w-full select-none p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md",
1015
+ defaultClassNames.day
1016
+ ),
1017
+ range_start: cn(
1018
+ "bg-zinc-800 rounded-l-md",
1019
+ defaultClassNames.range_start
1020
+ ),
1021
+ range_middle: cn("rounded-none", defaultClassNames.range_middle),
1022
+ range_end: cn("bg-zinc-800 rounded-r-md", defaultClassNames.range_end),
1023
+ today: cn(
1024
+ "bg-zinc-800 text-zinc-50 rounded-md data-[selected=true]:rounded-none",
1025
+ defaultClassNames.today
1026
+ ),
1027
+ outside: cn(
1028
+ "text-zinc-400 aria-selected:text-zinc-400",
1029
+ defaultClassNames.outside
1030
+ ),
1031
+ disabled: cn("text-zinc-400 opacity-50", defaultClassNames.disabled),
1032
+ hidden: cn("invisible", defaultClassNames.hidden),
1033
+ ...classNames
1034
+ },
1035
+ components: {
1036
+ Root: ({ className: className2, rootRef, ...props2 }) => {
1037
+ return /* @__PURE__ */ jsx13(
1038
+ "div",
1039
+ {
1040
+ "data-slot": "calendar",
1041
+ ref: rootRef,
1042
+ className: cn(className2),
1043
+ ...props2
1044
+ }
1045
+ );
1046
+ },
1047
+ Chevron: ({ className: className2, orientation, ...props2 }) => {
1048
+ if (orientation === "left") {
1049
+ return /* @__PURE__ */ jsx13(ChevronLeftIcon, { className: cn("size-4", className2), ...props2 });
1050
+ }
1051
+ if (orientation === "right") {
1052
+ return /* @__PURE__ */ jsx13(
1053
+ ChevronRightIcon,
1054
+ {
1055
+ className: cn("size-4", className2),
1056
+ ...props2
1057
+ }
1058
+ );
1059
+ }
1060
+ return /* @__PURE__ */ jsx13(ChevronDownIcon, { className: cn("size-4", className2), ...props2 });
1061
+ },
1062
+ DayButton: CalendarDayButton,
1063
+ WeekNumber: ({ children, ...props2 }) => {
1064
+ return /* @__PURE__ */ jsx13("td", { ...props2, children: /* @__PURE__ */ jsx13("div", { className: "flex size-[--cell-size] items-center justify-center text-center", children }) });
1065
+ },
1066
+ ...components
1067
+ },
1068
+ ...props
1069
+ }
1070
+ );
1071
+ }
1072
+ function CalendarDayButton({
1073
+ className,
1074
+ day,
1075
+ modifiers,
1076
+ ...props
1077
+ }) {
1078
+ const defaultClassNames = getDefaultClassNames();
1079
+ const ref = React11.useRef(null);
1080
+ React11.useEffect(() => {
1081
+ if (modifiers.focused) ref.current?.focus();
1082
+ }, [modifiers.focused]);
1083
+ return /* @__PURE__ */ jsx13(
1084
+ Button,
1085
+ {
1086
+ ref,
1087
+ variant: "ghost",
1088
+ size: "icon",
1089
+ "data-day": day.date.toLocaleDateString(),
1090
+ "data-selected-single": modifiers.selected && !modifiers.range_start && !modifiers.range_end && !modifiers.range_middle,
1091
+ "data-range-start": modifiers.range_start,
1092
+ "data-range-end": modifiers.range_end,
1093
+ "data-range-middle": modifiers.range_middle,
1094
+ className: cn(
1095
+ "data-[selected-single=true]:bg-zinc-50 data-[selected-single=true]:text-zinc-900 data-[range-middle=true]:bg-zinc-800 data-[range-middle=true]:text-zinc-50 data-[range-start=true]:bg-zinc-50 data-[range-start=true]:text-zinc-900 data-[range-end=true]:bg-zinc-50 data-[range-end=true]:text-zinc-900 group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 flex aspect-square h-auto w-full min-w-[--cell-size] flex-col gap-1 font-normal leading-none data-[range-end=true]:rounded-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] [&>span]:text-xs [&>span]:opacity-70",
1096
+ defaultClassNames.day,
1097
+ className
1098
+ ),
1099
+ ...props
1100
+ }
1101
+ );
1102
+ }
1103
+
1104
+ // src/ui/date-picker.tsx
1105
+ import * as React12 from "react";
1106
+ import { CalendarIcon } from "lucide-react";
1107
+ import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
1108
+ function DatePicker({
1109
+ value,
1110
+ onChange,
1111
+ min,
1112
+ max,
1113
+ className,
1114
+ id,
1115
+ placeholder = "Pick a date"
1116
+ }) {
1117
+ const [open, setOpen] = React12.useState(false);
1118
+ const selectedDate = value ? /* @__PURE__ */ new Date(value + "T00:00:00") : void 0;
1119
+ const minDate = min ? /* @__PURE__ */ new Date(min + "T00:00:00") : void 0;
1120
+ const maxDate = max ? /* @__PURE__ */ new Date(max + "T00:00:00") : void 0;
1121
+ const formatDate2 = (date) => {
1122
+ return date.toLocaleDateString("en-GB", {
1123
+ day: "2-digit",
1124
+ month: "short",
1125
+ year: "numeric"
1126
+ });
1127
+ };
1128
+ const handleDateSelect = (date) => {
1129
+ if (date) {
1130
+ const year = date.getFullYear();
1131
+ const month = String(date.getMonth() + 1).padStart(2, "0");
1132
+ const day = String(date.getDate()).padStart(2, "0");
1133
+ onChange(`${year}-${month}-${day}`);
1134
+ setOpen(false);
1135
+ }
1136
+ };
1137
+ return /* @__PURE__ */ jsxs8(Popover, { open, onOpenChange: setOpen, children: [
1138
+ /* @__PURE__ */ jsx14(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs8(
1139
+ Button,
1140
+ {
1141
+ id,
1142
+ variant: "outline",
1143
+ className: cn(
1144
+ "w-full justify-start text-left font-normal h-10 bg-zinc-800 border-none text-white shadow-input rounded-md px-3 py-2 text-sm",
1145
+ "focus-visible:outline-none focus-visible:ring-[2px] focus-visible:ring-neutral-600",
1146
+ "shadow-[0px_0px_1px_1px_var(--neutral-700)]",
1147
+ "hover:shadow-none transition duration-400",
1148
+ !selectedDate && "text-neutral-400",
1149
+ className
1150
+ ),
1151
+ children: [
1152
+ /* @__PURE__ */ jsx14(CalendarIcon, { className: "mr-2 h-4 w-4" }),
1153
+ selectedDate ? formatDate2(selectedDate) : /* @__PURE__ */ jsx14("span", { children: placeholder })
1154
+ ]
1155
+ }
1156
+ ) }),
1157
+ /* @__PURE__ */ jsx14(PopoverContent, { className: "w-auto p-0", align: "start", children: /* @__PURE__ */ jsx14(
1158
+ Calendar,
1159
+ {
1160
+ mode: "single",
1161
+ selected: selectedDate,
1162
+ onSelect: handleDateSelect,
1163
+ disabled: (date) => {
1164
+ const dateAtMidnight = new Date(
1165
+ date.getFullYear(),
1166
+ date.getMonth(),
1167
+ date.getDate()
1168
+ );
1169
+ if (minDate) {
1170
+ const minDateAtMidnight = new Date(
1171
+ minDate.getFullYear(),
1172
+ minDate.getMonth(),
1173
+ minDate.getDate()
1174
+ );
1175
+ if (dateAtMidnight < minDateAtMidnight) return true;
1176
+ }
1177
+ if (maxDate) {
1178
+ const maxDateAtMidnight = new Date(
1179
+ maxDate.getFullYear(),
1180
+ maxDate.getMonth(),
1181
+ maxDate.getDate()
1182
+ );
1183
+ if (dateAtMidnight > maxDateAtMidnight) return true;
1184
+ }
1185
+ return false;
1186
+ },
1187
+ initialFocus: true
1188
+ }
1189
+ ) })
1190
+ ] });
1191
+ }
1192
+
1193
+ // src/ui/time-picker.tsx
1194
+ import * as React13 from "react";
1195
+ import { ClockIcon } from "lucide-react";
1196
+ import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
1197
+ function TimePicker({
1198
+ value,
1199
+ onChange,
1200
+ placeholder = "Select time",
1201
+ className,
1202
+ disabled = false,
1203
+ min,
1204
+ max
1205
+ }) {
1206
+ const [open, setOpen] = React13.useState(false);
1207
+ const [hours, setHours] = React13.useState(
1208
+ value ? parseInt(value.split(":")[0]) : 9
1209
+ );
1210
+ const [minutes, setMinutes] = React13.useState(
1211
+ value ? parseInt(value.split(":")[1]) : 0
1212
+ );
1213
+ const formatTime = (h, m) => {
1214
+ return `${h.toString().padStart(2, "0")}:${m.toString().padStart(2, "0")}`;
1215
+ };
1216
+ const handleTimeSelect = (h, m) => {
1217
+ const timeString = formatTime(h, m);
1218
+ setHours(h);
1219
+ setMinutes(m);
1220
+ onChange?.(timeString);
1221
+ setOpen(false);
1222
+ };
1223
+ const generateTimeOptions = () => {
1224
+ const options = [];
1225
+ for (let h = 6; h <= 23; h++) {
1226
+ for (let m = 0; m < 60; m += 15) {
1227
+ const timeString = formatTime(h, m);
1228
+ if (min && timeString < min) continue;
1229
+ if (max && timeString > max) continue;
1230
+ options.push({ hours: h, minutes: m, display: timeString });
1231
+ }
1232
+ }
1233
+ return options;
1234
+ };
1235
+ const timeOptions = generateTimeOptions();
1236
+ const displayValue = value || "";
1237
+ return /* @__PURE__ */ jsxs9(Popover, { open, onOpenChange: setOpen, children: [
1238
+ /* @__PURE__ */ jsx15(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs9(
1239
+ Button,
1240
+ {
1241
+ variant: "outline",
1242
+ className: cn(
1243
+ "w-full justify-start text-left font-normal h-10 bg-zinc-800 border-none text-white shadow-input rounded-md px-3 py-2 text-sm",
1244
+ "focus-visible:outline-none focus-visible:ring-[2px] focus-visible:ring-neutral-600",
1245
+ "shadow-[0px_0px_1px_1px_var(--neutral-700)]",
1246
+ "hover:shadow-none transition duration-400",
1247
+ !value && "text-neutral-400",
1248
+ className
1249
+ ),
1250
+ disabled,
1251
+ children: [
1252
+ /* @__PURE__ */ jsx15(ClockIcon, { className: "mr-2 h-4 w-4" }),
1253
+ displayValue || placeholder
1254
+ ]
1255
+ }
1256
+ ) }),
1257
+ /* @__PURE__ */ jsx15(PopoverContent, { className: "w-auto p-0", align: "start", children: /* @__PURE__ */ jsx15("div", { className: "max-h-60 overflow-y-auto", children: /* @__PURE__ */ jsx15("div", { className: "grid grid-cols-1 gap-1 p-2", children: timeOptions.map(({ hours: h, minutes: m, display }) => /* @__PURE__ */ jsx15(
1258
+ Button,
1259
+ {
1260
+ variant: value === display ? "default" : "ghost",
1261
+ className: "justify-start text-left h-8 text-sm",
1262
+ onClick: () => handleTimeSelect(h, m),
1263
+ children: display
1264
+ },
1265
+ display
1266
+ )) }) }) })
1267
+ ] });
1268
+ }
1269
+
1270
+ // src/ui/datetime-picker.tsx
1271
+ import * as React14 from "react";
1272
+ import { CalendarIcon as CalendarIcon2 } from "lucide-react";
1273
+ import { jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
1274
+ function DateTimePicker({
1275
+ value,
1276
+ onChange,
1277
+ placeholder = "Pick date & time",
1278
+ className,
1279
+ disabled = false,
1280
+ required = false
1281
+ }) {
1282
+ const [open, setOpen] = React14.useState(false);
1283
+ const hourRef = React14.useRef(null);
1284
+ const minuteRef = React14.useRef(null);
1285
+ const datePart = value ? value.split("T")[0] : "";
1286
+ const timePart = value ? value.split("T")[1] || "" : "";
1287
+ const selectedHour = timePart ? parseInt(timePart.split(":")[0]) : -1;
1288
+ const selectedMinute = timePart ? parseInt(timePart.split(":")[1]) : -1;
1289
+ const selectedDate = datePart ? /* @__PURE__ */ new Date(datePart + "T00:00:00") : void 0;
1290
+ const formatDisplay = (val) => {
1291
+ if (!val) return "";
1292
+ const [d, t] = val.split("T");
1293
+ if (!d) return "";
1294
+ const date = /* @__PURE__ */ new Date(d + "T00:00:00");
1295
+ const dateStr = date.toLocaleDateString("en-GB", {
1296
+ day: "2-digit",
1297
+ month: "short",
1298
+ year: "numeric"
1299
+ });
1300
+ if (!t) return dateStr;
1301
+ return `${dateStr}, ${t}`;
1302
+ };
1303
+ const buildValue = (date, hour, minute) => {
1304
+ const h = hour.toString().padStart(2, "0");
1305
+ const m = minute.toString().padStart(2, "0");
1306
+ return `${date}T${h}:${m}`;
1307
+ };
1308
+ const handleDateSelect = (date) => {
1309
+ if (!date) return;
1310
+ const year = date.getFullYear();
1311
+ const month = String(date.getMonth() + 1).padStart(2, "0");
1312
+ const day = String(date.getDate()).padStart(2, "0");
1313
+ const newDate = `${year}-${month}-${day}`;
1314
+ const h = selectedHour >= 0 ? selectedHour : 12;
1315
+ const m = selectedMinute >= 0 ? selectedMinute : 0;
1316
+ onChange(buildValue(newDate, h, m));
1317
+ };
1318
+ const handleHourSelect = (h) => {
1319
+ if (!datePart) {
1320
+ const now = /* @__PURE__ */ new Date();
1321
+ const year = now.getFullYear();
1322
+ const month = String(now.getMonth() + 1).padStart(2, "0");
1323
+ const day = String(now.getDate()).padStart(2, "0");
1324
+ const m = selectedMinute >= 0 ? selectedMinute : 0;
1325
+ onChange(buildValue(`${year}-${month}-${day}`, h, m));
1326
+ } else {
1327
+ const m = selectedMinute >= 0 ? selectedMinute : 0;
1328
+ onChange(buildValue(datePart, h, m));
1329
+ }
1330
+ };
1331
+ const handleMinuteSelect = (m) => {
1332
+ if (!datePart) {
1333
+ const now = /* @__PURE__ */ new Date();
1334
+ const year = now.getFullYear();
1335
+ const month = String(now.getMonth() + 1).padStart(2, "0");
1336
+ const day = String(now.getDate()).padStart(2, "0");
1337
+ const h = selectedHour >= 0 ? selectedHour : 12;
1338
+ onChange(buildValue(`${year}-${month}-${day}`, h, m));
1339
+ } else {
1340
+ const h = selectedHour >= 0 ? selectedHour : 12;
1341
+ onChange(buildValue(datePart, h, m));
1342
+ }
1343
+ };
1344
+ React14.useEffect(() => {
1345
+ if (open) {
1346
+ setTimeout(() => {
1347
+ if (hourRef.current && selectedHour >= 0) {
1348
+ const el = hourRef.current.querySelector(`[data-hour="${selectedHour}"]`);
1349
+ el?.scrollIntoView({ block: "center" });
1350
+ }
1351
+ if (minuteRef.current && selectedMinute >= 0) {
1352
+ const el = minuteRef.current.querySelector(`[data-minute="${selectedMinute}"]`);
1353
+ el?.scrollIntoView({ block: "center" });
1354
+ }
1355
+ }, 50);
1356
+ }
1357
+ }, [open, selectedHour, selectedMinute]);
1358
+ return /* @__PURE__ */ jsxs10(Popover, { open, onOpenChange: setOpen, children: [
1359
+ /* @__PURE__ */ jsx16(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs10(
1360
+ Button,
1361
+ {
1362
+ type: "button",
1363
+ variant: "outline",
1364
+ disabled,
1365
+ className: cn(
1366
+ "w-full justify-start text-left font-normal h-10 bg-zinc-800 border-none text-white shadow-input rounded-md px-3 py-2 text-sm",
1367
+ "focus-visible:outline-none focus-visible:ring-[2px] focus-visible:ring-neutral-600",
1368
+ "shadow-[0px_0px_1px_1px_var(--neutral-700)]",
1369
+ "hover:shadow-none transition duration-400",
1370
+ !value && "text-neutral-400",
1371
+ className
1372
+ ),
1373
+ children: [
1374
+ /* @__PURE__ */ jsx16(CalendarIcon2, { className: "mr-2 h-4 w-4 shrink-0" }),
1375
+ value ? formatDisplay(value) : /* @__PURE__ */ jsx16("span", { children: placeholder })
1376
+ ]
1377
+ }
1378
+ ) }),
1379
+ /* @__PURE__ */ jsx16(PopoverContent, { className: "w-auto p-0", align: "start", children: /* @__PURE__ */ jsxs10("div", { className: "flex", children: [
1380
+ /* @__PURE__ */ jsx16(
1381
+ Calendar,
1382
+ {
1383
+ mode: "single",
1384
+ selected: selectedDate,
1385
+ onSelect: handleDateSelect,
1386
+ initialFocus: true
1387
+ }
1388
+ ),
1389
+ /* @__PURE__ */ jsxs10("div", { className: "flex border-l border-zinc-800", children: [
1390
+ /* @__PURE__ */ jsxs10(
1391
+ "div",
1392
+ {
1393
+ ref: hourRef,
1394
+ className: "h-[280px] w-16 overflow-y-auto p-1",
1395
+ children: [
1396
+ /* @__PURE__ */ jsx16("div", { className: "px-1 py-1.5 text-center text-xs text-zinc-400 font-medium", children: "Hr" }),
1397
+ Array.from({ length: 24 }, (_, i) => /* @__PURE__ */ jsx16(
1398
+ "button",
1399
+ {
1400
+ "data-hour": i,
1401
+ type: "button",
1402
+ onClick: () => handleHourSelect(i),
1403
+ className: cn(
1404
+ "w-full rounded-md px-2 py-1.5 text-sm text-center cursor-pointer transition-colors",
1405
+ selectedHour === i ? "bg-zinc-50 text-zinc-900 font-medium" : "text-zinc-300 hover:bg-zinc-800"
1406
+ ),
1407
+ children: i.toString().padStart(2, "0")
1408
+ },
1409
+ i
1410
+ ))
1411
+ ]
1412
+ }
1413
+ ),
1414
+ /* @__PURE__ */ jsxs10(
1415
+ "div",
1416
+ {
1417
+ ref: minuteRef,
1418
+ className: "h-[280px] w-16 overflow-y-auto border-l border-zinc-800 p-1",
1419
+ children: [
1420
+ /* @__PURE__ */ jsx16("div", { className: "px-1 py-1.5 text-center text-xs text-zinc-400 font-medium", children: "Min" }),
1421
+ Array.from({ length: 12 }, (_, i) => i * 5).map((m) => /* @__PURE__ */ jsx16(
1422
+ "button",
1423
+ {
1424
+ "data-minute": m,
1425
+ type: "button",
1426
+ onClick: () => handleMinuteSelect(m),
1427
+ className: cn(
1428
+ "w-full rounded-md px-2 py-1.5 text-sm text-center cursor-pointer transition-colors",
1429
+ selectedMinute === m ? "bg-zinc-50 text-zinc-900 font-medium" : "text-zinc-300 hover:bg-zinc-800"
1430
+ ),
1431
+ children: m.toString().padStart(2, "0")
1432
+ },
1433
+ m
1434
+ ))
1435
+ ]
1436
+ }
1437
+ )
1438
+ ] })
1439
+ ] }) })
1440
+ ] });
1441
+ }
1442
+
1443
+ // src/ui/chart.tsx
1444
+ import * as React15 from "react";
904
1445
  import * as RechartsPrimitive from "recharts";
905
- import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
1446
+ import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
906
1447
  var THEMES = { light: "", dark: ".dark" };
907
- var ChartContext = React10.createContext(null);
1448
+ var ChartContext = React15.createContext(null);
908
1449
  function useChart() {
909
- const context = React10.useContext(ChartContext);
1450
+ const context = React15.useContext(ChartContext);
910
1451
  if (!context) {
911
1452
  throw new Error("useChart must be used within a <ChartContainer />");
912
1453
  }
@@ -919,9 +1460,9 @@ function ChartContainer({
919
1460
  config,
920
1461
  ...props
921
1462
  }) {
922
- const uniqueId = React10.useId();
1463
+ const uniqueId = React15.useId();
923
1464
  const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`;
924
- return /* @__PURE__ */ jsx12(ChartContext.Provider, { value: { config }, children: /* @__PURE__ */ jsxs8(
1465
+ return /* @__PURE__ */ jsx17(ChartContext.Provider, { value: { config }, children: /* @__PURE__ */ jsxs11(
925
1466
  "div",
926
1467
  {
927
1468
  "data-slot": "chart",
@@ -932,8 +1473,8 @@ function ChartContainer({
932
1473
  ),
933
1474
  ...props,
934
1475
  children: [
935
- /* @__PURE__ */ jsx12(ChartStyle, { id: chartId, config }),
936
- /* @__PURE__ */ jsx12(RechartsPrimitive.ResponsiveContainer, { children })
1476
+ /* @__PURE__ */ jsx17(ChartStyle, { id: chartId, config }),
1477
+ /* @__PURE__ */ jsx17(RechartsPrimitive.ResponsiveContainer, { children })
937
1478
  ]
938
1479
  }
939
1480
  ) });
@@ -945,7 +1486,7 @@ var ChartStyle = ({ id, config }) => {
945
1486
  if (!colorConfig.length) {
946
1487
  return null;
947
1488
  }
948
- return /* @__PURE__ */ jsx12(
1489
+ return /* @__PURE__ */ jsx17(
949
1490
  "style",
950
1491
  {
951
1492
  dangerouslySetInnerHTML: {
@@ -980,7 +1521,7 @@ function ChartTooltipContent({
980
1521
  labelKey
981
1522
  }) {
982
1523
  const { config } = useChart();
983
- const tooltipLabel = React10.useMemo(() => {
1524
+ const tooltipLabel = React15.useMemo(() => {
984
1525
  if (hideLabel || !payload?.length) {
985
1526
  return null;
986
1527
  }
@@ -989,12 +1530,12 @@ function ChartTooltipContent({
989
1530
  const itemConfig = getPayloadConfigFromPayload(config, item, key);
990
1531
  const value = !labelKey && typeof label === "string" ? config[label]?.label || label : itemConfig?.label;
991
1532
  if (labelFormatter) {
992
- return /* @__PURE__ */ jsx12("div", { className: cn("font-medium", labelClassName), children: labelFormatter(value, payload) });
1533
+ return /* @__PURE__ */ jsx17("div", { className: cn("font-medium", labelClassName), children: labelFormatter(value, payload) });
993
1534
  }
994
1535
  if (!value) {
995
1536
  return null;
996
1537
  }
997
- return /* @__PURE__ */ jsx12("div", { className: cn("font-medium", labelClassName), children: value });
1538
+ return /* @__PURE__ */ jsx17("div", { className: cn("font-medium", labelClassName), children: value });
998
1539
  }, [
999
1540
  label,
1000
1541
  labelFormatter,
@@ -1008,7 +1549,7 @@ function ChartTooltipContent({
1008
1549
  return null;
1009
1550
  }
1010
1551
  const nestLabel = payload.length === 1 && indicator !== "dot";
1011
- return /* @__PURE__ */ jsxs8(
1552
+ return /* @__PURE__ */ jsxs11(
1012
1553
  "div",
1013
1554
  {
1014
1555
  className: cn(
@@ -1017,19 +1558,19 @@ function ChartTooltipContent({
1017
1558
  ),
1018
1559
  children: [
1019
1560
  !nestLabel ? tooltipLabel : null,
1020
- /* @__PURE__ */ jsx12("div", { className: "grid gap-1.5", children: payload.filter((item) => item.type !== "none").map((item, index) => {
1561
+ /* @__PURE__ */ jsx17("div", { className: "grid gap-1.5", children: payload.filter((item) => item.type !== "none").map((item, index) => {
1021
1562
  const key = `${nameKey || item.name || item.dataKey || "value"}`;
1022
1563
  const itemConfig = getPayloadConfigFromPayload(config, item, key);
1023
1564
  const indicatorColor = color || item.payload.fill || item.color;
1024
- return /* @__PURE__ */ jsx12(
1565
+ return /* @__PURE__ */ jsx17(
1025
1566
  "div",
1026
1567
  {
1027
1568
  className: cn(
1028
1569
  "flex w-full flex-wrap items-stretch gap-2",
1029
1570
  indicator === "dot" && "items-center"
1030
1571
  ),
1031
- children: formatter && item?.value !== void 0 && item.name ? formatter(item.value, item.name, item, index, item.payload) : /* @__PURE__ */ jsxs8(Fragment3, { children: [
1032
- itemConfig?.icon ? /* @__PURE__ */ jsx12(itemConfig.icon, {}) : !hideIndicator && /* @__PURE__ */ jsx12(
1572
+ children: formatter && item?.value !== void 0 && item.name ? formatter(item.value, item.name, item, index, item.payload) : /* @__PURE__ */ jsxs11(Fragment3, { children: [
1573
+ itemConfig?.icon ? /* @__PURE__ */ jsx17(itemConfig.icon, {}) : !hideIndicator && /* @__PURE__ */ jsx17(
1033
1574
  "div",
1034
1575
  {
1035
1576
  className: cn(
@@ -1047,7 +1588,7 @@ function ChartTooltipContent({
1047
1588
  }
1048
1589
  }
1049
1590
  ),
1050
- /* @__PURE__ */ jsxs8(
1591
+ /* @__PURE__ */ jsxs11(
1051
1592
  "div",
1052
1593
  {
1053
1594
  className: cn(
@@ -1055,11 +1596,11 @@ function ChartTooltipContent({
1055
1596
  nestLabel ? "items-end" : "items-center"
1056
1597
  ),
1057
1598
  children: [
1058
- /* @__PURE__ */ jsxs8("div", { className: "grid gap-1.5", children: [
1599
+ /* @__PURE__ */ jsxs11("div", { className: "grid gap-1.5", children: [
1059
1600
  nestLabel ? tooltipLabel : null,
1060
- /* @__PURE__ */ jsx12("span", { className: "text-[var(--ash-grey)]", children: itemConfig?.label || item.name })
1601
+ /* @__PURE__ */ jsx17("span", { className: "text-[var(--ash-grey)]", children: itemConfig?.label || item.name })
1061
1602
  ] }),
1062
- item.value && /* @__PURE__ */ jsx12("span", { className: "text-[var(--timberwolf)] font-mono font-medium tabular-nums", children: item.value.toLocaleString() })
1603
+ item.value && /* @__PURE__ */ jsx17("span", { className: "text-[var(--timberwolf)] font-mono font-medium tabular-nums", children: item.value.toLocaleString() })
1063
1604
  ]
1064
1605
  }
1065
1606
  )
@@ -1084,7 +1625,7 @@ function ChartLegendContent({
1084
1625
  if (!payload?.length) {
1085
1626
  return null;
1086
1627
  }
1087
- return /* @__PURE__ */ jsx12(
1628
+ return /* @__PURE__ */ jsx17(
1088
1629
  "div",
1089
1630
  {
1090
1631
  className: cn(
@@ -1095,14 +1636,14 @@ function ChartLegendContent({
1095
1636
  children: payload.filter((item) => item.type !== "none").map((item) => {
1096
1637
  const key = `${nameKey || item.dataKey || "value"}`;
1097
1638
  const itemConfig = getPayloadConfigFromPayload(config, item, key);
1098
- return /* @__PURE__ */ jsxs8(
1639
+ return /* @__PURE__ */ jsxs11(
1099
1640
  "div",
1100
1641
  {
1101
1642
  className: cn(
1102
1643
  "flex items-center gap-1.5 text-[var(--ash-grey)]"
1103
1644
  ),
1104
1645
  children: [
1105
- itemConfig?.icon && !hideIcon ? /* @__PURE__ */ jsx12(itemConfig.icon, {}) : /* @__PURE__ */ jsx12(
1646
+ itemConfig?.icon && !hideIcon ? /* @__PURE__ */ jsx17(itemConfig.icon, {}) : /* @__PURE__ */ jsx17(
1106
1647
  "div",
1107
1648
  {
1108
1649
  className: "h-2 w-2 shrink-0 rounded-[2px]",
@@ -1133,10 +1674,58 @@ function getPayloadConfigFromPayload(config, payload, key) {
1133
1674
  }
1134
1675
  return configLabelKey in config ? config[configLabelKey] : config[key];
1135
1676
  }
1677
+
1678
+ // src/ui/footer.tsx
1679
+ import { InstagramIcon, YoutubeIcon, LinkedinIcon } from "lucide-react";
1680
+ import Link2 from "next/link";
1681
+ import { jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
1682
+ function TikTokIcon({ className }) {
1683
+ return /* @__PURE__ */ jsx18(
1684
+ "svg",
1685
+ {
1686
+ xmlns: "http://www.w3.org/2000/svg",
1687
+ viewBox: "0 0 24 24",
1688
+ fill: "none",
1689
+ stroke: "currentColor",
1690
+ strokeWidth: 2,
1691
+ strokeLinecap: "round",
1692
+ strokeLinejoin: "round",
1693
+ className,
1694
+ children: /* @__PURE__ */ jsx18("path", { d: "M9 12a4 4 0 1 0 4 4V4a5 5 0 0 0 5 5" })
1695
+ }
1696
+ );
1697
+ }
1698
+ function Footer() {
1699
+ return /* @__PURE__ */ jsxs12("footer", { className: "container mx-auto flex p-5 items-center justify-between border-t border-[var(--timberwolf)]", children: [
1700
+ /* @__PURE__ */ jsxs12("div", { className: "flex gap-4", children: [
1701
+ /* @__PURE__ */ jsx18(Link2, { href: "https://www.instagram.com/playback_global", target: "_blank", children: /* @__PURE__ */ jsx18(InstagramIcon, { className: "h-7 w-7" }) }),
1702
+ /* @__PURE__ */ jsx18(Link2, { href: "https://youtube.com/@playback_global", target: "_blank", children: /* @__PURE__ */ jsx18(YoutubeIcon, { className: "h-7 w-7" }) }),
1703
+ /* @__PURE__ */ jsx18(Link2, { href: "https://www.tiktok.com/@playback_global", target: "_blank", children: /* @__PURE__ */ jsx18(TikTokIcon, { className: "h-7 w-7" }) }),
1704
+ /* @__PURE__ */ jsx18(
1705
+ Link2,
1706
+ {
1707
+ href: "https://www.linkedin.com/company/playbacksports/",
1708
+ target: "_blank",
1709
+ children: /* @__PURE__ */ jsx18(LinkedinIcon, { className: "h-7 w-7" })
1710
+ }
1711
+ )
1712
+ ] }),
1713
+ /* @__PURE__ */ jsxs12("h2", { className: "text-lg", children: [
1714
+ "by",
1715
+ " ",
1716
+ /* @__PURE__ */ jsx18(Link2, { href: "https://www.braintwopoint0.com", children: /* @__PURE__ */ jsxs12("span", { className: "font-semibold", children: [
1717
+ "BRAIN",
1718
+ /* @__PURE__ */ jsx18("span", { className: "font-thin", children: "2.0" })
1719
+ ] }) })
1720
+ ] })
1721
+ ] });
1722
+ }
1136
1723
  export {
1137
1724
  AnimatedTooltip,
1138
1725
  Badge,
1139
1726
  Button,
1727
+ Calendar,
1728
+ CalendarDayButton,
1140
1729
  Card,
1141
1730
  CardContent,
1142
1731
  CardDescription,
@@ -1149,6 +1738,8 @@ export {
1149
1738
  ChartStyle,
1150
1739
  ChartTooltip,
1151
1740
  ChartTooltipContent,
1741
+ DatePicker,
1742
+ DateTimePicker,
1152
1743
  Dialog,
1153
1744
  DialogClose,
1154
1745
  DialogContent,
@@ -1160,6 +1751,7 @@ export {
1160
1751
  DialogTitle,
1161
1752
  DialogTrigger,
1162
1753
  FlipWords,
1754
+ Footer,
1163
1755
  HeroHighlight,
1164
1756
  Highlight,
1165
1757
  HoverCard,
@@ -1168,6 +1760,10 @@ export {
1168
1760
  HoverEffect,
1169
1761
  Input,
1170
1762
  Label,
1763
+ Popover,
1764
+ PopoverAnchor,
1765
+ PopoverContent,
1766
+ PopoverTrigger,
1171
1767
  Select,
1172
1768
  SelectContent,
1173
1769
  SelectGroup,
@@ -1178,6 +1774,7 @@ export {
1178
1774
  SelectSeparator,
1179
1775
  SelectTrigger,
1180
1776
  SelectValue,
1777
+ TimePicker,
1181
1778
  badgeVariants,
1182
1779
  buttonVariants
1183
1780
  };