@orthacms/media-admin 0.0.0-reserve.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/LICENSE +21 -0
- package/README.md +7 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/components/AssetActionsMenu/index.d.ts +37 -0
- package/dist/lib/components/AssetActionsMenu/index.d.ts.map +1 -0
- package/dist/lib/components/AssetActionsMenu/index.js +57 -0
- package/dist/lib/components/AssetDetailDrawer/MetaRow/index.d.ts +11 -0
- package/dist/lib/components/AssetDetailDrawer/MetaRow/index.d.ts.map +1 -0
- package/dist/lib/components/AssetDetailDrawer/MetaRow/index.js +9 -0
- package/dist/lib/components/AssetDetailDrawer/index.d.ts +28 -0
- package/dist/lib/components/AssetDetailDrawer/index.d.ts.map +1 -0
- package/dist/lib/components/AssetDetailDrawer/index.js +93 -0
- package/dist/lib/components/EntryMediaTab/MediaFieldSection/index.d.ts +28 -0
- package/dist/lib/components/EntryMediaTab/MediaFieldSection/index.d.ts.map +1 -0
- package/dist/lib/components/EntryMediaTab/MediaFieldSection/index.js +52 -0
- package/dist/lib/components/EntryMediaTab/index.d.ts +11 -0
- package/dist/lib/components/EntryMediaTab/index.d.ts.map +1 -0
- package/dist/lib/components/EntryMediaTab/index.js +31 -0
- package/dist/lib/components/FolderActionsMenu/index.d.ts +21 -0
- package/dist/lib/components/FolderActionsMenu/index.d.ts.map +1 -0
- package/dist/lib/components/FolderActionsMenu/index.js +25 -0
- package/dist/lib/components/MediaAltTextWidget/index.d.ts +9 -0
- package/dist/lib/components/MediaAltTextWidget/index.d.ts.map +1 -0
- package/dist/lib/components/MediaAltTextWidget/index.js +66 -0
- package/dist/lib/components/MediaBreadcrumbs/index.d.ts +11 -0
- package/dist/lib/components/MediaBreadcrumbs/index.d.ts.map +1 -0
- package/dist/lib/components/MediaEmptyState/index.d.ts +13 -0
- package/dist/lib/components/MediaEmptyState/index.d.ts.map +1 -0
- package/dist/lib/components/MediaEmptyState/index.js +38 -0
- package/dist/lib/components/MediaFieldControl/MediaFieldItem/index.d.ts +34 -0
- package/dist/lib/components/MediaFieldControl/MediaFieldItem/index.d.ts.map +1 -0
- package/dist/lib/components/MediaFieldControl/MediaFieldItem/index.js +117 -0
- package/dist/lib/components/MediaFieldControl/index.d.ts +61 -0
- package/dist/lib/components/MediaFieldControl/index.d.ts.map +1 -0
- package/dist/lib/components/MediaFieldControl/index.js +422 -0
- package/dist/lib/components/MediaFoldersNav/MediaFolderTreeItem/index.d.ts +17 -0
- package/dist/lib/components/MediaFoldersNav/MediaFolderTreeItem/index.d.ts.map +1 -0
- package/dist/lib/components/MediaFoldersNav/MediaFolderTreeItem/index.js +37 -0
- package/dist/lib/components/MediaFoldersNav/index.d.ts +22 -0
- package/dist/lib/components/MediaFoldersNav/index.d.ts.map +1 -0
- package/dist/lib/components/MediaFoldersNav/index.js +40 -0
- package/dist/lib/components/MediaGrid/MediaAssetCard/index.d.ts +18 -0
- package/dist/lib/components/MediaGrid/MediaAssetCard/index.d.ts.map +1 -0
- package/dist/lib/components/MediaGrid/MediaAssetCard/index.js +29 -0
- package/dist/lib/components/MediaGrid/MediaFolderCard/index.d.ts +16 -0
- package/dist/lib/components/MediaGrid/MediaFolderCard/index.d.ts.map +1 -0
- package/dist/lib/components/MediaGrid/MediaFolderCard/index.js +25 -0
- package/dist/lib/components/MediaGrid/index.d.ts +24 -0
- package/dist/lib/components/MediaGrid/index.d.ts.map +1 -0
- package/dist/lib/components/MediaGrid/index.js +20 -0
- package/dist/lib/components/MediaKindBadge/index.d.ts +10 -0
- package/dist/lib/components/MediaKindBadge/index.d.ts.map +1 -0
- package/dist/lib/components/MediaKindBadge/index.js +30 -0
- package/dist/lib/components/MediaKindIcon/index.d.ts +11 -0
- package/dist/lib/components/MediaKindIcon/index.d.ts.map +1 -0
- package/dist/lib/components/MediaKindIcon/index.js +20 -0
- package/dist/lib/components/MediaLibrarySkeleton/index.d.ts +18 -0
- package/dist/lib/components/MediaLibrarySkeleton/index.d.ts.map +1 -0
- package/dist/lib/components/MediaLibrarySkeleton/index.js +43 -0
- package/dist/lib/components/MediaPagination/index.d.ts +26 -0
- package/dist/lib/components/MediaPagination/index.d.ts.map +1 -0
- package/dist/lib/components/MediaPagination/index.js +52 -0
- package/dist/lib/components/MediaPickerDialog/MediaPickerTile/index.d.ts +17 -0
- package/dist/lib/components/MediaPickerDialog/MediaPickerTile/index.d.ts.map +1 -0
- package/dist/lib/components/MediaPickerDialog/MediaPickerTile/index.js +43 -0
- package/dist/lib/components/MediaPickerDialog/index.d.ts +21 -0
- package/dist/lib/components/MediaPickerDialog/index.d.ts.map +1 -0
- package/dist/lib/components/MediaPickerDialog/index.js +208 -0
- package/dist/lib/components/MediaSelectionBar/index.d.ts +18 -0
- package/dist/lib/components/MediaSelectionBar/index.d.ts.map +1 -0
- package/dist/lib/components/MediaSelectionBar/index.js +26 -0
- package/dist/lib/components/MediaStorageStat/index.d.ts +9 -0
- package/dist/lib/components/MediaStorageStat/index.d.ts.map +1 -0
- package/dist/lib/components/MediaStorageStat/index.js +31 -0
- package/dist/lib/components/MediaStorageWidget/index.d.ts +10 -0
- package/dist/lib/components/MediaStorageWidget/index.d.ts.map +1 -0
- package/dist/lib/components/MediaStorageWidget/index.js +93 -0
- package/dist/lib/components/MediaTable/MediaAssetRow/index.d.ts +17 -0
- package/dist/lib/components/MediaTable/MediaAssetRow/index.d.ts.map +1 -0
- package/dist/lib/components/MediaTable/MediaFolderRow/index.d.ts +16 -0
- package/dist/lib/components/MediaTable/MediaFolderRow/index.d.ts.map +1 -0
- package/dist/lib/components/MediaTable/index.d.ts +26 -0
- package/dist/lib/components/MediaTable/index.d.ts.map +1 -0
- package/dist/lib/components/MediaThumbnail/index.d.ts +19 -0
- package/dist/lib/components/MediaThumbnail/index.d.ts.map +1 -0
- package/dist/lib/components/MediaThumbnail/index.js +26 -0
- package/dist/lib/components/MediaToolbar/index.d.ts +19 -0
- package/dist/lib/components/MediaToolbar/index.d.ts.map +1 -0
- package/dist/lib/components/MediaToolbar/index.js +62 -0
- package/dist/lib/components/MediaTopBar/index.d.ts +20 -0
- package/dist/lib/components/MediaTopBar/index.d.ts.map +1 -0
- package/dist/lib/components/MediaTopBar/index.js +35 -0
- package/dist/lib/components/MediaUploadBanner/MediaUploadRow/index.d.ts +14 -0
- package/dist/lib/components/MediaUploadBanner/MediaUploadRow/index.d.ts.map +1 -0
- package/dist/lib/components/MediaUploadBanner/MediaUploadRow/index.js +51 -0
- package/dist/lib/components/MediaUploadBanner/index.d.ts +24 -0
- package/dist/lib/components/MediaUploadBanner/index.d.ts.map +1 -0
- package/dist/lib/components/MediaUploadBanner/index.js +99 -0
- package/dist/lib/components/MediaUploadsWidget/index.d.ts +7 -0
- package/dist/lib/components/MediaUploadsWidget/index.d.ts.map +1 -0
- package/dist/lib/components/MediaUploadsWidget/index.js +70 -0
- package/dist/lib/components/MoveAssetsDialog/DestinationOption/index.d.ts +19 -0
- package/dist/lib/components/MoveAssetsDialog/DestinationOption/index.d.ts.map +1 -0
- package/dist/lib/components/MoveAssetsDialog/DestinationOption/index.js +10 -0
- package/dist/lib/components/MoveAssetsDialog/index.d.ts +18 -0
- package/dist/lib/components/MoveAssetsDialog/index.d.ts.map +1 -0
- package/dist/lib/components/MoveAssetsDialog/index.js +41 -0
- package/dist/lib/components/NewFolderDialog/index.d.ts +13 -0
- package/dist/lib/components/NewFolderDialog/index.d.ts.map +1 -0
- package/dist/lib/components/NewFolderDialog/index.js +45 -0
- package/dist/lib/components/RenameDialog/index.d.ts +13 -0
- package/dist/lib/components/RenameDialog/index.d.ts.map +1 -0
- package/dist/lib/components/RenameDialog/index.js +37 -0
- package/dist/lib/components/UploadDialog/StagedFileRow/index.d.ts +25 -0
- package/dist/lib/components/UploadDialog/StagedFileRow/index.d.ts.map +1 -0
- package/dist/lib/components/UploadDialog/StagedFileRow/index.js +82 -0
- package/dist/lib/components/UploadDialog/index.d.ts +50 -0
- package/dist/lib/components/UploadDialog/index.d.ts.map +1 -0
- package/dist/lib/components/UploadDialog/index.js +120 -0
- package/dist/lib/components/WysiwygLibrarySource/index.d.ts +14 -0
- package/dist/lib/components/WysiwygLibrarySource/index.d.ts.map +1 -0
- package/dist/lib/components/WysiwygLibrarySource/index.js +28 -0
- package/dist/lib/components/WysiwygUploadSource/index.d.ts +25 -0
- package/dist/lib/components/WysiwygUploadSource/index.d.ts.map +1 -0
- package/dist/lib/components/WysiwygUploadSource/index.js +102 -0
- package/dist/lib/constants/index.d.ts +82 -0
- package/dist/lib/constants/index.d.ts.map +1 -0
- package/dist/lib/constants/index.js +75 -0
- package/dist/lib/hooks/useMediaInsights/index.d.ts +32 -0
- package/dist/lib/hooks/useMediaInsights/index.d.ts.map +1 -0
- package/dist/lib/hooks/useMediaInsights/index.js +85 -0
- package/dist/lib/hooks/useMediaLibrary/index.d.ts +83 -0
- package/dist/lib/hooks/useMediaLibrary/index.d.ts.map +1 -0
- package/dist/lib/hooks/useMediaLibrary/index.js +341 -0
- package/dist/lib/hooks/usePendingMediaUploads/index.d.ts +26 -0
- package/dist/lib/hooks/usePendingMediaUploads/index.d.ts.map +1 -0
- package/dist/lib/hooks/usePendingMediaUploads/index.js +217 -0
- package/dist/lib/hooks/useUploadQueue/index.d.ts +33 -0
- package/dist/lib/hooks/useUploadQueue/index.d.ts.map +1 -0
- package/dist/lib/hooks/useUploadQueue/index.js +218 -0
- package/dist/lib/hooks/useWysiwygAssetPicker/index.d.ts +23 -0
- package/dist/lib/hooks/useWysiwygAssetPicker/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/apiMessage/index.d.ts +17 -0
- package/dist/lib/infrastructure/apiMessage/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/apiMessage/index.js +30 -0
- package/dist/lib/infrastructure/httpMediaGateway/index.d.ts +9 -0
- package/dist/lib/infrastructure/httpMediaGateway/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/httpMediaGateway/index.js +157 -0
- package/dist/lib/infrastructure/httpMediaInsightsGateway/index.d.ts +8 -0
- package/dist/lib/infrastructure/httpMediaInsightsGateway/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/httpMediaInsightsGateway/index.js +35 -0
- package/dist/lib/infrastructure/mediaGateway/index.d.ts +120 -0
- package/dist/lib/infrastructure/mediaGateway/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/mediaGateway/index.js +1 -0
- package/dist/lib/infrastructure/mediaInsightsGateway/index.d.ts +46 -0
- package/dist/lib/infrastructure/mediaInsightsGateway/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/mediaInsightsGateway/index.js +6 -0
- package/dist/lib/infrastructure/mediaKeys/index.d.ts +23 -0
- package/dist/lib/infrastructure/mediaKeys/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/mediaKeys/index.js +11 -0
- package/dist/lib/infrastructure/mediaMapper/index.d.ts +50 -0
- package/dist/lib/infrastructure/mediaMapper/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/mediaMapper/index.js +39 -0
- package/dist/lib/pages/MediaLibraryPage/index.d.ts +23 -0
- package/dist/lib/pages/MediaLibraryPage/index.d.ts.map +1 -0
- package/dist/lib/pages/MediaLibraryPage/index.js +425 -0
- package/dist/lib/types/mediaAsset/index.d.ts +44 -0
- package/dist/lib/types/mediaAsset/index.d.ts.map +1 -0
- package/dist/lib/types/mediaAsset/index.js +1 -0
- package/dist/lib/types/mediaFieldDisplay/index.d.ts +48 -0
- package/dist/lib/types/mediaFieldDisplay/index.d.ts.map +1 -0
- package/dist/lib/types/mediaFieldDisplay/index.js +1 -0
- package/dist/lib/types/mediaFolder/index.d.ts +16 -0
- package/dist/lib/types/mediaFolder/index.d.ts.map +1 -0
- package/dist/lib/types/mediaFolder/index.js +1 -0
- package/dist/lib/types/pendingUpload/index.d.ts +38 -0
- package/dist/lib/types/pendingUpload/index.d.ts.map +1 -0
- package/dist/lib/types/pendingUpload/index.js +1 -0
- package/dist/lib/types/upload/index.d.ts +37 -0
- package/dist/lib/types/upload/index.d.ts.map +1 -0
- package/dist/lib/types/upload/index.js +1 -0
- package/dist/lib/utils/assetGradient/index.d.ts +8 -0
- package/dist/lib/utils/assetGradient/index.d.ts.map +1 -0
- package/dist/lib/utils/assetGradient/index.js +16 -0
- package/dist/lib/utils/assetHandlers/index.d.ts +11 -0
- package/dist/lib/utils/assetHandlers/index.d.ts.map +1 -0
- package/dist/lib/utils/assetHandlers/index.js +17 -0
- package/dist/lib/utils/folderContents/index.d.ts +17 -0
- package/dist/lib/utils/folderContents/index.d.ts.map +1 -0
- package/dist/lib/utils/folderContents/index.js +35 -0
- package/dist/lib/utils/folderTree/index.d.ts +13 -0
- package/dist/lib/utils/folderTree/index.d.ts.map +1 -0
- package/dist/lib/utils/folderTree/index.js +15 -0
- package/dist/lib/utils/formatBytes/index.d.ts +6 -0
- package/dist/lib/utils/formatBytes/index.d.ts.map +1 -0
- package/dist/lib/utils/formatBytes/index.js +17 -0
- package/dist/lib/utils/formatDuration/index.d.ts +6 -0
- package/dist/lib/utils/formatDuration/index.d.ts.map +1 -0
- package/dist/lib/utils/formatDuration/index.js +13 -0
- package/dist/lib/utils/kindFromMime/index.d.ts +10 -0
- package/dist/lib/utils/kindFromMime/index.d.ts.map +1 -0
- package/dist/lib/utils/kindFromMime/index.js +27 -0
- package/dist/lib/utils/mediaAccept/index.d.ts +30 -0
- package/dist/lib/utils/mediaAccept/index.d.ts.map +1 -0
- package/dist/lib/utils/mediaAccept/index.js +63 -0
- package/dist/lib/utils/mediaPlugin/index.d.ts +15 -0
- package/dist/lib/utils/mediaPlugin/index.d.ts.map +1 -0
- package/dist/lib/utils/mediaPlugin/index.js +177 -0
- package/dist/lib/utils/toWysiwygEmbed/index.d.ts +23 -0
- package/dist/lib/utils/toWysiwygEmbed/index.d.ts.map +1 -0
- package/dist/lib/utils/toWysiwygEmbed/index.js +44 -0
- package/package.json +50 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { defineMessages, useIntl } from 'react-intl';
|
|
3
|
+
import { Button, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from '@orthacms/design-system';
|
|
4
|
+
import { FileSearch, ImagePlus, UploadCloud } from 'lucide-react';
|
|
5
|
+
/** Intl descriptors for {@link MediaEmptyState}, co-located. */
|
|
6
|
+
const messages = defineMessages({
|
|
7
|
+
emptyTitle: {
|
|
8
|
+
id: 'media.empty.emptyTitle',
|
|
9
|
+
defaultMessage: 'This folder is empty'
|
|
10
|
+
},
|
|
11
|
+
emptyBody: {
|
|
12
|
+
id: 'media.empty.emptyBody',
|
|
13
|
+
defaultMessage: 'Upload images, video, audio, or documents to get started.'
|
|
14
|
+
},
|
|
15
|
+
upload: { id: 'media.empty.upload', defaultMessage: 'Upload assets' },
|
|
16
|
+
noResultsTitle: {
|
|
17
|
+
id: 'media.empty.noResultsTitle',
|
|
18
|
+
defaultMessage: 'No matching assets'
|
|
19
|
+
},
|
|
20
|
+
noResultsBody: {
|
|
21
|
+
id: 'media.empty.noResultsBody',
|
|
22
|
+
defaultMessage: 'Try a different search term or clear the filters.'
|
|
23
|
+
},
|
|
24
|
+
clear: { id: 'media.empty.clear', defaultMessage: 'Clear filters' }
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* The browser's empty state. When a search/filter is active it offers to clear
|
|
28
|
+
* them; otherwise (a genuinely empty folder) it invites an upload — the upload
|
|
29
|
+
* CTA shows only when the user may create. The page decides which variant via
|
|
30
|
+
* `hasFilters`.
|
|
31
|
+
*/
|
|
32
|
+
export function MediaEmptyState({ hasFilters, canCreate, onUpload, onClearFilters }) {
|
|
33
|
+
const intl = useIntl();
|
|
34
|
+
if (hasFilters) {
|
|
35
|
+
return (_jsxs(Empty, { className: "py-16", children: [_jsxs(EmptyHeader, { children: [_jsx(EmptyMedia, { variant: "icon", children: _jsx(FileSearch, { "aria-hidden": true }) }), _jsx(EmptyTitle, { children: intl.formatMessage(messages.noResultsTitle) }), _jsx(EmptyDescription, { children: intl.formatMessage(messages.noResultsBody) })] }), _jsx(EmptyContent, { children: _jsx(Button, { variant: "outline", className: "shadow-none", onClick: onClearFilters, children: intl.formatMessage(messages.clear) }) })] }));
|
|
36
|
+
}
|
|
37
|
+
return (_jsxs(Empty, { className: "py-16", children: [_jsxs(EmptyHeader, { children: [_jsx(EmptyMedia, { variant: "icon", children: _jsx(ImagePlus, { "aria-hidden": true }) }), _jsx(EmptyTitle, { children: intl.formatMessage(messages.emptyTitle) }), _jsx(EmptyDescription, { children: intl.formatMessage(messages.emptyBody) })] }), canCreate ? (_jsx(EmptyContent, { children: _jsxs(Button, { onClick: onUpload, children: [_jsx(UploadCloud, { "aria-hidden": true }), intl.formatMessage(messages.upload)] }) })) : null] }));
|
|
38
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { MediaFieldDisplay } from '../../../types/mediaFieldDisplay';
|
|
2
|
+
/**
|
|
3
|
+
* One attached asset on a media field — a preview tile (the real image, else the
|
|
4
|
+
* asset's deterministic gradient behind its kind glyph) over the file name and
|
|
5
|
+
* what is known of its type / size / dimensions, with the per-item controls
|
|
6
|
+
* revealed on hover or focus: open in a new tab, remove, and — in an ordered
|
|
7
|
+
* multiple field — nudge up/down. A `missing` ref renders as an explicit warning
|
|
8
|
+
* tile instead of a broken preview, so a dead id can still be found and removed,
|
|
9
|
+
* and a `resolving` one (its ref still in flight) renders a placeholder rather
|
|
10
|
+
* than guessing a URL — a guess would fetch the full-size original.
|
|
11
|
+
*
|
|
12
|
+
* In a **read-only** editor the tile keeps its preview, its name, its metadata
|
|
13
|
+
* and its open-in-a-new-tab link, and drops remove + reorder. The position badge
|
|
14
|
+
* stays: order is part of what the field *holds*, not a control.
|
|
15
|
+
*/
|
|
16
|
+
export declare function MediaFieldItem({ item, index, total, multiple, readOnly, onRemove, onMove, alt, decorative, onAltChange, onDecorativeChange }: {
|
|
17
|
+
item: MediaFieldDisplay;
|
|
18
|
+
/** Zero-based position, shown (1-based) and used to gate the arrows. */
|
|
19
|
+
index: number;
|
|
20
|
+
total: number;
|
|
21
|
+
/** Ordered-multiple field: renders the position badge + reorder arrows. */
|
|
22
|
+
multiple: boolean;
|
|
23
|
+
/** Preview mode — drop the remove and reorder controls. */
|
|
24
|
+
readOnly?: boolean;
|
|
25
|
+
onRemove: () => void;
|
|
26
|
+
onMove: (delta: number) => void;
|
|
27
|
+
/** The text alternative stored on **this usage**, if any. */
|
|
28
|
+
alt?: string;
|
|
29
|
+
/** Whether this usage is marked purely presentational. */
|
|
30
|
+
decorative?: boolean;
|
|
31
|
+
onAltChange?: (next: string) => void;
|
|
32
|
+
onDecorativeChange?: (next: boolean) => void;
|
|
33
|
+
}): import("react").JSX.Element;
|
|
34
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/MediaFieldControl/MediaFieldItem/index.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAoE1E;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,EAC3B,IAAI,EACJ,KAAK,EACL,KAAK,EACL,QAAQ,EACR,QAAgB,EAChB,QAAQ,EACR,MAAM,EACN,GAAG,EACH,UAAkB,EAClB,WAAW,EACX,kBAAkB,EACrB,EAAE;IACC,IAAI,EAAE,iBAAiB,CAAC;IACxB,wEAAwE;IACxE,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,QAAQ,EAAE,OAAO,CAAC;IAClB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,6DAA6D;IAC7D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CAChD,+BAsOA"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useId } from 'react';
|
|
3
|
+
import { defineMessages, useIntl } from 'react-intl';
|
|
4
|
+
import { ArrowDown, ArrowUp, ExternalLink, FileWarning, Trash2 } from 'lucide-react';
|
|
5
|
+
import { Button, Checkbox, Field, FieldLabel, Input, cn } from '@orthacms/design-system';
|
|
6
|
+
import { MEDIA_ALT_MAX_LENGTH } from '@orthacms/content-domain';
|
|
7
|
+
import { MEDIA_KIND } from '../../../constants';
|
|
8
|
+
import { assetGradient } from '../../../utils/assetGradient';
|
|
9
|
+
import { formatBytes } from '../../../utils/formatBytes';
|
|
10
|
+
import { MediaKindIcon } from '../../MediaKindIcon';
|
|
11
|
+
/** Intl descriptors for {@link MediaFieldItem}, co-located. */
|
|
12
|
+
const messages = defineMessages({
|
|
13
|
+
altLabel: {
|
|
14
|
+
id: 'media.field.item.altLabel',
|
|
15
|
+
defaultMessage: 'Alt text for {name}'
|
|
16
|
+
},
|
|
17
|
+
altPlaceholder: {
|
|
18
|
+
id: 'media.field.item.altPlaceholder',
|
|
19
|
+
defaultMessage: 'Describe this image'
|
|
20
|
+
},
|
|
21
|
+
altMissing: {
|
|
22
|
+
id: 'media.field.item.altMissing',
|
|
23
|
+
defaultMessage: 'Needs alt text'
|
|
24
|
+
},
|
|
25
|
+
decorativeLabel: {
|
|
26
|
+
id: 'media.field.item.decorativeLabel',
|
|
27
|
+
defaultMessage: 'Decorative — no description needed'
|
|
28
|
+
},
|
|
29
|
+
remove: { id: 'media.fieldItem.remove', defaultMessage: 'Remove {name}' },
|
|
30
|
+
preview: {
|
|
31
|
+
id: 'media.fieldItem.preview',
|
|
32
|
+
defaultMessage: 'Open {name} in a new tab'
|
|
33
|
+
},
|
|
34
|
+
moveUp: { id: 'media.fieldItem.moveUp', defaultMessage: 'Move {name} up' },
|
|
35
|
+
moveDown: {
|
|
36
|
+
id: 'media.fieldItem.moveDown',
|
|
37
|
+
defaultMessage: 'Move {name} down'
|
|
38
|
+
},
|
|
39
|
+
unavailable: {
|
|
40
|
+
id: 'media.fieldItem.unavailable',
|
|
41
|
+
defaultMessage: 'Unavailable asset'
|
|
42
|
+
},
|
|
43
|
+
unavailableHint: {
|
|
44
|
+
id: 'media.fieldItem.unavailableHint',
|
|
45
|
+
defaultMessage: 'Deleted or out of workspace'
|
|
46
|
+
},
|
|
47
|
+
pending: {
|
|
48
|
+
id: 'media.fieldItem.pending',
|
|
49
|
+
defaultMessage: 'Uploads on save'
|
|
50
|
+
},
|
|
51
|
+
resolving: {
|
|
52
|
+
id: 'media.fieldItem.resolving',
|
|
53
|
+
defaultMessage: 'Loading asset…'
|
|
54
|
+
},
|
|
55
|
+
position: {
|
|
56
|
+
id: 'media.fieldItem.position',
|
|
57
|
+
defaultMessage: 'Position {index} of {total}'
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
/** `image/png` → `PNG`; the short type label under the file name. */
|
|
61
|
+
function formatKind(mimeType) {
|
|
62
|
+
const subtype = mimeType.split('/')[1];
|
|
63
|
+
if (!subtype)
|
|
64
|
+
return null;
|
|
65
|
+
return subtype.split('+')[0]?.toUpperCase() ?? null;
|
|
66
|
+
}
|
|
67
|
+
/** The glyph kind for a ref's `kind` string, falling back for an unknown one. */
|
|
68
|
+
function kindOf(kind) {
|
|
69
|
+
const known = Object.values(MEDIA_KIND);
|
|
70
|
+
return known.includes(kind) ? kind : MEDIA_KIND.Document;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* One attached asset on a media field — a preview tile (the real image, else the
|
|
74
|
+
* asset's deterministic gradient behind its kind glyph) over the file name and
|
|
75
|
+
* what is known of its type / size / dimensions, with the per-item controls
|
|
76
|
+
* revealed on hover or focus: open in a new tab, remove, and — in an ordered
|
|
77
|
+
* multiple field — nudge up/down. A `missing` ref renders as an explicit warning
|
|
78
|
+
* tile instead of a broken preview, so a dead id can still be found and removed,
|
|
79
|
+
* and a `resolving` one (its ref still in flight) renders a placeholder rather
|
|
80
|
+
* than guessing a URL — a guess would fetch the full-size original.
|
|
81
|
+
*
|
|
82
|
+
* In a **read-only** editor the tile keeps its preview, its name, its metadata
|
|
83
|
+
* and its open-in-a-new-tab link, and drops remove + reorder. The position badge
|
|
84
|
+
* stays: order is part of what the field *holds*, not a control.
|
|
85
|
+
*/
|
|
86
|
+
export function MediaFieldItem({ item, index, total, multiple, readOnly = false, onRemove, onMove, alt, decorative = false, onAltChange, onDecorativeChange }) {
|
|
87
|
+
const intl = useIntl();
|
|
88
|
+
const altId = useId();
|
|
89
|
+
const asImage = item.kind === MEDIA_KIND.Image;
|
|
90
|
+
const meta = [
|
|
91
|
+
formatKind(item.mimeType),
|
|
92
|
+
typeof item.size === 'number' ? formatBytes(item.size) : null,
|
|
93
|
+
item.dimensions
|
|
94
|
+
? `${item.dimensions.width}×${item.dimensions.height}`
|
|
95
|
+
: null
|
|
96
|
+
]
|
|
97
|
+
.filter(Boolean)
|
|
98
|
+
.join(' · ');
|
|
99
|
+
return (_jsxs("li", { className: cn('group/item relative overflow-hidden rounded-lg border bg-card transition-shadow hover:shadow-md', item.missing && 'border-destructive/50', (item.pending || item.resolving) && 'border-dashed'), children: [_jsxs("div", { className: "relative aspect-[4/3] w-full overflow-hidden bg-muted", style: !item.missing && !item.resolving && !asImage
|
|
100
|
+
? { backgroundImage: assetGradient(item.id) }
|
|
101
|
+
: undefined, children: [item.resolving ? (_jsx("span", { className: "flex size-full animate-pulse items-center justify-center bg-muted text-[11px] text-muted-foreground", children: intl.formatMessage(messages.resolving) })) : item.missing ? (_jsxs("span", { className: "flex size-full flex-col items-center justify-center gap-1 bg-destructive/5 px-2 text-center text-destructive", children: [_jsx(FileWarning, { className: "size-6", "aria-hidden": true }), _jsx("span", { className: "text-[11px] font-medium leading-tight", children: intl.formatMessage(messages.unavailableHint) })] })) : asImage ? (_jsx("img", { src: item.url, alt: item.name, loading: "lazy", className: "absolute inset-0 size-full object-cover" })) : (_jsx("span", { className: "flex size-full items-center justify-center", children: _jsx(MediaKindIcon, { kind: kindOf(item.kind), className: "size-8 text-white/90 drop-shadow-sm" }) })), multiple ? (_jsx("span", { className: "absolute left-1.5 top-1.5 grid size-5 place-items-center rounded bg-black/60 text-[11px] font-medium tabular-nums text-white", title: intl.formatMessage(messages.position, {
|
|
102
|
+
index: index + 1,
|
|
103
|
+
total
|
|
104
|
+
}), children: index + 1 })) : null, item.pending ? (_jsx("span", { className: "absolute bottom-1.5 left-1.5 rounded bg-warning-soft px-1.5 py-0.5 text-[10px] font-medium leading-none text-warning-soft-foreground shadow-sm", children: intl.formatMessage(messages.pending) })) : null, _jsxs("div", { className: "absolute right-1.5 top-1.5 flex items-center gap-0.5 rounded-md bg-background/85 p-0.5 shadow-sm backdrop-blur transition-opacity focus-within:opacity-100 group-hover/item:opacity-100 sm:opacity-0", children: [item.missing || item.pending || item.resolving ? null : (_jsx(Button, { asChild: true, variant: "ghost", size: "icon", className: "size-6", children: _jsx("a", { href: item.originalUrl ?? item.url, target: "_blank", rel: "noreferrer", "aria-label": intl.formatMessage(messages.preview, { name: item.name }), children: _jsx(ExternalLink, { className: "size-3.5", "aria-hidden": true }) }) })), readOnly ? null : (_jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "size-6 text-muted-foreground hover:bg-destructive/10 hover:text-destructive", "aria-label": intl.formatMessage(messages.remove, {
|
|
105
|
+
name: item.name
|
|
106
|
+
}), onClick: onRemove, children: _jsx(Trash2, { className: "size-3.5", "aria-hidden": true }) }))] }), multiple && total > 1 && !readOnly ? (_jsxs("div", { className: "absolute bottom-1.5 right-1.5 flex items-center gap-0.5 rounded-md bg-background/85 p-0.5 shadow-sm backdrop-blur transition-opacity focus-within:opacity-100 group-hover/item:opacity-100 sm:opacity-0", children: [_jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "size-6", disabled: index === 0, "aria-label": intl.formatMessage(messages.moveUp, {
|
|
107
|
+
name: item.name
|
|
108
|
+
}), onClick: () => onMove(-1), children: _jsx(ArrowUp, { className: "size-3.5", "aria-hidden": true }) }), _jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "size-6", disabled: index === total - 1, "aria-label": intl.formatMessage(messages.moveDown, {
|
|
109
|
+
name: item.name
|
|
110
|
+
}), onClick: () => onMove(1), children: _jsx(ArrowDown, { className: "size-3.5", "aria-hidden": true }) })] })) : null] }), _jsxs("div", { className: "min-w-0 px-2.5 py-2", children: [_jsx("p", { className: cn('truncate text-xs font-medium', item.missing && 'text-destructive', item.resolving && 'text-muted-foreground'), title: item.missing || item.resolving ? undefined : item.name, children: item.missing
|
|
111
|
+
? intl.formatMessage(messages.unavailable)
|
|
112
|
+
: item.resolving
|
|
113
|
+
? intl.formatMessage(messages.resolving)
|
|
114
|
+
: item.name }), _jsx("p", { className: "truncate text-[11px] text-muted-foreground", children: item.missing ? item.id : item.resolving ? '' : meta })] }), !readOnly && !item.missing && !item.resolving && onAltChange ? (_jsxs("div", { className: "flex flex-col gap-1.5 border-t px-2.5 py-2", children: [_jsxs(Field, { children: [_jsx(FieldLabel, { htmlFor: altId, className: "text-[11px]", children: intl.formatMessage(messages.altLabel, {
|
|
115
|
+
name: item.name
|
|
116
|
+
}) }), _jsx(Input, { id: altId, value: alt ?? '', disabled: decorative, maxLength: MEDIA_ALT_MAX_LENGTH, placeholder: intl.formatMessage(messages.altPlaceholder), onChange: (event) => onAltChange(event.target.value), className: "h-7 text-xs" })] }), onDecorativeChange ? (_jsxs("label", { className: "text-muted-foreground flex items-center gap-1.5 text-[11px]", children: [_jsx(Checkbox, { checked: decorative, onCheckedChange: (next) => onDecorativeChange(next === true) }), intl.formatMessage(messages.decorativeLabel)] })) : null, !decorative && !(alt ?? '').trim() ? (_jsx("p", { className: "text-warning-soft-foreground text-[11px]", children: intl.formatMessage(messages.altMissing) })) : null] })) : null] }));
|
|
117
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { MediaRef } from '@orthacms/content-admin';
|
|
2
|
+
import type { MediaPendingUploads } from '../../types/pendingUpload';
|
|
3
|
+
import { type MediaAccept } from '../../utils/mediaAccept';
|
|
4
|
+
/**
|
|
5
|
+
* The editor control for one media field — a single asset or an ordered list.
|
|
6
|
+
* The attached assets render as preview tiles ({@link MediaFieldItem}, resolved
|
|
7
|
+
* from the server-provided refs or a just-picked/uploaded asset) inside a panel
|
|
8
|
+
* that doubles as a **drop zone**. Below it sit **Select from library** (the
|
|
9
|
+
* {@link MediaPickerDialog}) and **Upload**, plus the field's accept hint and, in
|
|
10
|
+
* multiple mode, the attached count.
|
|
11
|
+
*
|
|
12
|
+
* **Choosing a file uploads nothing.** The {@link UploadDialog} — the Media
|
|
13
|
+
* Library's own modal, reused whole — stages and previews the files (a drop on
|
|
14
|
+
* the panel opens it pre-staged), and confirming only *stages* them: they get a
|
|
15
|
+
* placeholder id, render as "Pending upload" tiles, and the bytes move when the
|
|
16
|
+
* record is **saved or published** (`usePendingMediaUploads`, the plugin's
|
|
17
|
+
* presave contribution). So abandoning an edit leaves nothing behind in the
|
|
18
|
+
* library, and a record plus its new assets land as one commit.
|
|
19
|
+
*
|
|
20
|
+
* Fully controlled: the parent (the Media tab, bound to the entry form) owns the
|
|
21
|
+
* value as an asset id or id array.
|
|
22
|
+
*
|
|
23
|
+
* **Read-only** (the reader has no `content:update`/`content:create` on the
|
|
24
|
+
* record) reduces it to the tiles: no drop zone, no Select/Upload row, no
|
|
25
|
+
* remove or reorder on a tile. Note this is a *content* permission, distinct
|
|
26
|
+
* from the `media:*` gates below — a user may hold every media permission there
|
|
27
|
+
* is and still not be allowed to change **this record**, and attaching an asset
|
|
28
|
+
* to a record is a write to the record.
|
|
29
|
+
*/
|
|
30
|
+
export declare function MediaFieldControl({ id, multiple, accept, value, initialRefs, refsPending, invalid, describedBy, required, uploads, readOnly, onChange, onBlur }: {
|
|
31
|
+
id: string;
|
|
32
|
+
multiple: boolean;
|
|
33
|
+
accept?: MediaAccept;
|
|
34
|
+
value: unknown;
|
|
35
|
+
/** Server-resolved refs for pre-existing ids (names / thumbnails / missing). */
|
|
36
|
+
initialRefs?: MediaRef[];
|
|
37
|
+
/**
|
|
38
|
+
* Whether the entry's media read is still in flight. Distinguishes "not
|
|
39
|
+
* resolved **yet**" (wait, render a placeholder) from "resolved to nothing"
|
|
40
|
+
* (the read failed or no media plugin is bound — fall back to the raw route
|
|
41
|
+
* rather than waiting forever).
|
|
42
|
+
*/
|
|
43
|
+
refsPending?: boolean;
|
|
44
|
+
invalid?: boolean;
|
|
45
|
+
describedBy?: string;
|
|
46
|
+
required?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* The editor-level staging for not-yet-uploaded files. Absent when no presave
|
|
49
|
+
* contribution is mounted — the control then offers library picking only,
|
|
50
|
+
* rather than an Upload button that could never commit.
|
|
51
|
+
*/
|
|
52
|
+
uploads?: MediaPendingUploads;
|
|
53
|
+
/**
|
|
54
|
+
* Preview mode — the entry editor is read-only, so the field shows what is
|
|
55
|
+
* attached and offers no way to change it.
|
|
56
|
+
*/
|
|
57
|
+
readOnly?: boolean;
|
|
58
|
+
onChange: (value: unknown) => void;
|
|
59
|
+
onBlur?: () => void;
|
|
60
|
+
}): import("react").JSX.Element;
|
|
61
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/MediaFieldControl/index.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAKxD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAErE,OAAO,EAGH,KAAK,WAAW,EACnB,MAAM,yBAAyB,CAAC;AAqHjC;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,iBAAiB,CAAC,EAC9B,EAAE,EACF,QAAQ,EACR,MAAM,EACN,KAAK,EACL,WAAW,EACX,WAAW,EACX,OAAO,EACP,WAAW,EACX,QAAQ,EACR,OAAO,EACP,QAAgB,EAChB,QAAQ,EACR,MAAM,EACT,EAAE;IACC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,KAAK,EAAE,OAAO,CAAC;IACf,gFAAgF;IAChF,WAAW,CAAC,EAAE,QAAQ,EAAE,CAAC;IACzB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB,+BA0dA"}
|