@webdevarif/dashui 0.5.0 → 0.6.0
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/index.d.mts +58 -59
- package/dist/index.d.ts +58 -59
- package/dist/index.js +254 -482
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +211 -439
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -98,8 +98,6 @@ __export(index_exports, {
|
|
|
98
98
|
LoadingSpinner: () => LoadingSpinner,
|
|
99
99
|
LocalInput: () => LocalInput,
|
|
100
100
|
MediaCard: () => MediaCard,
|
|
101
|
-
MediaGrid: () => MediaGrid,
|
|
102
|
-
MediaPickerDialog: () => MediaPickerDialog,
|
|
103
101
|
NotificationBell: () => NotificationBell,
|
|
104
102
|
Page: () => Page,
|
|
105
103
|
PageSection: () => PageSection,
|
|
@@ -145,6 +143,8 @@ __export(index_exports, {
|
|
|
145
143
|
TooltipProvider: () => TooltipProvider,
|
|
146
144
|
TooltipTrigger: () => TooltipTrigger,
|
|
147
145
|
TopBar: () => TopBar,
|
|
146
|
+
UploadProgressPanel: () => UploadProgressPanel,
|
|
147
|
+
UploadZone: () => UploadZone,
|
|
148
148
|
badgeVariants: () => badgeVariants,
|
|
149
149
|
buttonVariants: () => buttonVariants,
|
|
150
150
|
cn: () => cn,
|
|
@@ -1909,436 +1909,150 @@ function StorageBar({
|
|
|
1909
1909
|
] });
|
|
1910
1910
|
}
|
|
1911
1911
|
|
|
1912
|
-
// src/components/media/
|
|
1912
|
+
// src/components/media/upload-zone.tsx
|
|
1913
|
+
var import_react = require("react");
|
|
1914
|
+
var import_lucide_react10 = require("lucide-react");
|
|
1913
1915
|
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1916
|
+
var CloudUploadIcon = import_lucide_react10.Cloud;
|
|
1917
|
+
function UploadZone({
|
|
1918
|
+
onFiles,
|
|
1919
|
+
accept = "*",
|
|
1920
|
+
multiple = true,
|
|
1921
|
+
disabled = false
|
|
1922
|
+
}) {
|
|
1923
|
+
const [dragActive, setDragActive] = (0, import_react.useState)(false);
|
|
1924
|
+
const inputRef = (0, import_react.useRef)(null);
|
|
1925
|
+
const handleDrag = (e) => {
|
|
1926
|
+
e.preventDefault();
|
|
1927
|
+
e.stopPropagation();
|
|
1928
|
+
if (!disabled) {
|
|
1929
|
+
setDragActive(e.type === "dragenter" || e.type === "dragover");
|
|
1930
|
+
}
|
|
1931
|
+
};
|
|
1932
|
+
const handleDrop = (e) => {
|
|
1933
|
+
e.preventDefault();
|
|
1934
|
+
e.stopPropagation();
|
|
1935
|
+
setDragActive(false);
|
|
1936
|
+
if (!disabled && e.dataTransfer.files?.length) {
|
|
1937
|
+
onFiles(Array.from(e.dataTransfer.files));
|
|
1938
|
+
}
|
|
1939
|
+
};
|
|
1940
|
+
const handleChange = (e) => {
|
|
1941
|
+
if (e.target.files?.length) {
|
|
1942
|
+
onFiles(Array.from(e.target.files));
|
|
1943
|
+
}
|
|
1944
|
+
};
|
|
1926
1945
|
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
|
|
1927
1946
|
"div",
|
|
1928
1947
|
{
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
className: cn(
|
|
1936
|
-
"group relative aspect-square cursor-pointer rounded-xl overflow-hidden border-2 transition-all duration-150",
|
|
1937
|
-
selected ? "border-[color:var(--primary)] shadow-[0_0_0_2px_rgba(40,127,113,0.2)]" : "border-transparent hover:border-[color:var(--primary)]/40",
|
|
1938
|
-
className
|
|
1939
|
-
),
|
|
1948
|
+
className: `relative rounded-lg border-2 border-dashed p-8 text-center transition-colors ${dragActive ? "border-blue-500 bg-blue-50/50" : "border-gray-300 bg-gray-50/50 hover:border-gray-400"} ${disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"}`,
|
|
1949
|
+
onDragEnter: handleDrag,
|
|
1950
|
+
onDragLeave: handleDrag,
|
|
1951
|
+
onDragOver: handleDrag,
|
|
1952
|
+
onDrop: handleDrop,
|
|
1953
|
+
onClick: () => !disabled && inputRef.current?.click(),
|
|
1940
1954
|
children: [
|
|
1941
|
-
|
|
1942
|
-
"
|
|
1955
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
1956
|
+
"input",
|
|
1943
1957
|
{
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1958
|
+
ref: inputRef,
|
|
1959
|
+
type: "file",
|
|
1960
|
+
accept,
|
|
1961
|
+
multiple,
|
|
1962
|
+
onChange: handleChange,
|
|
1963
|
+
disabled,
|
|
1964
|
+
className: "hidden"
|
|
1948
1965
|
}
|
|
1949
|
-
)
|
|
1950
|
-
/* @__PURE__ */ (0, import_jsx_runtime32.
|
|
1951
|
-
|
|
1952
|
-
"
|
|
1953
|
-
|
|
1954
|
-
className: "
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
fill: "none",
|
|
1958
|
-
stroke: "currentColor",
|
|
1959
|
-
strokeWidth: "3",
|
|
1960
|
-
strokeLinecap: "round",
|
|
1961
|
-
strokeLinejoin: "round",
|
|
1962
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("polyline", { points: "20 6 9 17 4 12" })
|
|
1963
|
-
}
|
|
1964
|
-
) })
|
|
1966
|
+
),
|
|
1967
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-col items-center gap-2", children: [
|
|
1968
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(CloudUploadIcon, { className: "w-8 h-8 text-gray-400" }),
|
|
1969
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { children: [
|
|
1970
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { className: "text-sm font-medium text-gray-700", children: dragActive ? "Drop files here" : "Drag & drop files, or click to browse" }),
|
|
1971
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { className: "text-xs text-gray-500 mt-1", children: "Max file size: 100MB" })
|
|
1972
|
+
] })
|
|
1973
|
+
] })
|
|
1965
1974
|
]
|
|
1966
1975
|
}
|
|
1967
1976
|
);
|
|
1968
1977
|
}
|
|
1969
1978
|
|
|
1970
|
-
// src/components/media/
|
|
1979
|
+
// src/components/media/upload-progress-panel.tsx
|
|
1980
|
+
var import_lucide_react11 = require("lucide-react");
|
|
1971
1981
|
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
1972
|
-
var
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
selected,
|
|
1980
|
-
onSelect,
|
|
1981
|
-
loading = false,
|
|
1982
|
-
columns = 5,
|
|
1983
|
-
emptyMessage = "No files yet.",
|
|
1984
|
-
onUploadClick,
|
|
1985
|
-
className
|
|
1982
|
+
var CheckmarkCircle01Icon = import_lucide_react11.CheckCircle;
|
|
1983
|
+
var Cancel01Icon = import_lucide_react11.X;
|
|
1984
|
+
function UploadProgressPanel({
|
|
1985
|
+
items,
|
|
1986
|
+
onRetry,
|
|
1987
|
+
onCancel,
|
|
1988
|
+
onCancelAll
|
|
1986
1989
|
}) {
|
|
1987
|
-
if (
|
|
1988
|
-
|
|
1990
|
+
if (items.length === 0) return null;
|
|
1991
|
+
const activeCount = items.filter((it) => it.status === "uploading").length;
|
|
1992
|
+
const doneCount = items.filter((it) => it.status === "done").length;
|
|
1993
|
+
const failedCount = items.filter((it) => it.status === "failed").length;
|
|
1994
|
+
const avgProgress = items.length > 0 ? Math.round(items.reduce((s, it) => s + it.progress, 0) / items.length) : 0;
|
|
1995
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "rounded-lg border border-gray-200 bg-white p-4 shadow-sm", children: [
|
|
1996
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [
|
|
1997
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("h3", { className: "text-sm font-semibold text-gray-900", children: activeCount > 0 ? `Uploading ${activeCount} file${activeCount > 1 ? "s" : ""}` : "Upload complete" }),
|
|
1998
|
+
onCancelAll && items.some((it) => it.status === "uploading" || it.status === "pending") && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
1999
|
+
"button",
|
|
2000
|
+
{
|
|
2001
|
+
onClick: onCancelAll,
|
|
2002
|
+
className: "text-xs text-red-600 hover:text-red-700 font-medium",
|
|
2003
|
+
children: "Cancel all"
|
|
2004
|
+
}
|
|
2005
|
+
)
|
|
2006
|
+
] }),
|
|
2007
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "w-full h-2 bg-gray-200 rounded-full overflow-hidden mb-4", children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
1989
2008
|
"div",
|
|
1990
2009
|
{
|
|
1991
|
-
className: "
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
)
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2010
|
+
className: "h-full bg-blue-500 transition-all duration-300",
|
|
2011
|
+
style: { width: `${avgProgress}%` }
|
|
2012
|
+
}
|
|
2013
|
+
) }),
|
|
2014
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("p", { className: "text-xs text-gray-600 mb-4", children: [
|
|
2015
|
+
doneCount,
|
|
2016
|
+
" done",
|
|
2017
|
+
failedCount > 0 && ` \xB7 ${failedCount} failed`,
|
|
2018
|
+
activeCount > 0 && ` \xB7 ${activeCount} uploading`
|
|
2019
|
+
] }),
|
|
2020
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "space-y-2 max-h-48 overflow-y-auto", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex items-center gap-3 p-2 rounded-md bg-gray-50 hover:bg-gray-100 transition-colors", children: [
|
|
2021
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "shrink-0", children: [
|
|
2022
|
+
item.status === "done" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CheckmarkCircle01Icon, { className: "w-4 h-4 text-green-600" }),
|
|
2023
|
+
item.status === "failed" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Cancel01Icon, { className: "w-4 h-4 text-red-600" }),
|
|
2024
|
+
(item.status === "uploading" || item.status === "pending") && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "w-4 h-4 rounded-full border-2 border-blue-300 border-t-blue-600 animate-spin" })
|
|
2025
|
+
] }),
|
|
2026
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex-1 min-w-0", children: [
|
|
2027
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { className: "text-xs font-medium text-gray-900 truncate", children: item.name }),
|
|
2028
|
+
item.error && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { className: "text-xs text-red-600", children: item.error }),
|
|
2029
|
+
item.status === "uploading" && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("p", { className: "text-xs text-gray-500", children: [
|
|
2030
|
+
item.progress,
|
|
2031
|
+
"%"
|
|
2032
|
+
] })
|
|
2033
|
+
] }),
|
|
2034
|
+
item.status === "failed" && onRetry && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
2035
|
+
"button",
|
|
2000
2036
|
{
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
fill: "none",
|
|
2005
|
-
stroke: "currentColor",
|
|
2006
|
-
strokeWidth: "1.5",
|
|
2007
|
-
strokeLinecap: "round",
|
|
2008
|
-
strokeLinejoin: "round",
|
|
2009
|
-
children: [
|
|
2010
|
-
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2" }),
|
|
2011
|
-
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("circle", { cx: "9", cy: "9", r: "2" }),
|
|
2012
|
-
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" })
|
|
2013
|
-
]
|
|
2037
|
+
onClick: () => onRetry(item.id),
|
|
2038
|
+
className: "text-xs text-blue-600 hover:text-blue-700 font-medium shrink-0",
|
|
2039
|
+
children: "Retry"
|
|
2014
2040
|
}
|
|
2015
|
-
)
|
|
2016
|
-
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
2017
|
-
onUploadClick && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
2041
|
+
),
|
|
2042
|
+
(item.status === "uploading" || item.status === "pending") && onCancel && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
2018
2043
|
"button",
|
|
2019
2044
|
{
|
|
2020
|
-
onClick:
|
|
2021
|
-
className: "
|
|
2022
|
-
children: "
|
|
2045
|
+
onClick: () => onCancel(item.id),
|
|
2046
|
+
className: "text-xs text-gray-600 hover:text-gray-700 shrink-0",
|
|
2047
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Cancel01Icon, { className: "w-4 h-4" })
|
|
2023
2048
|
}
|
|
2024
2049
|
)
|
|
2025
|
-
] })
|
|
2026
|
-
}
|
|
2027
|
-
return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: cn("grid gap-2", columnsClass[columns] ?? columnsClass[5], className), children: files.map((file) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
2028
|
-
MediaCard,
|
|
2029
|
-
{
|
|
2030
|
-
file,
|
|
2031
|
-
selected: selected?.has(file.id),
|
|
2032
|
-
onClick: () => onSelect?.(file)
|
|
2033
|
-
},
|
|
2034
|
-
file.id
|
|
2035
|
-
)) });
|
|
2036
|
-
}
|
|
2037
|
-
|
|
2038
|
-
// src/components/media/media-picker-dialog.tsx
|
|
2039
|
-
var React20 = __toESM(require("react"));
|
|
2040
|
-
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
2041
|
-
var ALL_TYPE_OPTIONS = [
|
|
2042
|
-
{ value: "all", label: "All" },
|
|
2043
|
-
{ value: "images", label: "Images" },
|
|
2044
|
-
{ value: "videos", label: "Videos" },
|
|
2045
|
-
{ value: "documents", label: "Docs" }
|
|
2046
|
-
];
|
|
2047
|
-
function MediaPickerDialog({
|
|
2048
|
-
open,
|
|
2049
|
-
onOpenChange,
|
|
2050
|
-
title = "Media Library",
|
|
2051
|
-
files,
|
|
2052
|
-
folders = [],
|
|
2053
|
-
loading = false,
|
|
2054
|
-
total,
|
|
2055
|
-
typeFilter = "all",
|
|
2056
|
-
onTypeChange,
|
|
2057
|
-
search = "",
|
|
2058
|
-
onSearch,
|
|
2059
|
-
activeFolderId,
|
|
2060
|
-
onFolderChange,
|
|
2061
|
-
onUpload,
|
|
2062
|
-
onLoadMore,
|
|
2063
|
-
hasMore = false,
|
|
2064
|
-
multiple = false,
|
|
2065
|
-
initialSelected = [],
|
|
2066
|
-
accept = "all",
|
|
2067
|
-
onSelect
|
|
2068
|
-
}) {
|
|
2069
|
-
const [localSelected, setLocalSelected] = React20.useState(new Set(initialSelected));
|
|
2070
|
-
const [isDragging, setIsDragging] = React20.useState(false);
|
|
2071
|
-
const fileInputRef = React20.useRef(null);
|
|
2072
|
-
const dragCounterRef = React20.useRef(0);
|
|
2073
|
-
React20.useEffect(() => {
|
|
2074
|
-
if (!open) {
|
|
2075
|
-
setLocalSelected(/* @__PURE__ */ new Set());
|
|
2076
|
-
setIsDragging(false);
|
|
2077
|
-
dragCounterRef.current = 0;
|
|
2078
|
-
}
|
|
2079
|
-
}, [open]);
|
|
2080
|
-
const prevInitialRef = React20.useRef("");
|
|
2081
|
-
React20.useEffect(() => {
|
|
2082
|
-
if (!open) return;
|
|
2083
|
-
const key = initialSelected.join(",");
|
|
2084
|
-
if (key === prevInitialRef.current) return;
|
|
2085
|
-
prevInitialRef.current = key;
|
|
2086
|
-
if (initialSelected.length > 0) {
|
|
2087
|
-
setLocalSelected(new Set(initialSelected));
|
|
2088
|
-
}
|
|
2089
|
-
}, [open, initialSelected]);
|
|
2090
|
-
const handleDragEnter = (e) => {
|
|
2091
|
-
e.preventDefault();
|
|
2092
|
-
e.stopPropagation();
|
|
2093
|
-
if (e.dataTransfer.types.includes("Files")) {
|
|
2094
|
-
dragCounterRef.current++;
|
|
2095
|
-
setIsDragging(true);
|
|
2096
|
-
}
|
|
2097
|
-
};
|
|
2098
|
-
const handleDragLeave = (e) => {
|
|
2099
|
-
e.preventDefault();
|
|
2100
|
-
e.stopPropagation();
|
|
2101
|
-
dragCounterRef.current--;
|
|
2102
|
-
if (dragCounterRef.current <= 0) {
|
|
2103
|
-
dragCounterRef.current = 0;
|
|
2104
|
-
setIsDragging(false);
|
|
2105
|
-
}
|
|
2106
|
-
};
|
|
2107
|
-
const handleDragOver = (e) => {
|
|
2108
|
-
e.preventDefault();
|
|
2109
|
-
e.stopPropagation();
|
|
2110
|
-
};
|
|
2111
|
-
const handleDrop = (e) => {
|
|
2112
|
-
e.preventDefault();
|
|
2113
|
-
e.stopPropagation();
|
|
2114
|
-
dragCounterRef.current = 0;
|
|
2115
|
-
setIsDragging(false);
|
|
2116
|
-
if (!onUpload || !e.dataTransfer.files.length) return;
|
|
2117
|
-
const accepted = accept === "images" ? Array.from(e.dataTransfer.files).filter((f) => f.type.startsWith("image/")) : Array.from(e.dataTransfer.files);
|
|
2118
|
-
if (!accepted.length) return;
|
|
2119
|
-
const dt = new DataTransfer();
|
|
2120
|
-
accepted.forEach((f) => dt.items.add(f));
|
|
2121
|
-
onUpload(dt.files);
|
|
2122
|
-
};
|
|
2123
|
-
const typeOptions = ALL_TYPE_OPTIONS.filter(
|
|
2124
|
-
(o) => accept === "images" ? o.value === "all" || o.value === "images" : true
|
|
2125
|
-
);
|
|
2126
|
-
const handleFileSelect = (file) => {
|
|
2127
|
-
setLocalSelected((prev) => {
|
|
2128
|
-
if (multiple) {
|
|
2129
|
-
const next = new Set(prev);
|
|
2130
|
-
next.has(file.id) ? next.delete(file.id) : next.add(file.id);
|
|
2131
|
-
return next;
|
|
2132
|
-
}
|
|
2133
|
-
return prev.has(file.id) ? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set([file.id]);
|
|
2134
|
-
});
|
|
2135
|
-
};
|
|
2136
|
-
const handleConfirm = () => {
|
|
2137
|
-
const selected = files.filter((f) => localSelected.has(f.id));
|
|
2138
|
-
onSelect(selected);
|
|
2139
|
-
onOpenChange(false);
|
|
2140
|
-
};
|
|
2141
|
-
const handleUploadChange = (e) => {
|
|
2142
|
-
if (e.target.files && onUpload) {
|
|
2143
|
-
onUpload(e.target.files);
|
|
2144
|
-
}
|
|
2145
|
-
};
|
|
2146
|
-
const firstSelected = files.find((f) => localSelected.has(f.id));
|
|
2147
|
-
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Dialog, { open, onOpenChange, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
2148
|
-
DialogContent,
|
|
2149
|
-
{
|
|
2150
|
-
"aria-describedby": void 0,
|
|
2151
|
-
className: "flex h-[85vh] max-h-[700px] max-w-4xl flex-col gap-0 p-0",
|
|
2152
|
-
children: [
|
|
2153
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(DialogHeader, { className: "flex-row items-center gap-3 border-b px-5 py-3 pr-12 space-y-0 shrink-0", children: [
|
|
2154
|
-
onUpload && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
|
|
2155
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2156
|
-
"input",
|
|
2157
|
-
{
|
|
2158
|
-
ref: fileInputRef,
|
|
2159
|
-
type: "file",
|
|
2160
|
-
className: "hidden",
|
|
2161
|
-
multiple: true,
|
|
2162
|
-
accept: accept === "images" ? "image/*" : void 0,
|
|
2163
|
-
onChange: handleUploadChange
|
|
2164
|
-
}
|
|
2165
|
-
),
|
|
2166
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
2167
|
-
"button",
|
|
2168
|
-
{
|
|
2169
|
-
onClick: () => fileInputRef.current?.click(),
|
|
2170
|
-
className: "flex shrink-0 items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground transition-opacity hover:opacity-90",
|
|
2171
|
-
children: [
|
|
2172
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("svg", { className: "h-3.5 w-3.5", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2173
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
|
|
2174
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("polyline", { points: "17 8 12 3 7 8" }),
|
|
2175
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
|
|
2176
|
-
] }),
|
|
2177
|
-
"Upload"
|
|
2178
|
-
]
|
|
2179
|
-
}
|
|
2180
|
-
)
|
|
2181
|
-
] }),
|
|
2182
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(DialogTitle, { className: "text-sm font-semibold flex-1", children: title }),
|
|
2183
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "text-xs text-muted-foreground shrink-0", children: [
|
|
2184
|
-
total,
|
|
2185
|
-
" files"
|
|
2186
|
-
] })
|
|
2187
|
-
] }),
|
|
2188
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex flex-1 overflow-hidden min-h-0", children: [
|
|
2189
|
-
folders.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("aside", { className: "flex w-44 shrink-0 flex-col gap-0.5 overflow-y-auto border-r p-2", children: [
|
|
2190
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
2191
|
-
"button",
|
|
2192
|
-
{
|
|
2193
|
-
onClick: () => onFolderChange?.(""),
|
|
2194
|
-
className: cn(
|
|
2195
|
-
"flex w-full items-center gap-2 rounded-md px-2.5 py-1.5 text-sm transition-colors",
|
|
2196
|
-
!activeFolderId ? "bg-primary/10 font-medium text-primary" : "text-muted-foreground hover:bg-accent"
|
|
2197
|
-
),
|
|
2198
|
-
children: [
|
|
2199
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("svg", { className: "h-3.5 w-3.5 shrink-0", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("path", { d: "M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z" }) }),
|
|
2200
|
-
"All files"
|
|
2201
|
-
]
|
|
2202
|
-
}
|
|
2203
|
-
),
|
|
2204
|
-
folders.map((folder) => /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
2205
|
-
"button",
|
|
2206
|
-
{
|
|
2207
|
-
onClick: () => onFolderChange?.(folder.id),
|
|
2208
|
-
className: cn(
|
|
2209
|
-
"flex w-full items-center gap-2 rounded-md px-2.5 py-1.5 text-sm transition-colors",
|
|
2210
|
-
activeFolderId === folder.id ? "bg-primary/10 font-medium text-primary" : "text-muted-foreground hover:bg-accent"
|
|
2211
|
-
),
|
|
2212
|
-
children: [
|
|
2213
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "text-base leading-none", children: folder.icon ?? "\u{1F4C1}" }),
|
|
2214
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "truncate", children: folder.name })
|
|
2215
|
-
]
|
|
2216
|
-
},
|
|
2217
|
-
folder.id
|
|
2218
|
-
))
|
|
2219
|
-
] }),
|
|
2220
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex flex-1 flex-col overflow-hidden min-w-0", children: [
|
|
2221
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex items-center gap-2 border-b px-4 py-2 shrink-0", children: [
|
|
2222
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "flex items-center gap-0.5 rounded-lg border border-input bg-muted/50 p-0.5", children: typeOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2223
|
-
"button",
|
|
2224
|
-
{
|
|
2225
|
-
onClick: () => onTypeChange?.(opt.value),
|
|
2226
|
-
className: cn(
|
|
2227
|
-
"rounded-md px-2.5 py-1 text-xs font-medium transition-colors",
|
|
2228
|
-
typeFilter === opt.value ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
|
|
2229
|
-
),
|
|
2230
|
-
children: opt.label
|
|
2231
|
-
},
|
|
2232
|
-
opt.value
|
|
2233
|
-
)) }),
|
|
2234
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "relative flex-1 max-w-xs ml-auto", children: [
|
|
2235
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("svg", { className: "pointer-events-none absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2236
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("circle", { cx: "11", cy: "11", r: "8" }),
|
|
2237
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("path", { d: "m21 21-4.35-4.35" })
|
|
2238
|
-
] }),
|
|
2239
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2240
|
-
"input",
|
|
2241
|
-
{
|
|
2242
|
-
type: "search",
|
|
2243
|
-
value: search,
|
|
2244
|
-
onChange: (e) => onSearch?.(e.target.value),
|
|
2245
|
-
placeholder: "Search\u2026",
|
|
2246
|
-
className: "h-8 w-full rounded-lg border border-input bg-background pl-8 pr-3 text-xs outline-none focus:border-primary focus:ring-1 focus:ring-primary/30"
|
|
2247
|
-
}
|
|
2248
|
-
)
|
|
2249
|
-
] })
|
|
2250
|
-
] }),
|
|
2251
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
2252
|
-
"div",
|
|
2253
|
-
{
|
|
2254
|
-
className: "relative flex-1 overflow-y-auto p-4",
|
|
2255
|
-
onDragEnter: handleDragEnter,
|
|
2256
|
-
onDragLeave: handleDragLeave,
|
|
2257
|
-
onDragOver: handleDragOver,
|
|
2258
|
-
onDrop: handleDrop,
|
|
2259
|
-
children: [
|
|
2260
|
-
isDragging && onUpload && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "pointer-events-none absolute inset-0 z-10 flex flex-col items-center justify-center gap-3 rounded-lg border-2 border-dashed border-primary bg-primary/5 backdrop-blur-[1px]", children: [
|
|
2261
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("svg", { className: "h-10 w-10 text-primary opacity-70", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2262
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
|
|
2263
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("polyline", { points: "17 8 12 3 7 8" }),
|
|
2264
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
|
|
2265
|
-
] }),
|
|
2266
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("p", { className: "text-sm font-medium text-primary", children: [
|
|
2267
|
-
"Drop ",
|
|
2268
|
-
accept === "images" ? "images" : "files",
|
|
2269
|
-
" to upload"
|
|
2270
|
-
] })
|
|
2271
|
-
] }),
|
|
2272
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2273
|
-
MediaGrid,
|
|
2274
|
-
{
|
|
2275
|
-
files,
|
|
2276
|
-
selected: localSelected,
|
|
2277
|
-
onSelect: handleFileSelect,
|
|
2278
|
-
loading,
|
|
2279
|
-
columns: 5,
|
|
2280
|
-
onUploadClick: onUpload ? () => fileInputRef.current?.click() : void 0
|
|
2281
|
-
}
|
|
2282
|
-
),
|
|
2283
|
-
hasMore && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2284
|
-
"button",
|
|
2285
|
-
{
|
|
2286
|
-
onClick: onLoadMore,
|
|
2287
|
-
className: "rounded-lg border px-4 py-2 text-xs text-muted-foreground transition-colors hover:bg-accent",
|
|
2288
|
-
children: "Load more"
|
|
2289
|
-
}
|
|
2290
|
-
) })
|
|
2291
|
-
]
|
|
2292
|
-
}
|
|
2293
|
-
)
|
|
2294
|
-
] })
|
|
2295
|
-
] }),
|
|
2296
|
-
localSelected.size > 0 && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex items-center justify-between gap-4 border-t px-5 py-3 shrink-0 bg-muted/20", children: [
|
|
2297
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "text-sm text-muted-foreground", children: [
|
|
2298
|
-
localSelected.size,
|
|
2299
|
-
" file",
|
|
2300
|
-
localSelected.size !== 1 ? "s" : "",
|
|
2301
|
-
" selected"
|
|
2302
|
-
] }),
|
|
2303
|
-
firstSelected && firstSelected.mimeType.startsWith("image/") && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2304
|
-
"img",
|
|
2305
|
-
{
|
|
2306
|
-
src: firstSelected.url,
|
|
2307
|
-
alt: firstSelected.name,
|
|
2308
|
-
className: "h-9 w-9 rounded-lg border border-border object-cover shadow-sm"
|
|
2309
|
-
}
|
|
2310
|
-
),
|
|
2311
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
2312
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2313
|
-
"button",
|
|
2314
|
-
{
|
|
2315
|
-
onClick: () => setLocalSelected(/* @__PURE__ */ new Set()),
|
|
2316
|
-
className: "rounded-lg px-3 py-1.5 text-sm text-muted-foreground transition-colors hover:bg-accent",
|
|
2317
|
-
children: "Cancel"
|
|
2318
|
-
}
|
|
2319
|
-
),
|
|
2320
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
2321
|
-
"button",
|
|
2322
|
-
{
|
|
2323
|
-
onClick: handleConfirm,
|
|
2324
|
-
className: "rounded-lg bg-primary px-4 py-1.5 text-sm font-medium text-primary-foreground transition-opacity hover:opacity-90",
|
|
2325
|
-
children: [
|
|
2326
|
-
"Use ",
|
|
2327
|
-
localSelected.size,
|
|
2328
|
-
" file",
|
|
2329
|
-
localSelected.size !== 1 ? "s" : ""
|
|
2330
|
-
]
|
|
2331
|
-
}
|
|
2332
|
-
)
|
|
2333
|
-
] })
|
|
2334
|
-
] })
|
|
2335
|
-
]
|
|
2336
|
-
}
|
|
2337
|
-
) });
|
|
2050
|
+
] }, item.id)) })
|
|
2051
|
+
] });
|
|
2338
2052
|
}
|
|
2339
2053
|
|
|
2340
2054
|
// src/components/media/image-picker-field.tsx
|
|
2341
|
-
var
|
|
2055
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
2342
2056
|
var sizeMap = {
|
|
2343
2057
|
sm: { box: "h-12 w-12", icon: "h-4 w-4", text: "text-[9px]" },
|
|
2344
2058
|
md: { box: "h-20 w-20", icon: "h-5 w-5", text: "text-[10px]" },
|
|
@@ -2354,8 +2068,8 @@ function ImagePickerField({
|
|
|
2354
2068
|
className
|
|
2355
2069
|
}) {
|
|
2356
2070
|
const sz = sizeMap[size];
|
|
2357
|
-
return /* @__PURE__ */ (0,
|
|
2358
|
-
/* @__PURE__ */ (0,
|
|
2071
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: cn("relative inline-flex shrink-0", className), children: [
|
|
2072
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2359
2073
|
"button",
|
|
2360
2074
|
{
|
|
2361
2075
|
type: "button",
|
|
@@ -2365,15 +2079,15 @@ function ImagePickerField({
|
|
|
2365
2079
|
sz.box,
|
|
2366
2080
|
value ? "border-border overflow-hidden" : "border-border hover:border-[color:var(--primary)] hover:bg-primary/5"
|
|
2367
2081
|
),
|
|
2368
|
-
children: value ? /* @__PURE__ */ (0,
|
|
2082
|
+
children: value ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2369
2083
|
"img",
|
|
2370
2084
|
{
|
|
2371
2085
|
src: value,
|
|
2372
2086
|
alt: filename ?? "Selected image",
|
|
2373
2087
|
className: "h-full w-full rounded-md object-cover"
|
|
2374
2088
|
}
|
|
2375
|
-
) : /* @__PURE__ */ (0,
|
|
2376
|
-
/* @__PURE__ */ (0,
|
|
2089
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex flex-col items-center gap-1", children: [
|
|
2090
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
2377
2091
|
"svg",
|
|
2378
2092
|
{
|
|
2379
2093
|
className: cn(sz.icon, "text-muted-foreground transition-colors group-hover:text-primary"),
|
|
@@ -2385,17 +2099,17 @@ function ImagePickerField({
|
|
|
2385
2099
|
strokeLinecap: "round",
|
|
2386
2100
|
strokeLinejoin: "round",
|
|
2387
2101
|
children: [
|
|
2388
|
-
/* @__PURE__ */ (0,
|
|
2389
|
-
/* @__PURE__ */ (0,
|
|
2390
|
-
/* @__PURE__ */ (0,
|
|
2102
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2" }),
|
|
2103
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("circle", { cx: "9", cy: "9", r: "2" }),
|
|
2104
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" })
|
|
2391
2105
|
]
|
|
2392
2106
|
}
|
|
2393
2107
|
),
|
|
2394
|
-
size !== "sm" && /* @__PURE__ */ (0,
|
|
2108
|
+
size !== "sm" && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: cn(sz.text, "text-muted-foreground text-center leading-tight transition-colors group-hover:text-primary"), children: emptyLabel })
|
|
2395
2109
|
] })
|
|
2396
2110
|
}
|
|
2397
2111
|
),
|
|
2398
|
-
value && onRemove && /* @__PURE__ */ (0,
|
|
2112
|
+
value && onRemove && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2399
2113
|
"button",
|
|
2400
2114
|
{
|
|
2401
2115
|
type: "button",
|
|
@@ -2405,12 +2119,70 @@ function ImagePickerField({
|
|
|
2405
2119
|
},
|
|
2406
2120
|
className: "absolute -right-1.5 -top-1.5 flex h-5 w-5 items-center justify-center rounded-full bg-destructive text-destructive-foreground shadow-sm transition-opacity hover:opacity-90",
|
|
2407
2121
|
"aria-label": "Remove image",
|
|
2408
|
-
children: /* @__PURE__ */ (0,
|
|
2122
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("svg", { className: "h-2.5 w-2.5", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("path", { d: "M18 6 6 18M6 6l12 12" }) })
|
|
2409
2123
|
}
|
|
2410
2124
|
)
|
|
2411
2125
|
] });
|
|
2412
2126
|
}
|
|
2413
2127
|
|
|
2128
|
+
// src/components/media/media-card.tsx
|
|
2129
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
2130
|
+
function stripExtension(name) {
|
|
2131
|
+
return name.replace(/\.[^/.]+$/, "");
|
|
2132
|
+
}
|
|
2133
|
+
function getFileEmoji(mimeType) {
|
|
2134
|
+
if (mimeType.startsWith("video/")) return "\u{1F3AC}";
|
|
2135
|
+
if (mimeType.startsWith("audio/")) return "\u{1F3B5}";
|
|
2136
|
+
if (mimeType === "application/pdf") return "\u{1F4C4}";
|
|
2137
|
+
return "\u{1F4CE}";
|
|
2138
|
+
}
|
|
2139
|
+
function MediaCard({ file, selected = false, onClick, className }) {
|
|
2140
|
+
const isImage = file.mimeType.startsWith("image/");
|
|
2141
|
+
const displayName = stripExtension(file.name);
|
|
2142
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
|
|
2143
|
+
"div",
|
|
2144
|
+
{
|
|
2145
|
+
role: "button",
|
|
2146
|
+
tabIndex: 0,
|
|
2147
|
+
onClick,
|
|
2148
|
+
onKeyDown: (e) => {
|
|
2149
|
+
if (e.key === "Enter" || e.key === " ") onClick?.();
|
|
2150
|
+
},
|
|
2151
|
+
className: cn(
|
|
2152
|
+
"group relative aspect-square cursor-pointer rounded-xl overflow-hidden border-2 transition-all duration-150",
|
|
2153
|
+
selected ? "border-[color:var(--primary)] shadow-[0_0_0_2px_rgba(40,127,113,0.2)]" : "border-transparent hover:border-[color:var(--primary)]/40",
|
|
2154
|
+
className
|
|
2155
|
+
),
|
|
2156
|
+
children: [
|
|
2157
|
+
isImage ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
2158
|
+
"img",
|
|
2159
|
+
{
|
|
2160
|
+
src: file.url,
|
|
2161
|
+
alt: file.name,
|
|
2162
|
+
className: "h-full w-full object-cover transition-transform duration-150 group-hover:scale-[1.03]",
|
|
2163
|
+
loading: "lazy"
|
|
2164
|
+
}
|
|
2165
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "flex h-full w-full items-center justify-center bg-muted text-4xl", children: getFileEmoji(file.mimeType) }),
|
|
2166
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "absolute inset-0 flex items-end bg-gradient-to-t from-black/60 via-transparent to-transparent opacity-0 transition-opacity duration-150 group-hover:opacity-100", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "truncate px-2 pb-2 text-[11px] font-medium text-white", children: displayName }) }),
|
|
2167
|
+
selected && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "absolute right-1.5 top-1.5 flex h-5 w-5 items-center justify-center rounded-full bg-primary shadow", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
2168
|
+
"svg",
|
|
2169
|
+
{
|
|
2170
|
+
className: "h-3 w-3 text-white",
|
|
2171
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2172
|
+
viewBox: "0 0 24 24",
|
|
2173
|
+
fill: "none",
|
|
2174
|
+
stroke: "currentColor",
|
|
2175
|
+
strokeWidth: "3",
|
|
2176
|
+
strokeLinecap: "round",
|
|
2177
|
+
strokeLinejoin: "round",
|
|
2178
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("polyline", { points: "20 6 9 17 4 12" })
|
|
2179
|
+
}
|
|
2180
|
+
) })
|
|
2181
|
+
]
|
|
2182
|
+
}
|
|
2183
|
+
);
|
|
2184
|
+
}
|
|
2185
|
+
|
|
2414
2186
|
// src/components/form/form-field.tsx
|
|
2415
2187
|
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
2416
2188
|
function FormField({
|
|
@@ -2478,7 +2250,7 @@ function FormSection({
|
|
|
2478
2250
|
}
|
|
2479
2251
|
|
|
2480
2252
|
// src/components/form/local-input.tsx
|
|
2481
|
-
var
|
|
2253
|
+
var import_react2 = require("react");
|
|
2482
2254
|
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
2483
2255
|
function LocalInput({
|
|
2484
2256
|
value,
|
|
@@ -2486,11 +2258,11 @@ function LocalInput({
|
|
|
2486
2258
|
commitOnBlur,
|
|
2487
2259
|
...rest
|
|
2488
2260
|
}) {
|
|
2489
|
-
const [local, setLocal] = (0,
|
|
2490
|
-
const ref = (0,
|
|
2491
|
-
const onChangeRef = (0,
|
|
2261
|
+
const [local, setLocal] = (0, import_react2.useState)(String(value ?? ""));
|
|
2262
|
+
const ref = (0, import_react2.useRef)(null);
|
|
2263
|
+
const onChangeRef = (0, import_react2.useRef)(onChange);
|
|
2492
2264
|
onChangeRef.current = onChange;
|
|
2493
|
-
(0,
|
|
2265
|
+
(0, import_react2.useEffect)(() => {
|
|
2494
2266
|
if (document.activeElement !== ref.current) {
|
|
2495
2267
|
setLocal(String(value ?? ""));
|
|
2496
2268
|
}
|
|
@@ -2517,7 +2289,7 @@ function LocalInput({
|
|
|
2517
2289
|
}
|
|
2518
2290
|
|
|
2519
2291
|
// src/components/form/responsive-size-device-icon.tsx
|
|
2520
|
-
var
|
|
2292
|
+
var import_react3 = require("react");
|
|
2521
2293
|
|
|
2522
2294
|
// src/components/form/responsive-types.tsx
|
|
2523
2295
|
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
@@ -2552,7 +2324,7 @@ function ResponsiveSizeDeviceIcon({
|
|
|
2552
2324
|
activeDevice,
|
|
2553
2325
|
setActiveDevice
|
|
2554
2326
|
}) {
|
|
2555
|
-
const [open, setOpen] = (0,
|
|
2327
|
+
const [open, setOpen] = (0, import_react3.useState)(false);
|
|
2556
2328
|
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "relative", children: [
|
|
2557
2329
|
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
2558
2330
|
"button",
|
|
@@ -2602,7 +2374,7 @@ function ResponsiveSizeDeviceIcon({
|
|
|
2602
2374
|
}
|
|
2603
2375
|
|
|
2604
2376
|
// src/components/form/responsive-size-field.tsx
|
|
2605
|
-
var
|
|
2377
|
+
var import_react4 = require("react");
|
|
2606
2378
|
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
2607
2379
|
function ResponsiveSizeField({
|
|
2608
2380
|
value,
|
|
@@ -2613,7 +2385,7 @@ function ResponsiveSizeField({
|
|
|
2613
2385
|
onUnitChange,
|
|
2614
2386
|
onCustomChange
|
|
2615
2387
|
}) {
|
|
2616
|
-
const [unitOpen, setUnitOpen] = (0,
|
|
2388
|
+
const [unitOpen, setUnitOpen] = (0, import_react4.useState)(false);
|
|
2617
2389
|
const currentVal = value[activeDevice] ?? value.desktop ?? 0;
|
|
2618
2390
|
const isCustom = unit === "custom";
|
|
2619
2391
|
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "relative flex items-center border border-white/10 rounded-md bg-white/5 w-full", style: { height: 32 }, children: [
|
|
@@ -2696,23 +2468,23 @@ function ResponsiveSizeField({
|
|
|
2696
2468
|
}
|
|
2697
2469
|
|
|
2698
2470
|
// src/components/feedback/alert.tsx
|
|
2699
|
-
var
|
|
2471
|
+
var import_lucide_react12 = require("lucide-react");
|
|
2700
2472
|
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
2701
2473
|
var variantConfig = {
|
|
2702
2474
|
info: {
|
|
2703
|
-
icon:
|
|
2475
|
+
icon: import_lucide_react12.Info,
|
|
2704
2476
|
classes: "border-blue-200 bg-blue-50 text-blue-900 dark:border-blue-800 dark:bg-blue-950 dark:text-blue-100"
|
|
2705
2477
|
},
|
|
2706
2478
|
success: {
|
|
2707
|
-
icon:
|
|
2479
|
+
icon: import_lucide_react12.CheckCircle2,
|
|
2708
2480
|
classes: "border-green-200 bg-green-50 text-green-900 dark:border-green-800 dark:bg-green-950 dark:text-green-100"
|
|
2709
2481
|
},
|
|
2710
2482
|
warning: {
|
|
2711
|
-
icon:
|
|
2483
|
+
icon: import_lucide_react12.AlertTriangle,
|
|
2712
2484
|
classes: "border-yellow-200 bg-yellow-50 text-yellow-900 dark:border-yellow-800 dark:bg-yellow-950 dark:text-yellow-100"
|
|
2713
2485
|
},
|
|
2714
2486
|
error: {
|
|
2715
|
-
icon:
|
|
2487
|
+
icon: import_lucide_react12.AlertCircle,
|
|
2716
2488
|
classes: "border-red-200 bg-red-50 text-red-900 dark:border-red-800 dark:bg-red-950 dark:text-red-100"
|
|
2717
2489
|
}
|
|
2718
2490
|
};
|
|
@@ -2746,7 +2518,7 @@ function Alert({
|
|
|
2746
2518
|
{
|
|
2747
2519
|
onClick: onDismiss,
|
|
2748
2520
|
className: "absolute right-3 top-3 rounded-md p-1 opacity-70 hover:opacity-100",
|
|
2749
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
2521
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react12.X, { className: "h-4 w-4" })
|
|
2750
2522
|
}
|
|
2751
2523
|
)
|
|
2752
2524
|
]
|
|
@@ -2755,7 +2527,7 @@ function Alert({
|
|
|
2755
2527
|
}
|
|
2756
2528
|
|
|
2757
2529
|
// src/components/feedback/loading-spinner.tsx
|
|
2758
|
-
var
|
|
2530
|
+
var import_lucide_react13 = require("lucide-react");
|
|
2759
2531
|
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
2760
2532
|
var sizeMap2 = {
|
|
2761
2533
|
sm: "h-4 w-4",
|
|
@@ -2764,7 +2536,7 @@ var sizeMap2 = {
|
|
|
2764
2536
|
};
|
|
2765
2537
|
function LoadingSpinner({ size = "md", className }) {
|
|
2766
2538
|
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2767
|
-
|
|
2539
|
+
import_lucide_react13.Loader2,
|
|
2768
2540
|
{
|
|
2769
2541
|
className: cn("animate-spin text-muted-foreground", sizeMap2[size], className)
|
|
2770
2542
|
}
|
|
@@ -2875,7 +2647,7 @@ function PostStatusBadge({
|
|
|
2875
2647
|
}
|
|
2876
2648
|
|
|
2877
2649
|
// src/components/content/post-list-table.tsx
|
|
2878
|
-
var
|
|
2650
|
+
var React20 = __toESM(require("react"));
|
|
2879
2651
|
|
|
2880
2652
|
// src/components/Skeleton.tsx
|
|
2881
2653
|
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
@@ -2965,10 +2737,10 @@ function getInitials(name) {
|
|
|
2965
2737
|
return name.split(" ").slice(0, 2).map((w) => w[0]?.toUpperCase() ?? "").join("");
|
|
2966
2738
|
}
|
|
2967
2739
|
function RowActions({ post, onEdit, onDelete, onDuplicate, onStatusChange }) {
|
|
2968
|
-
const [open, setOpen] =
|
|
2969
|
-
const [statusOpen, setStatusOpen] =
|
|
2970
|
-
const ref =
|
|
2971
|
-
|
|
2740
|
+
const [open, setOpen] = React20.useState(false);
|
|
2741
|
+
const [statusOpen, setStatusOpen] = React20.useState(false);
|
|
2742
|
+
const ref = React20.useRef(null);
|
|
2743
|
+
React20.useEffect(() => {
|
|
2972
2744
|
if (!open) return;
|
|
2973
2745
|
function handleClick(e) {
|
|
2974
2746
|
if (ref.current && !ref.current.contains(e.target)) {
|
|
@@ -3480,7 +3252,7 @@ function SlugInput({
|
|
|
3480
3252
|
}
|
|
3481
3253
|
|
|
3482
3254
|
// src/components/content/post-sidebar-section.tsx
|
|
3483
|
-
var
|
|
3255
|
+
var React21 = __toESM(require("react"));
|
|
3484
3256
|
var import_jsx_runtime52 = require("react/jsx-runtime");
|
|
3485
3257
|
function IconChevronDown() {
|
|
3486
3258
|
return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
@@ -3504,7 +3276,7 @@ function PostSidebarSection({
|
|
|
3504
3276
|
defaultOpen = true,
|
|
3505
3277
|
className
|
|
3506
3278
|
}) {
|
|
3507
|
-
const [open, setOpen] =
|
|
3279
|
+
const [open, setOpen] = React21.useState(defaultOpen);
|
|
3508
3280
|
return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: cn("border-b border-border", className), children: [
|
|
3509
3281
|
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
|
|
3510
3282
|
"button",
|
|
@@ -3540,18 +3312,18 @@ function PostSidebarSection({
|
|
|
3540
3312
|
}
|
|
3541
3313
|
|
|
3542
3314
|
// src/components/ui/hsl-color-input.tsx
|
|
3543
|
-
var
|
|
3315
|
+
var import_react6 = require("react");
|
|
3544
3316
|
var import_color2 = __toESM(require("color"));
|
|
3545
3317
|
var Popover2 = __toESM(require("@radix-ui/react-popover"));
|
|
3546
3318
|
|
|
3547
3319
|
// src/components/ui/color-picker.tsx
|
|
3548
3320
|
var import_color = __toESM(require("color"));
|
|
3549
|
-
var
|
|
3321
|
+
var import_react5 = require("react");
|
|
3550
3322
|
var Slider = __toESM(require("@radix-ui/react-slider"));
|
|
3551
3323
|
var import_jsx_runtime53 = require("react/jsx-runtime");
|
|
3552
|
-
var ColorPickerContext = (0,
|
|
3324
|
+
var ColorPickerContext = (0, import_react5.createContext)(void 0);
|
|
3553
3325
|
var useColorPicker = () => {
|
|
3554
|
-
const ctx = (0,
|
|
3326
|
+
const ctx = (0, import_react5.useContext)(ColorPickerContext);
|
|
3555
3327
|
if (!ctx) throw new Error("useColorPicker must be used within ColorPicker");
|
|
3556
3328
|
return ctx;
|
|
3557
3329
|
};
|
|
@@ -3569,51 +3341,51 @@ var ColorPicker = ({
|
|
|
3569
3341
|
return (0, import_color.default)("#000000");
|
|
3570
3342
|
}
|
|
3571
3343
|
})();
|
|
3572
|
-
const [hue, setHueState] = (0,
|
|
3573
|
-
const [saturation, setSaturationState] = (0,
|
|
3574
|
-
const [lightness, setLightnessState] = (0,
|
|
3575
|
-
const [alpha, setAlphaState] = (0,
|
|
3576
|
-
const [mode, setMode] = (0,
|
|
3577
|
-
const notifyRef = (0,
|
|
3578
|
-
(0,
|
|
3344
|
+
const [hue, setHueState] = (0, import_react5.useState)(initial.hue());
|
|
3345
|
+
const [saturation, setSaturationState] = (0, import_react5.useState)(initial.saturationl());
|
|
3346
|
+
const [lightness, setLightnessState] = (0, import_react5.useState)(initial.lightness());
|
|
3347
|
+
const [alpha, setAlphaState] = (0, import_react5.useState)(initial.alpha() * 100);
|
|
3348
|
+
const [mode, setMode] = (0, import_react5.useState)("HEX");
|
|
3349
|
+
const notifyRef = (0, import_react5.useRef)(onChange);
|
|
3350
|
+
(0, import_react5.useEffect)(() => {
|
|
3579
3351
|
notifyRef.current = onChange;
|
|
3580
3352
|
}, [onChange]);
|
|
3581
|
-
const notify = (0,
|
|
3353
|
+
const notify = (0, import_react5.useCallback)((h, s, l, a) => {
|
|
3582
3354
|
notifyRef.current?.(import_color.default.hsl(h, s, l).alpha(a / 100).hexa());
|
|
3583
3355
|
}, []);
|
|
3584
|
-
const setHue = (0,
|
|
3356
|
+
const setHue = (0, import_react5.useCallback)((h) => {
|
|
3585
3357
|
setHueState(h);
|
|
3586
3358
|
notify(h, saturation, lightness, alpha);
|
|
3587
3359
|
}, [saturation, lightness, alpha, notify]);
|
|
3588
|
-
const setSaturation = (0,
|
|
3360
|
+
const setSaturation = (0, import_react5.useCallback)((s) => {
|
|
3589
3361
|
setSaturationState(s);
|
|
3590
3362
|
notify(hue, s, lightness, alpha);
|
|
3591
3363
|
}, [hue, lightness, alpha, notify]);
|
|
3592
|
-
const setLightness = (0,
|
|
3364
|
+
const setLightness = (0, import_react5.useCallback)((l) => {
|
|
3593
3365
|
setLightnessState(l);
|
|
3594
3366
|
notify(hue, saturation, l, alpha);
|
|
3595
3367
|
}, [hue, saturation, alpha, notify]);
|
|
3596
|
-
const setAlpha = (0,
|
|
3368
|
+
const setAlpha = (0, import_react5.useCallback)((a) => {
|
|
3597
3369
|
setAlphaState(a);
|
|
3598
3370
|
notify(hue, saturation, lightness, a);
|
|
3599
3371
|
}, [hue, saturation, lightness, notify]);
|
|
3600
3372
|
return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ColorPickerContext.Provider, { value: { hue, saturation, lightness, alpha, mode, setHue, setSaturation, setLightness, setAlpha, setMode }, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: cn("flex flex-col gap-3", className), ...props, children }) });
|
|
3601
3373
|
};
|
|
3602
|
-
var ColorPickerSelection = (0,
|
|
3603
|
-
const containerRef = (0,
|
|
3604
|
-
const [isDragging, setIsDragging] = (0,
|
|
3374
|
+
var ColorPickerSelection = (0, import_react5.memo)(({ className, ...props }) => {
|
|
3375
|
+
const containerRef = (0, import_react5.useRef)(null);
|
|
3376
|
+
const [isDragging, setIsDragging] = (0, import_react5.useState)(false);
|
|
3605
3377
|
const { hue, saturation, lightness, setSaturation, setLightness } = useColorPicker();
|
|
3606
|
-
const [posX, setPosX] = (0,
|
|
3607
|
-
const [posY, setPosY] = (0,
|
|
3378
|
+
const [posX, setPosX] = (0, import_react5.useState)(() => saturation / 100);
|
|
3379
|
+
const [posY, setPosY] = (0, import_react5.useState)(() => {
|
|
3608
3380
|
const x = saturation / 100;
|
|
3609
3381
|
const topL = x < 0.01 ? 100 : 50 + 50 * (1 - x);
|
|
3610
3382
|
return topL > 0 ? Math.max(0, Math.min(1, 1 - lightness / topL)) : 0;
|
|
3611
3383
|
});
|
|
3612
|
-
const bg = (0,
|
|
3384
|
+
const bg = (0, import_react5.useMemo)(
|
|
3613
3385
|
() => `linear-gradient(0deg,rgba(0,0,0,1),rgba(0,0,0,0)),linear-gradient(90deg,rgba(255,255,255,1),rgba(255,255,255,0)),hsl(${hue},100%,50%)`,
|
|
3614
3386
|
[hue]
|
|
3615
3387
|
);
|
|
3616
|
-
const handleMove = (0,
|
|
3388
|
+
const handleMove = (0, import_react5.useCallback)((e) => {
|
|
3617
3389
|
if (!isDragging || !containerRef.current) return;
|
|
3618
3390
|
const rect = containerRef.current.getBoundingClientRect();
|
|
3619
3391
|
const x = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
|
|
@@ -3623,7 +3395,7 @@ var ColorPickerSelection = (0, import_react4.memo)(({ className, ...props }) =>
|
|
|
3623
3395
|
setSaturation(x * 100);
|
|
3624
3396
|
setLightness((x < 0.01 ? 100 : 50 + 50 * (1 - x)) * (1 - y));
|
|
3625
3397
|
}, [isDragging, setSaturation, setLightness]);
|
|
3626
|
-
(0,
|
|
3398
|
+
(0, import_react5.useEffect)(() => {
|
|
3627
3399
|
if (!isDragging) return;
|
|
3628
3400
|
const up = () => setIsDragging(false);
|
|
3629
3401
|
window.addEventListener("pointermove", handleMove);
|
|
@@ -3732,8 +3504,8 @@ var ColorPickerOutput = ({ className, ...props }) => {
|
|
|
3732
3504
|
};
|
|
3733
3505
|
var ColorPickerFormat = ({ className, ...props }) => {
|
|
3734
3506
|
const { hue, saturation, lightness, alpha, mode, setHue, setSaturation, setLightness, setAlpha } = useColorPicker();
|
|
3735
|
-
const [focused, setFocused] = (0,
|
|
3736
|
-
const [localVal, setLocalVal] = (0,
|
|
3507
|
+
const [focused, setFocused] = (0, import_react5.useState)(false);
|
|
3508
|
+
const [localVal, setLocalVal] = (0, import_react5.useState)("");
|
|
3737
3509
|
const computedVal = (() => {
|
|
3738
3510
|
try {
|
|
3739
3511
|
const c = import_color.default.hsl(hue, saturation, lightness).alpha(alpha / 100);
|
|
@@ -3747,7 +3519,7 @@ var ColorPickerFormat = ({ className, ...props }) => {
|
|
|
3747
3519
|
}
|
|
3748
3520
|
return "";
|
|
3749
3521
|
})();
|
|
3750
|
-
(0,
|
|
3522
|
+
(0, import_react5.useEffect)(() => {
|
|
3751
3523
|
if (!focused) setLocalVal(computedVal);
|
|
3752
3524
|
}, [computedVal, focused]);
|
|
3753
3525
|
const tryApply = (raw) => {
|
|
@@ -3845,7 +3617,7 @@ function hexToHsl(hex) {
|
|
|
3845
3617
|
}
|
|
3846
3618
|
function ColorReader({ onHexChange }) {
|
|
3847
3619
|
const { hue, saturation, lightness, alpha } = useColorPicker();
|
|
3848
|
-
(0,
|
|
3620
|
+
(0, import_react6.useEffect)(() => {
|
|
3849
3621
|
try {
|
|
3850
3622
|
const hex = import_color2.default.hsl(hue, saturation, lightness).alpha(alpha / 100).hex();
|
|
3851
3623
|
onHexChange(hex);
|
|
@@ -3855,21 +3627,21 @@ function ColorReader({ onHexChange }) {
|
|
|
3855
3627
|
return null;
|
|
3856
3628
|
}
|
|
3857
3629
|
function HslColorInput({ value, onChange, className, inputClassName, disabled }) {
|
|
3858
|
-
const [open, setOpen] = (0,
|
|
3630
|
+
const [open, setOpen] = (0, import_react6.useState)(false);
|
|
3859
3631
|
const hexValue = hslToHex(value);
|
|
3860
3632
|
const cssColor = value ? `hsl(${value})` : "transparent";
|
|
3861
|
-
const pendingHexRef = (0,
|
|
3862
|
-
const onChangeRef = (0,
|
|
3863
|
-
(0,
|
|
3633
|
+
const pendingHexRef = (0, import_react6.useRef)(hexValue);
|
|
3634
|
+
const onChangeRef = (0, import_react6.useRef)(onChange);
|
|
3635
|
+
(0, import_react6.useEffect)(() => {
|
|
3864
3636
|
onChangeRef.current = onChange;
|
|
3865
3637
|
}, [onChange]);
|
|
3866
|
-
(0,
|
|
3638
|
+
(0, import_react6.useEffect)(() => {
|
|
3867
3639
|
if (open) pendingHexRef.current = hexValue;
|
|
3868
3640
|
}, [open, hexValue]);
|
|
3869
|
-
const handleHexChange = (0,
|
|
3641
|
+
const handleHexChange = (0, import_react6.useCallback)((hex) => {
|
|
3870
3642
|
pendingHexRef.current = hex;
|
|
3871
3643
|
}, []);
|
|
3872
|
-
const handleOpenChange = (0,
|
|
3644
|
+
const handleOpenChange = (0, import_react6.useCallback)((newOpen) => {
|
|
3873
3645
|
if (!newOpen && open) {
|
|
3874
3646
|
const pending = pendingHexRef.current;
|
|
3875
3647
|
if (pending && pending !== hexValue) {
|
|
@@ -3937,9 +3709,9 @@ function HslColorInput({ value, onChange, className, inputClassName, disabled })
|
|
|
3937
3709
|
}
|
|
3938
3710
|
|
|
3939
3711
|
// src/hooks/index.ts
|
|
3940
|
-
var
|
|
3712
|
+
var import_react7 = require("react");
|
|
3941
3713
|
function useDisclosure(initial = false) {
|
|
3942
|
-
const [isOpen, setIsOpen] = (0,
|
|
3714
|
+
const [isOpen, setIsOpen] = (0, import_react7.useState)(initial);
|
|
3943
3715
|
return {
|
|
3944
3716
|
isOpen,
|
|
3945
3717
|
open: () => setIsOpen(true),
|
|
@@ -3949,7 +3721,7 @@ function useDisclosure(initial = false) {
|
|
|
3949
3721
|
};
|
|
3950
3722
|
}
|
|
3951
3723
|
function usePagination(total, pageSize = 20) {
|
|
3952
|
-
const [page, setPage] = (0,
|
|
3724
|
+
const [page, setPage] = (0, import_react7.useState)(1);
|
|
3953
3725
|
const totalPages = Math.ceil(total / pageSize);
|
|
3954
3726
|
return { page, setPage, pageSize, total, totalPages };
|
|
3955
3727
|
}
|
|
@@ -4346,8 +4118,6 @@ var import_next_themes2 = require("next-themes");
|
|
|
4346
4118
|
LoadingSpinner,
|
|
4347
4119
|
LocalInput,
|
|
4348
4120
|
MediaCard,
|
|
4349
|
-
MediaGrid,
|
|
4350
|
-
MediaPickerDialog,
|
|
4351
4121
|
NotificationBell,
|
|
4352
4122
|
Page,
|
|
4353
4123
|
PageSection,
|
|
@@ -4393,6 +4163,8 @@ var import_next_themes2 = require("next-themes");
|
|
|
4393
4163
|
TooltipProvider,
|
|
4394
4164
|
TooltipTrigger,
|
|
4395
4165
|
TopBar,
|
|
4166
|
+
UploadProgressPanel,
|
|
4167
|
+
UploadZone,
|
|
4396
4168
|
badgeVariants,
|
|
4397
4169
|
buttonVariants,
|
|
4398
4170
|
cn,
|