@conduction/nextcloud-vue 0.1.0-beta.3 → 0.1.0-beta.4

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.
Files changed (152) hide show
  1. package/README.md +226 -226
  2. package/dist/nextcloud-vue.cjs.js +60455 -8755
  3. package/dist/nextcloud-vue.cjs.js.map +1 -1
  4. package/dist/nextcloud-vue.css +2062 -528
  5. package/dist/nextcloud-vue.esm.js +60411 -8731
  6. package/dist/nextcloud-vue.esm.js.map +1 -1
  7. package/package.json +75 -62
  8. package/src/components/CnActionsBar/CnActionsBar.vue +235 -225
  9. package/src/components/CnActionsBar/index.js +1 -1
  10. package/src/components/CnAdvancedFormDialog/CnAdvancedFormDialog.vue +579 -0
  11. package/src/components/CnAdvancedFormDialog/CnDataTab.vue +217 -0
  12. package/src/components/CnAdvancedFormDialog/CnMetadataTab.vue +121 -0
  13. package/src/components/CnAdvancedFormDialog/CnPropertiesTab.vue +418 -0
  14. package/src/components/CnAdvancedFormDialog/CnPropertyValueCell.vue +247 -0
  15. package/src/components/CnAdvancedFormDialog/index.js +1 -0
  16. package/src/components/CnCardGrid/CnCardGrid.vue +152 -152
  17. package/src/components/CnCardGrid/index.js +1 -1
  18. package/src/components/CnCellRenderer/CnCellRenderer.vue +132 -132
  19. package/src/components/CnCellRenderer/index.js +1 -1
  20. package/src/components/CnChartWidget/CnChartWidget.vue +320 -0
  21. package/src/components/CnChartWidget/index.js +1 -0
  22. package/src/components/CnConfigurationCard/CnConfigurationCard.vue +77 -77
  23. package/src/components/CnConfigurationCard/index.js +1 -1
  24. package/src/components/CnDashboardGrid/CnDashboardGrid.vue +225 -0
  25. package/src/components/CnDashboardGrid/index.js +1 -0
  26. package/src/components/CnDashboardPage/CnDashboardPage.vue +390 -0
  27. package/src/components/CnDashboardPage/index.js +1 -0
  28. package/src/components/CnDataTable/CnDataTable.vue +349 -349
  29. package/src/components/CnDataTable/index.js +1 -1
  30. package/src/components/CnDetailCard/CnDetailCard.vue +214 -0
  31. package/src/components/CnDetailCard/index.js +1 -0
  32. package/src/components/CnDetailPage/CnDetailPage.vue +281 -0
  33. package/src/components/CnDetailPage/index.js +1 -0
  34. package/src/components/CnFacetSidebar/CnFacetSidebar.vue +231 -223
  35. package/src/components/CnFacetSidebar/index.js +1 -1
  36. package/src/components/CnFilterBar/CnFilterBar.vue +152 -152
  37. package/src/components/CnFilterBar/index.js +1 -1
  38. package/src/components/CnIcon/CnIcon.vue +89 -89
  39. package/src/components/CnIcon/index.js +1 -1
  40. package/src/components/CnIndexPage/CnIndexPage.vue +874 -816
  41. package/src/components/CnIndexPage/index.js +1 -1
  42. package/src/components/CnIndexSidebar/CnIndexSidebar.vue +503 -484
  43. package/src/components/CnIndexSidebar/index.js +1 -1
  44. package/src/components/CnItemCard/CnItemCard.vue +132 -0
  45. package/src/components/CnItemCard/index.js +1 -0
  46. package/src/components/CnKpiGrid/CnKpiGrid.vue +89 -89
  47. package/src/components/CnKpiGrid/index.js +1 -1
  48. package/src/components/CnMassActionBar/CnMassActionBar.vue +160 -160
  49. package/src/components/CnMassActionBar/index.js +1 -1
  50. package/src/components/CnMassCopyDialog/CnMassCopyDialog.vue +320 -320
  51. package/src/components/CnMassCopyDialog/index.js +1 -1
  52. package/src/components/CnMassDeleteDialog/CnMassDeleteDialog.vue +238 -238
  53. package/src/components/CnMassDeleteDialog/index.js +1 -1
  54. package/src/components/CnMassExportDialog/CnMassExportDialog.vue +190 -190
  55. package/src/components/CnMassExportDialog/index.js +1 -1
  56. package/src/components/CnMassImportDialog/CnMassImportDialog.vue +491 -491
  57. package/src/components/CnMassImportDialog/index.js +1 -1
  58. package/src/components/CnNoteCard/CnNoteCard.vue +149 -0
  59. package/src/components/CnNoteCard/index.js +1 -0
  60. package/src/components/CnNotesCard/CnNotesCard.vue +413 -0
  61. package/src/components/CnNotesCard/index.js +1 -0
  62. package/src/components/CnObjectCard/CnObjectCard.vue +292 -292
  63. package/src/components/CnObjectCard/index.js +1 -1
  64. package/src/components/CnObjectSidebar/CnObjectSidebar.vue +876 -0
  65. package/src/components/CnObjectSidebar/index.js +1 -0
  66. package/src/components/CnPageHeader/CnPageHeader.vue +57 -57
  67. package/src/components/CnPageHeader/index.js +1 -1
  68. package/src/components/CnPagination/CnPagination.vue +252 -252
  69. package/src/components/CnPagination/index.js +1 -1
  70. package/src/components/CnRowActions/CnRowActions.vue +73 -73
  71. package/src/components/CnRowActions/index.js +1 -1
  72. package/src/components/CnSchemaFormDialog/CnSchemaConfigurationTab.vue +226 -0
  73. package/src/components/CnSchemaFormDialog/CnSchemaFormDialog.vue +787 -0
  74. package/src/components/CnSchemaFormDialog/CnSchemaPropertiesTab.vue +305 -0
  75. package/src/components/CnSchemaFormDialog/CnSchemaPropertyActions.vue +1398 -0
  76. package/src/components/CnSchemaFormDialog/CnSchemaSecurityTab.vue +236 -0
  77. package/src/components/CnSchemaFormDialog/index.js +1 -0
  78. package/src/components/CnSettingsCard/CnSettingsCard.vue +92 -92
  79. package/src/components/CnSettingsCard/index.js +1 -1
  80. package/src/components/CnSettingsSection/CnSettingsSection.vue +266 -266
  81. package/src/components/CnSettingsSection/index.js +1 -1
  82. package/src/components/CnStatsBlock/CnStatsBlock.vue +420 -366
  83. package/src/components/CnStatsBlock/index.js +1 -1
  84. package/src/components/CnStatusBadge/CnStatusBadge.vue +77 -77
  85. package/src/components/CnStatusBadge/index.js +1 -1
  86. package/src/components/CnTabbedFormDialog/CnTabbedFormDialog.vue +540 -0
  87. package/src/components/CnTabbedFormDialog/index.js +1 -0
  88. package/src/components/CnTasksCard/CnTasksCard.vue +373 -0
  89. package/src/components/CnTasksCard/index.js +1 -0
  90. package/src/components/CnTileWidget/CnTileWidget.vue +159 -0
  91. package/src/components/CnTileWidget/index.js +1 -0
  92. package/src/components/CnTimelineStages/CnTimelineStages.vue +292 -0
  93. package/src/components/CnTimelineStages/index.js +1 -0
  94. package/src/components/CnUserActionMenu/CnUserActionMenu.vue +435 -0
  95. package/src/components/CnUserActionMenu/index.js +1 -0
  96. package/src/components/CnVersionInfoCard/CnVersionInfoCard.vue +312 -312
  97. package/src/components/CnVersionInfoCard/index.js +1 -1
  98. package/src/components/CnWidgetRenderer/CnWidgetRenderer.vue +180 -0
  99. package/src/components/CnWidgetRenderer/index.js +1 -0
  100. package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +211 -0
  101. package/src/components/CnWidgetWrapper/index.js +1 -0
  102. package/src/components/index.js +43 -29
  103. package/src/composables/index.js +4 -3
  104. package/src/composables/useDashboardView.js +240 -0
  105. package/src/composables/useDetailView.js +289 -132
  106. package/src/composables/useListView.js +363 -362
  107. package/src/composables/useSubResource.js +142 -142
  108. package/src/constants/metadata.js +30 -30
  109. package/src/css/CnSchemaFormDialog.css +546 -0
  110. package/src/css/__sample_nextcloud_tokens.css +110 -0
  111. package/src/css/actions-bar.css +48 -48
  112. package/src/css/badge.css +51 -51
  113. package/src/css/card.css +128 -128
  114. package/src/css/dashboard.css +70 -0
  115. package/src/css/detail-page.css +168 -0
  116. package/src/css/detail.css +68 -68
  117. package/src/css/index-page.css +44 -32
  118. package/src/css/index-sidebar.css +193 -187
  119. package/src/css/index.css +16 -12
  120. package/src/css/layout.css +90 -90
  121. package/src/css/page-header.css +33 -33
  122. package/src/css/pagination.css +72 -72
  123. package/src/css/table.css +142 -142
  124. package/src/css/timeline-stages.css +218 -0
  125. package/src/css/utilities.css +46 -46
  126. package/src/index.js +72 -53
  127. package/src/store/createSubResourcePlugin.js +135 -135
  128. package/src/store/index.js +3 -3
  129. package/src/store/plugins/auditTrails.js +17 -17
  130. package/src/store/plugins/files.js +250 -186
  131. package/src/store/plugins/index.js +7 -5
  132. package/src/store/plugins/lifecycle.js +180 -180
  133. package/src/store/plugins/relations.js +68 -68
  134. package/src/store/plugins/search.js +372 -0
  135. package/src/store/plugins/selection.js +104 -0
  136. package/src/store/useObjectStore.js +829 -686
  137. package/src/types/auditTrail.d.ts +32 -32
  138. package/src/types/file.d.ts +23 -23
  139. package/src/types/index.d.ts +35 -35
  140. package/src/types/notification.d.ts +36 -36
  141. package/src/types/object.d.ts +40 -40
  142. package/src/types/organisation.d.ts +41 -41
  143. package/src/types/register.d.ts +25 -25
  144. package/src/types/schema.d.ts +39 -39
  145. package/src/types/shared.d.ts +79 -79
  146. package/src/types/source.d.ts +14 -14
  147. package/src/types/task.d.ts +31 -31
  148. package/src/utils/errors.js +96 -96
  149. package/src/utils/headers.js +68 -50
  150. package/src/utils/id.js +13 -0
  151. package/src/utils/index.js +3 -3
  152. package/src/utils/schema.js +422 -419
@@ -1,292 +1,292 @@
1
- <template>
2
- <div
3
- class="cn-object-card"
4
- :class="{ 'cn-object-card--selected': selected }"
5
- @click="$emit('click', object)">
6
- <!-- Selection checkbox -->
7
- <div v-if="selectable" class="cn-object-card__checkbox" @click.stop>
8
- <NcCheckboxRadioSwitch
9
- :checked="selected"
10
- @update:checked="$emit('select', object)" />
11
- </div>
12
-
13
- <!-- Card content -->
14
- <div class="cn-object-card__content">
15
- <!-- Header: image + title -->
16
- <div class="cn-object-card__header">
17
- <img
18
- v-if="imageUrl"
19
- :src="imageUrl"
20
- :alt="title"
21
- class="cn-object-card__image">
22
-
23
- <div class="cn-object-card__title-area">
24
- <h3 class="cn-object-card__title">{{ title }}</h3>
25
- <p v-if="description" class="cn-object-card__description">
26
- {{ truncatedDescription }}
27
- </p>
28
- </div>
29
- </div>
30
-
31
- <!-- Badges slot -->
32
- <div v-if="$scopedSlots.badges" class="cn-object-card__badges">
33
- <slot name="badges" :object="object" />
34
- </div>
35
-
36
- <!-- Metadata: visible properties as label:value pairs -->
37
- <div v-if="metadataFields.length > 0" class="cn-object-card__metadata">
38
- <slot name="metadata" :object="object" :fields="metadataFields">
39
- <div
40
- v-for="field in metadataFields"
41
- :key="field.key"
42
- class="cn-object-card__meta-item">
43
- <span class="cn-object-card__meta-label">{{ field.label }}</span>
44
- <CnCellRenderer
45
- :value="field.value"
46
- :property="field.property"
47
- :truncate="60" />
48
- </div>
49
- </slot>
50
- </div>
51
- </div>
52
-
53
- <!-- Actions slot -->
54
- <div v-if="$scopedSlots.actions" class="cn-object-card__actions" @click.stop>
55
- <slot name="actions" :object="object" />
56
- </div>
57
- </div>
58
- </template>
59
-
60
- <script>
61
- import { NcCheckboxRadioSwitch } from '@nextcloud/vue'
62
- import { CnCellRenderer } from '../CnCellRenderer/index.js'
63
- import { formatValue } from '../../utils/schema.js'
64
-
65
- /**
66
- * CnObjectCard — Schema-configuration-driven card for object display.
67
- *
68
- * Uses `schema.configuration` to determine which fields map to the card title,
69
- * description, and image. Remaining visible properties are shown as metadata.
70
- *
71
- * @example
72
- * <CnObjectCard :object="publication" :schema="pubSchema">
73
- * <template #actions="{ object }">
74
- * <NcActions><NcActionButton @click="edit(object)">Edit</NcActionButton></NcActions>
75
- * </template>
76
- * </CnObjectCard>
77
- */
78
- export default {
79
- name: 'CnObjectCard',
80
-
81
- components: {
82
- NcCheckboxRadioSwitch,
83
- CnCellRenderer,
84
- },
85
-
86
- props: {
87
- /** The object data */
88
- object: {
89
- type: Object,
90
- required: true,
91
- },
92
- /** Schema definition with properties and configuration */
93
- schema: {
94
- type: Object,
95
- required: true,
96
- },
97
- /** Whether this card is selected */
98
- selected: {
99
- type: Boolean,
100
- default: false,
101
- },
102
- /** Whether to show selection checkbox */
103
- selectable: {
104
- type: Boolean,
105
- default: false,
106
- },
107
- /** Maximum number of metadata fields to show */
108
- maxMetadata: {
109
- type: Number,
110
- default: 4,
111
- },
112
- },
113
-
114
- computed: {
115
- config() {
116
- return this.schema?.configuration || {}
117
- },
118
-
119
- title() {
120
- const field = this.config.objectNameField
121
- if (field && this.object[field]) {
122
- return String(this.object[field])
123
- }
124
- return this.object.title || this.object.name || this.object.id || '—'
125
- },
126
-
127
- description() {
128
- const field = this.config.objectDescriptionField
129
- if (field && this.object[field]) {
130
- return String(this.object[field])
131
- }
132
- return null
133
- },
134
-
135
- truncatedDescription() {
136
- if (!this.description) return null
137
- if (this.description.length > 120) {
138
- return this.description.substring(0, 120) + '...'
139
- }
140
- return this.description
141
- },
142
-
143
- imageUrl() {
144
- const field = this.config.objectImageField
145
- if (field && this.object[field]) {
146
- return this.object[field]
147
- }
148
- return null
149
- },
150
-
151
- /** Fields excluded from metadata (already shown as title/desc/image) */
152
- configFields() {
153
- return [
154
- this.config.objectNameField,
155
- this.config.objectDescriptionField,
156
- this.config.objectSummaryField,
157
- this.config.objectImageField,
158
- ].filter(Boolean)
159
- },
160
-
161
- /** Remaining visible properties for the metadata section */
162
- metadataFields() {
163
- if (!this.schema?.properties) return []
164
-
165
- return Object.entries(this.schema.properties)
166
- .filter(([key, prop]) => {
167
- if (this.configFields.includes(key)) return false
168
- if (prop.visible === false) return false
169
- if (prop.type === 'object') return false
170
- if (prop.format === 'markdown') return false
171
- return true
172
- })
173
- .sort(([, a], [, b]) => {
174
- const orderA = typeof a.order === 'number' ? a.order : Infinity
175
- const orderB = typeof b.order === 'number' ? b.order : Infinity
176
- return orderA - orderB
177
- })
178
- .slice(0, this.maxMetadata)
179
- .map(([key, prop]) => ({
180
- key,
181
- label: prop.title || key,
182
- value: this.object[key],
183
- property: prop,
184
- }))
185
- },
186
- },
187
-
188
- methods: {
189
- formatValue,
190
- },
191
- }
192
- </script>
193
-
194
- <style scoped>
195
- .cn-object-card {
196
- display: flex;
197
- gap: 12px;
198
- padding: 16px;
199
- background: var(--color-main-background);
200
- border: 1px solid var(--color-border);
201
- border-radius: var(--border-radius-large, 10px);
202
- cursor: pointer;
203
- transition: box-shadow 0.2s ease, border-color 0.2s ease;
204
- }
205
-
206
- .cn-object-card:hover {
207
- border-color: var(--color-primary-element);
208
- box-shadow: 0 2px 8px var(--color-box-shadow);
209
- }
210
-
211
- .cn-object-card--selected {
212
- border-color: var(--color-primary-element);
213
- background: var(--color-primary-element-light);
214
- }
215
-
216
- .cn-object-card__checkbox {
217
- flex-shrink: 0;
218
- padding-top: 2px;
219
- }
220
-
221
- .cn-object-card__content {
222
- flex: 1;
223
- min-width: 0;
224
- }
225
-
226
- .cn-object-card__header {
227
- display: flex;
228
- gap: 12px;
229
- align-items: flex-start;
230
- }
231
-
232
- .cn-object-card__image {
233
- width: 48px;
234
- height: 48px;
235
- border-radius: var(--border-radius);
236
- object-fit: cover;
237
- flex-shrink: 0;
238
- }
239
-
240
- .cn-object-card__title-area {
241
- flex: 1;
242
- min-width: 0;
243
- }
244
-
245
- .cn-object-card__title {
246
- margin: 0;
247
- font-size: 16px;
248
- font-weight: 600;
249
- line-height: 1.3;
250
- overflow: hidden;
251
- text-overflow: ellipsis;
252
- white-space: nowrap;
253
- }
254
-
255
- .cn-object-card__description {
256
- margin: 4px 0 0;
257
- font-size: 13px;
258
- color: var(--color-text-maxcontrast);
259
- line-height: 1.4;
260
- }
261
-
262
- .cn-object-card__badges {
263
- margin-top: 8px;
264
- }
265
-
266
- .cn-object-card__metadata {
267
- display: grid;
268
- grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
269
- gap: 8px;
270
- margin-top: 12px;
271
- padding-top: 12px;
272
- border-top: 1px solid var(--color-border);
273
- }
274
-
275
- .cn-object-card__meta-item {
276
- display: flex;
277
- flex-direction: column;
278
- gap: 2px;
279
- }
280
-
281
- .cn-object-card__meta-label {
282
- font-size: 11px;
283
- font-weight: 500;
284
- color: var(--color-text-maxcontrast);
285
- text-transform: uppercase;
286
- letter-spacing: 0.3px;
287
- }
288
-
289
- .cn-object-card__actions {
290
- flex-shrink: 0;
291
- }
292
- </style>
1
+ <template>
2
+ <div
3
+ class="cn-object-card"
4
+ :class="{ 'cn-object-card--selected': selected }"
5
+ @click="$emit('click', object)">
6
+ <!-- Selection checkbox -->
7
+ <div v-if="selectable" class="cn-object-card__checkbox" @click.stop>
8
+ <NcCheckboxRadioSwitch
9
+ :checked="selected"
10
+ @update:checked="$emit('select', object)" />
11
+ </div>
12
+
13
+ <!-- Card content -->
14
+ <div class="cn-object-card__content">
15
+ <!-- Header: image + title -->
16
+ <div class="cn-object-card__header">
17
+ <img
18
+ v-if="imageUrl"
19
+ :src="imageUrl"
20
+ :alt="title"
21
+ class="cn-object-card__image">
22
+
23
+ <div class="cn-object-card__title-area">
24
+ <h3 class="cn-object-card__title">{{ title }}</h3>
25
+ <p v-if="description" class="cn-object-card__description">
26
+ {{ truncatedDescription }}
27
+ </p>
28
+ </div>
29
+ </div>
30
+
31
+ <!-- Badges slot -->
32
+ <div v-if="$scopedSlots.badges" class="cn-object-card__badges">
33
+ <slot name="badges" :object="object" />
34
+ </div>
35
+
36
+ <!-- Metadata: visible properties as label:value pairs -->
37
+ <div v-if="metadataFields.length > 0" class="cn-object-card__metadata">
38
+ <slot name="metadata" :object="object" :fields="metadataFields">
39
+ <div
40
+ v-for="field in metadataFields"
41
+ :key="field.key"
42
+ class="cn-object-card__meta-item">
43
+ <span class="cn-object-card__meta-label">{{ field.label }}</span>
44
+ <CnCellRenderer
45
+ :value="field.value"
46
+ :property="field.property"
47
+ :truncate="60" />
48
+ </div>
49
+ </slot>
50
+ </div>
51
+ </div>
52
+
53
+ <!-- Actions slot -->
54
+ <div v-if="$scopedSlots.actions" class="cn-object-card__actions" @click.stop>
55
+ <slot name="actions" :object="object" />
56
+ </div>
57
+ </div>
58
+ </template>
59
+
60
+ <script>
61
+ import { NcCheckboxRadioSwitch } from '@nextcloud/vue'
62
+ import { CnCellRenderer } from '../CnCellRenderer/index.js'
63
+ import { formatValue } from '../../utils/schema.js'
64
+
65
+ /**
66
+ * CnObjectCard — Schema-configuration-driven card for object display.
67
+ *
68
+ * Uses `schema.configuration` to determine which fields map to the card title,
69
+ * description, and image. Remaining visible properties are shown as metadata.
70
+ *
71
+ * @example
72
+ * <CnObjectCard :object="publication" :schema="pubSchema">
73
+ * <template #actions="{ object }">
74
+ * <NcActions><NcActionButton @click="edit(object)">Edit</NcActionButton></NcActions>
75
+ * </template>
76
+ * </CnObjectCard>
77
+ */
78
+ export default {
79
+ name: 'CnObjectCard',
80
+
81
+ components: {
82
+ NcCheckboxRadioSwitch,
83
+ CnCellRenderer,
84
+ },
85
+
86
+ props: {
87
+ /** The object data */
88
+ object: {
89
+ type: Object,
90
+ required: true,
91
+ },
92
+ /** Schema definition with properties and configuration */
93
+ schema: {
94
+ type: Object,
95
+ required: true,
96
+ },
97
+ /** Whether this card is selected */
98
+ selected: {
99
+ type: Boolean,
100
+ default: false,
101
+ },
102
+ /** Whether to show selection checkbox */
103
+ selectable: {
104
+ type: Boolean,
105
+ default: false,
106
+ },
107
+ /** Maximum number of metadata fields to show */
108
+ maxMetadata: {
109
+ type: Number,
110
+ default: 4,
111
+ },
112
+ },
113
+
114
+ computed: {
115
+ config() {
116
+ return this.schema?.configuration || {}
117
+ },
118
+
119
+ title() {
120
+ const field = this.config.objectNameField
121
+ if (field && this.object[field]) {
122
+ return String(this.object[field])
123
+ }
124
+ return this.object.title || this.object.name || this.object.id || '—'
125
+ },
126
+
127
+ description() {
128
+ const field = this.config.objectDescriptionField
129
+ if (field && this.object[field]) {
130
+ return String(this.object[field])
131
+ }
132
+ return null
133
+ },
134
+
135
+ truncatedDescription() {
136
+ if (!this.description) return null
137
+ if (this.description.length > 120) {
138
+ return this.description.substring(0, 120) + '...'
139
+ }
140
+ return this.description
141
+ },
142
+
143
+ imageUrl() {
144
+ const field = this.config.objectImageField
145
+ if (field && this.object[field]) {
146
+ return this.object[field]
147
+ }
148
+ return null
149
+ },
150
+
151
+ /** Fields excluded from metadata (already shown as title/desc/image) */
152
+ configFields() {
153
+ return [
154
+ this.config.objectNameField,
155
+ this.config.objectDescriptionField,
156
+ this.config.objectSummaryField,
157
+ this.config.objectImageField,
158
+ ].filter(Boolean)
159
+ },
160
+
161
+ /** Remaining visible properties for the metadata section */
162
+ metadataFields() {
163
+ if (!this.schema?.properties) return []
164
+
165
+ return Object.entries(this.schema.properties)
166
+ .filter(([key, prop]) => {
167
+ if (this.configFields.includes(key)) return false
168
+ if (prop.visible === false) return false
169
+ if (prop.type === 'object') return false
170
+ if (prop.format === 'markdown') return false
171
+ return true
172
+ })
173
+ .sort(([, a], [, b]) => {
174
+ const orderA = typeof a.order === 'number' ? a.order : Infinity
175
+ const orderB = typeof b.order === 'number' ? b.order : Infinity
176
+ return orderA - orderB
177
+ })
178
+ .slice(0, this.maxMetadata)
179
+ .map(([key, prop]) => ({
180
+ key,
181
+ label: prop.title || key,
182
+ value: this.object[key],
183
+ property: prop,
184
+ }))
185
+ },
186
+ },
187
+
188
+ methods: {
189
+ formatValue,
190
+ },
191
+ }
192
+ </script>
193
+
194
+ <style scoped>
195
+ .cn-object-card {
196
+ display: flex;
197
+ gap: 12px;
198
+ padding: 16px;
199
+ background: var(--color-main-background);
200
+ border: 1px solid var(--color-border);
201
+ border-radius: var(--border-radius-large, 10px);
202
+ cursor: pointer;
203
+ transition: box-shadow 0.2s ease, border-color 0.2s ease;
204
+ }
205
+
206
+ .cn-object-card:hover {
207
+ border-color: var(--color-primary-element);
208
+ box-shadow: 0 2px 8px var(--color-box-shadow);
209
+ }
210
+
211
+ .cn-object-card--selected {
212
+ border-color: var(--color-primary-element);
213
+ background: var(--color-primary-element-light);
214
+ }
215
+
216
+ .cn-object-card__checkbox {
217
+ flex-shrink: 0;
218
+ padding-top: 2px;
219
+ }
220
+
221
+ .cn-object-card__content {
222
+ flex: 1;
223
+ min-width: 0;
224
+ }
225
+
226
+ .cn-object-card__header {
227
+ display: flex;
228
+ gap: 12px;
229
+ align-items: flex-start;
230
+ }
231
+
232
+ .cn-object-card__image {
233
+ width: 48px;
234
+ height: 48px;
235
+ border-radius: var(--border-radius);
236
+ object-fit: cover;
237
+ flex-shrink: 0;
238
+ }
239
+
240
+ .cn-object-card__title-area {
241
+ flex: 1;
242
+ min-width: 0;
243
+ }
244
+
245
+ .cn-object-card__title {
246
+ margin: 0;
247
+ font-size: 16px;
248
+ font-weight: 600;
249
+ line-height: 1.3;
250
+ overflow: hidden;
251
+ text-overflow: ellipsis;
252
+ white-space: nowrap;
253
+ }
254
+
255
+ .cn-object-card__description {
256
+ margin: 4px 0 0;
257
+ font-size: 13px;
258
+ color: var(--color-text-maxcontrast);
259
+ line-height: 1.4;
260
+ }
261
+
262
+ .cn-object-card__badges {
263
+ margin-top: 8px;
264
+ }
265
+
266
+ .cn-object-card__metadata {
267
+ display: grid;
268
+ grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
269
+ gap: 8px;
270
+ margin-top: 12px;
271
+ padding-top: 12px;
272
+ border-top: 1px solid var(--color-border);
273
+ }
274
+
275
+ .cn-object-card__meta-item {
276
+ display: flex;
277
+ flex-direction: column;
278
+ gap: 2px;
279
+ }
280
+
281
+ .cn-object-card__meta-label {
282
+ font-size: 11px;
283
+ font-weight: 500;
284
+ color: var(--color-text-maxcontrast);
285
+ text-transform: uppercase;
286
+ letter-spacing: 0.3px;
287
+ }
288
+
289
+ .cn-object-card__actions {
290
+ flex-shrink: 0;
291
+ }
292
+ </style>
@@ -1 +1 @@
1
- export { default as CnObjectCard } from './CnObjectCard.vue'
1
+ export { default as CnObjectCard } from './CnObjectCard.vue'