Appearance
Components ​
All components live in app/components/. Nuxt 4 auto-imports with pathPrefix: false — a file at components/asset/AssetCard.vue is used in templates as <AssetCard>, not <AssetAssetCard>.
Conventions ​
<script setup lang="ts">exclusively- Props:
defineProps<{ foo: string; bar?: number }>() - Emits:
defineEmits<{ (e: 'update:modelValue', v: string): void }>() - No
any— useunknown+ type guards if the shape is truly dynamic - Component files match the PascalCase component name exactly
- Co-locate slot content and render logic; extract sub-components when a single template exceeds ~150 lines
Global Components ​
App shell and persistent UI. Auto-imported via Nuxt's component system.
| Component | Description |
|---|---|
AppLoader.vue | Animated Collage SVG logo used as a loading spinner; accepts size/position props and a color array |
AsyncIcon.vue | Resolves icon names against the collage: Vuetify icon set; accepts name, color, width, height, and strokeWidth |
BreadCrumbs.vue | Folder-aware breadcrumb trail; navigates to root via the folder icon and supports both parent-path and children arrays |
DamNotification.vue | Sidebar notification bell with unread badge; opens a slide-out menu of system notifications |
EmptyStateIcon.vue | Renders either the default or branded empty-state icon depending on useBrand().brand.is_branded |
Error.vue | HTTP error display with status code, human-readable message, and a back-to-home button; handles 401 session-expired case. Props: error, isSharePage (default false), redirectSecondsLeft (number | null, default null). When redirectSecondsLeft > 0 it shows Redirecting to login in Ns… under the message; the value comes from useCollageErrorLayout via error.vue (see Layouts) |
ExternalLogo.vue | Renders a workspace logo image, or falls back to the brand name as text |
Header.vue | Top app bar; shows SMTP-unconfigured and uncategorized-assets alerts, embeds GlobalSearch, and exposes workspace-level controls |
ProcessingRequestOverlay.vue | Full-screen blocking overlay with spinner and configurable title; shown during long async operations |
Sidebar.vue | Left navigation drawer with rail/mini toggle, workspace logo, drag-to-folder support, and responsive mobile close button. The profile menu is bound to profileMenuOpen from useCollageSidebar(), which logoutApp() sets to false first so the menu closes before the logout redirect. Since 38752451 the redirect is immediate (window.location.replace('/') in finally, no 5 second delay); logout() itself waits at most 300 ms for the API (see Logout). The drawer treats the viewport as mobile at window.innerWidth <= 1199 (was 960) or (max-width: 600px) |
Asset Components ​
Components used in asset grid views, the asset detail panel, and the upload flow.
| Component | Description |
|---|---|
AddTags.vue | Thin wrapper around TagsBox for the asset detail panel; wires tag search, add, and remove to the asset store. Passes its canAddTags and canRemoveTags props (both default false) to TagsBox as can-add and can-remove; disable is !canAddTags. The asset detail page passes canAddTagsAsset / canRemoveTagsAsset from useAssetDetail, resolved with canAddTags / canRemoveTags for the current workspace (false when no workspace) |
AssetCard.vue | Grid card for a single asset; handles image, video (hover-play preview), audio, and generic file types; integrates selection checkbox and options menu. With externalPreview (folder and collage detail pages) the expand icon becomes expandGalleyIcon, the card emits expand instead of opening AssetQuickViewDialog, and that dialog is not mounted |
AssetContainer.vue | Inline preview container for PDFs (iframe), documents (image preview), and text files; shows skeleton while loading. Adds transparent-images to .assets-detail-wrapper for png, svg and gif (gray backdrop, 16 px padding) |
AssetCustomFieldsSection.vue | Displays editable custom field values in the asset detail panel; renders multi-select fields as chips and dates with a calendar style |
AssetImageOverlay.vue | Hover overlay for image asset cards; renders selection checkbox, options menu (DamItemMenu), and download button. expandIcon prop (default lightBoxIcon) names the expand button icon |
AssetUpload.vue | Full upload panel with drag-drop zone, queue management, per-file progress, success/error summary, and a "Next" action for post-upload flow |
AssetVersionItem.vue | Single row in the version history list; shows thumbnail, version label, date, uploaded-by, and a context menu for restore/delete |
AssetVideoOverlay.vue | Hover overlay for video asset cards; same controls pattern as AssetImageOverlay with video-specific behaviour, including the expandIcon prop |
ImageEditActions.vue | Sidebar panel for the image editor; exposes resize (width/height), crop aspect ratio presets, flip, and rotate controls |
ImageEditor.vue | Cropper.js canvas wrapper; initialises the cropper on image load and delegates resize/flip/rotate commands from ImageEditActions |
MediaResources.vue | Hidden DOM elements that wire assets into Fancybox for lightbox expand; renders a hidden <video> or <a> per file |
MiniUploadDialog.vue | Floating mini-panel showing the active upload queue; collapsible header with overall percentage and error indicator |
UploadBackdrop.vue | Full-viewport drag-over drop zone overlay; fades in when files are dragged over the window |
UploadChunk.vue | Single file row inside the upload queue; shows folder path, filename, chunk progress bar, and error/retry state |
UploadChunkExternal.vue | Variant of UploadChunk for the external (portal) upload context; same layout adapted for guest uploaders |
UploadedListItem.vue | Table list row for a completed upload; thumbnail, filename, folder path, and selection checkbox |
Collage Components ​
Components used in collage grid/list views and the dashboard recents panel.
| Component | Description |
|---|---|
Card.vue | Collage thumbnail card; supports single and multi-image preview mosaics with a lazy-load strategy and an options menu |
FolderCard.vue | Folder card in the collage grid; renders folder icon, name, selection checkbox, and context menu |
ListItem.vue | Collage list-view row; thumbnail avatar, collage name, and metadata columns |
MediaCard.vue | Asset card within a collage or portal detail view; handles restricted-visibility lock icon and opens asset detail on click |
MediaControls.vue | Hover control overlay for media cards; selection checkbox and options menu in card-mode context |
PreviewModal.vue | Hidden Fancybox resources for collage-detail lightbox; injects <video> and <a> elements that Fancybox targets |
RecentFolderListItem.vue | Folder row in the dashboard "Recent" list; folder icon, name, and asset count |
RecentUploadListItem.vue | Asset row in the dashboard "Recent Uploads" list; thumbnail, upload date, and filename |
VideoControls.vue | Hover overlay variant for video media cards; same checkbox and menu pattern tuned for video |
DAM Components ​
Core list-view, toolbar, and utility components used across DAM folder and asset views.
| Component | Description |
|---|---|
CustomTextEditor.vue | Lightweight rich-text editor (bold, italic, underline, lists) used for DAM text fields such as descriptions |
DamBulkActionsBar.vue | Floating or inline action bar that appears when one or more items are selected; draggable when floating |
DamDetailListView.vue | Sortable table list for assets with header (DamListHeader), row slots, and scroll events |
DamDisplayPanel.vue | "Display" dropdown button; controls active view mode (grid/mosaic/list) and thumbnail size for the current view |
DamItemMenu.vue | Reusable three-dot context menu button; filters out invisible items and delegates click events to the parent |
DamLibraryListView.vue | Sortable table list for folders and collages; same structure as DamDetailListView with a name-field prop |
DamListHeader.vue | Sticky table header row with per-column sort arrows, loading spinners, and a select-all checkbox |
DamListViewSkeleton.vue | Skeleton placeholder for list views; supports full-header and rows-only modes |
DamSettingsListView.vue | Sortable table list variant used on org-settings pages. subLabelField (default '') renders that field as a muted second line under the name (.table-list-suburl), for example the email under a person's name; when set and non-empty it replaces the first-column tooltip. Cells can be overridden with #cell-<field> slots |
DamSharingListView.vue | Sortable table list variant used on sharing/permissions pages |
SearchBreadCrumbs.vue | Compact breadcrumb strip shown inside folder pickers and search results; ellipsis-truncates long paths |
StaticPlanNotificationSettings.vue | Read-only notification settings UI shown to users whose plan does not allow editing |
DAM / Org-Settings Dialogs ​
Dialogs under dam/Dialogs/Org-Settings/, used from the organisation settings pages.
| Component | Description |
|---|---|
ActivateUserDialog.vue | Sets a new password when activating an org user; validates and submits via the users API |
ActivityLogsDialog.vue | Shows the last 30 days of user activity in a paginated table |
ImageCropper.vue | Tabbed upload-and-crop dialog for logos and profile images; supports direct upload and URL import tabs |
UserDialog.vue | Add or edit an external workspace user (name, email, role) |
WorkspaceOwnerDialog.vue | Transfers workspace ownership to another super-user; requires confirmation |
Portal Components ​
Components under dam/portals/ for configuring and managing brand portals.
| Component | Description |
|---|---|
AddEditBannerDialog.vue | Dialog to create or update a portal banner; accepts image upload, link URL, and active state |
AddEditTileDialog.vue | Dialog to create or update a portal tile; image upload, title, and link fields |
CNameGuideDialog.vue | Step-by-step CNAME setup guide for custom-domain portals; displays the required DNS record |
InvitePortalUserDialog.vue | Invite a new portal user or edit an existing one (name, email, permission level) |
PortalBannerList.vue | Renders, reorders, activates, edits, and deletes portal banners |
PortalBrandingTab.vue | Branding settings tab inside portal settings; logo, colours, custom domain, and white-label toggles |
PortalTileList.vue | Renders, reorders, activates, edits, and deletes portal tiles; includes a carousel-mode toggle |
PortalUpgradePlanSection.vue | Upgrade CTA shown when portal branding features are gated by the workspace plan |
StaticPlanWorkspaceBranding.vue | Read-only workspace branding preview displayed when the plan does not allow editing |
Dialog Components ​
General-purpose dialogs in components/dialogs/.
| Component | Description |
|---|---|
AccountSettingsMobileDialog.vue | Explains that account settings require the desktop version; shown on small screens |
AdvanceShareDialog.vue | "Update Advanced Settings" dialog for share links (expiry, download permissions, etc.) |
AnnouncementDialog.vue | Configurable announcement/notification modal with title and rich-text body |
AssetPreviewDialog.vue | Paging lightbox used by folder and collage detail pages. Props: assets, startAssetId, pagination (AssetPreviewPagination), searchPage, subFlag, hideDownload, loop (default true), showThumbnails (default true), preloadCount (default 2); v-model:dialog. Emits change(asset, index) 400 ms after the current asset settles and permissions. Arrows and thumbnail strip render only when total > 1. See Asset Preview Lightbox |
AssetQuickViewDialog.vue | Large lightbox preview of a single asset with full metadata, tags, and version info |
BulkPortalVisibilityDialog.vue | "Portals" dialog that publishes or unpublishes assets, folders or collages to portals; replaced PermissionDialog on every DAM surface (e6727808, 2026-09-07). Props (BulkPortalVisibilityProps): dialog, assetIds, folderIds, collectionIds, currentVisibility, isExistSubfolder, bulk (array props default [], booleans false). One row per portal (left border in the portal's primary_color) with Publish / Unpublish buttons that only stage the change; with coverage on, each row also shows a coverage label and bar, and the title shows "N asset(s) selected". "Apply to all subfolders" appears when showNestedApply. Save sends the staged changes; emits visibility-updated (BulkPortalVisibilityUpdatedEvent: assetIds, folderIds, collectionIds, publish, unpublish, nested) and close. Logic in useBulkPortalVisibilityDialog (see Composables) |
ConfirmationDialog.vue | Generic yes/no confirmation with configurable heading, message, and button labels |
CreateOrRenameDialog.vue | Shared dialog for creating new collages or renaming collages, folders, and assets |
CreatePortalDialog.vue | Creates a new brand portal; accepts a portal name with validation |
CustomFieldDialog.vue | Remove-option confirmation sub-dialog used inside the custom fields manager |
ExternalUserDialog.vue | Add or edit an external user (name, email); used from the folder sharing panel |
FileConversionDialog.vue | Download dialog with format conversion options; plan-gates certain formats |
LogoEditDialog.vue | Tabbed upload/crop dialog for the workspace logo (upload tab + URL tab) |
ManageCustomFields.vue | Full custom-fields manager dialog (add, edit, reorder, delete fields) |
PortalLimitDialog.vue | Shown when the workspace has reached its portal quota; prompts user to contact support |
SaveToCollage.vue | Adds selected assets to an existing collage or creates a new one |
ShareAssetDialog.vue | Tabbed sharing dialog (link visibility, download options, password, expiry) |
StaticBulkPortalVisibility.vue | Static placeholder (4 sample portals, Publish/Unpublish buttons, "Apply to all subfolders") shown inside BulkPortalVisibilityDialog with UpgradePlanSection when the plan does not allow portal visibility changes (canUpdateVisibility false) |
AddTags/AddMultipleTags.vue | Bulk tag-add dialog for multiple selected assets; wraps TagsBox and passes canAddTagsBulk, canRemoveTagsBulk and canRemoveCustomFieldsBulk from useAddMultipleTags (resolved with canAddTags / canRemoveTags / canRemoveCustomFields for the current workspace) |
AddTags/TagsBox.vue | Tag input UI with search autocomplete, common-tag suggestions, and chip display. Props canAdd, canRemove, canRemoveCustomFields (all default true) hide the input section and make tag / custom-field chips non-closable; with no tags and canAdd false it shows "This asset has no tags.". Emits update:tagsAdded |
FolderDialogs/FolderDialog.vue | Folder picker for move/copy operations; supports creating a new subfolder inline. Emits close, reset, copied(folders: FolderItem[]) (the destination folders), moved / movedMultiple(target?: MoveToFolder), move-files(folderId) and moveUncatg(folder). The search page reloads its asset hits 1200 ms after copied so the copy is indexed first. |
FolderDialogs/FolderDialogListItem.vue | Single folder row inside the folder picker; handles disabled state and nested breadcrumbs |
Search Components ​
Components used on the global search bar and the /search results page.
| Component | Description |
|---|---|
AddedFilterOption.vue | Active filter chip showing category, operator, and value; click opens inline menus to change operator or value |
GlobalSearch.vue | Header search bar with keyboard handling, instant type-ahead suggestions, and tab navigation |
SearchAssets.vue | Asset results section on the search results page (grid or list view) |
SearchCollages.vue | Collage results section on the search results page |
SearchEmptyState.vue | Zero-results empty state; configurable title and subtitle |
SearchFilter.vue | Two-level filter dropdown (pick category → pick value/operator); supports custom fields |
SearchFolders.vue | Folder results section on the search results page |
SearchMatchChip.vue | "Matched In" indicator for one SearchMatch (tag, custom_field, description). Full mode: a tag chip (linked to a tag search in a new tab), a Label: value chip, or an italic "In description" chip, each with a +N hover menu for the other matches. compact mode (grid cards): icon badge (tagsIcon / customFieldsIcon / infoIcon) with count 1 + others.length (no count for description). Hover opens after 120 ms and closes 150 ms after leaving; only one match menu is open app-wide, tracked in useState('search-match-open-menu') keyed by useId(), so moving to another chip closes the previous menu. Clicks are stopped so the row or card does not open |
SearchMatchDetails.vue | Menu body for SearchMatchChip. Props match, assetId?, othersOnly?; with othersOnly the title becomes "More matched tags" / "More matched custom fields" and the primary match is left out. Tag clicks send Amplitude TAG_CLICKED with source: 'search-match' |
SearchResultGroup.vue | Groups a labelled set of search hits using DamDetailListView or DamLibraryListView |
SearchTableHeader.vue | Sortable column header row for the search results list view |
SearchTabs.vue | Tab switcher between All / Assets / Collages / Folders; the "All" tab is available only inside GlobalSearch |
Shared Components ​
Reusable building blocks in components/shared/ used across multiple features.
| Component | Description |
|---|---|
AppDialog.vue | Base dialog shell (v-dialog + v-card). Props: size (sm 480, md 600 default, lg 800, xl 1120 px from MODAL_SIZE_WIDTHS), title, persistent, bodyClass, footerClass, hideClose; v-model for open state; emits close and after-leave. Slots: title, header-action, subheader, default (body), footer (the actions row renders only when the slot has non-empty content) and outside, rendered after the card inside v-dialog for content placed around it, such as the AssetPreviewDialog arrows. The close button carries aria-label="Close" |
ShareAssetsPasswordProtected.vue | Password entry form shown when a share link is password-protected |
SharedAssetsPage.vue | Full shared-assets page wrapper; handles the password gate and renders the asset grid once access is granted |
UpgradePlanSection.vue | Upgrade plan CTA block with a "Contact Support" button; shown when a feature is gated by plan |
ViewModeSwitcher.vue | Icon button group to switch between grid, mosaic, and list view modes |
Insights Components ​
Analytics visualisation components used on the Insights page.
| Component | Description |
|---|---|
InsightsGraph.vue | Renders a row of weekly bar-chart metric cards (views, downloads, etc.) using Bar.client |
InsightsTabGraph.vue | Tabbed chart panel; each tab shows a time-series metric chart with loading and no-data states |
Chart Components ​
| Component | Description |
|---|---|
Bar.client.vue | Client-only Chart.js bar chart wrapper (via vue-chartjs); accepts chartData, options, and plugins props |
Org-Settings Components ​
Tab content components used inside the account/organisation settings pages.
| Component | Description |
|---|---|
EmailNotificationsAlert.vue | Alert banner for notification-related status messages (e.g. notifications disabled by admin) |
NotificationSettingsTab.vue | Notification settings tab with system/email toggles per event type |
ProfileSettingsTab.vue | User profile settings tab; edits avatar, display name, email, and password |
Single Sign-On components (app/components/org-settings/Sso*.vue) ​
Used by the two Single Sign-On pages. See Single Sign-On for the flow.
| Component | Props | Emits | Behaviour |
|---|---|---|---|
SsoPageHeader.vue | modelValue: number, loading: boolean, pill?: { label, cls } | null | update:modelValue | Two tabs, Connection (0) and Sign-in activity (1), plus an optional status pill. The summary page passes Live (is-live) when enabled and Connected · off (is-off) when disabled. |
SsoSetupStepper.vue | current: number, editing: 'domains' | 'status' | null | select(step) | Renders SSO_SETUP_STEPS. A step is done when it is before current; in edit mode every step except the current one shows as done. Each step gets an aria label such as Connect, current step. |
SsoProviderLogo.vue | provider: string | — | Logo for microsoft, google, okta or other. |
SsoGuideDrawer.vue | guide: SsoProviderGuide | null, values: Record<SsoSpField, string>, copiedField: string | null | close, copy(key, value, label) | Side drawer holding SsoGuideFlow. Closes on Escape and on any document click outside the drawer, except clicks on .sso-guide-btn (the toggle). |
SsoGuideFlow.vue | steps: SsoGuideStep[], values, copiedField | copy(key, value, label) | Renders the provider's step-by-step guide. Action kinds map to verbs: open Go to, click Click, type Type, select Choose, paste Paste, skip Leave, upload Upload, check Wait for. Copy keys are guide:<target>; the label emitted is action.target, so the toast reads Reply URL copied to clipboard, not guide:Reply URL ... (176091e2). |
SsoActivityPanel.vue | events: SsoActivityEvent[], loading, loadingMore | loadMore | Table with columns Who, Outcome, Detail, When. Who is user_name, else email, else - (email shown as a second line when a name exists). Outcome chips: ok/signed_in Signed in (chip-published), blocked Blocked (chip-error), system System (chip-scheduled). Detail falls back to reason, then -. Dates before 1970 or invalid show -. Emits loadMore within 50 px of the bottom. |
Skeleton Loaders ​
| Component | Description |
|---|---|
skeleton-loaders/collage/CardSkeleton.vue | Repeating card-grid skeleton rows used while collage/asset grids are loading |
skeleton-loaders/collage/MosaicSkeleton.vue | Mosaic-layout skeleton tiles with varied sizes matching the mosaic grid pattern |
Table Components ​
| Component | Description |
|---|---|
table/SortTableHeaderColumn.vue | Single sortable table header column; shows sort arrow on hover and a spinner during async sort |
Theme / Settings Components ​
| Component | Description |
|---|---|
theme/settings/AccountSettingsLeftMenu.vue | Left navigation menu for the account settings layout; includes workspace selector and section links |
SVG Components ​
Static SVG illustration components in components/svg/. These are used as decorative elements and are not interactive.
| Component | Description |
|---|---|
EmailIcon.vue | Email envelope illustration used on email-confirmation screens |
FaviconIcon.vue | Collage favicon SVG |
LoginDecorLeft.vue | Left decorative element on the login/auth pages |
LoginDecorRight.vue | Right decorative element on the login/auth pages |
SupportIcon.vue | Support/help illustration icon |