@conduction/nextcloud-vue 0.1.0-beta.2 → 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 (153) hide show
  1. package/README.md +226 -226
  2. package/css/index.css +5 -0
  3. package/dist/nextcloud-vue.cjs.js +60455 -8755
  4. package/dist/nextcloud-vue.cjs.js.map +1 -1
  5. package/dist/nextcloud-vue.css +2062 -528
  6. package/dist/nextcloud-vue.esm.js +60411 -8731
  7. package/dist/nextcloud-vue.esm.js.map +1 -1
  8. package/package.json +75 -61
  9. package/src/components/CnActionsBar/CnActionsBar.vue +235 -225
  10. package/src/components/CnActionsBar/index.js +1 -1
  11. package/src/components/CnAdvancedFormDialog/CnAdvancedFormDialog.vue +579 -0
  12. package/src/components/CnAdvancedFormDialog/CnDataTab.vue +217 -0
  13. package/src/components/CnAdvancedFormDialog/CnMetadataTab.vue +121 -0
  14. package/src/components/CnAdvancedFormDialog/CnPropertiesTab.vue +418 -0
  15. package/src/components/CnAdvancedFormDialog/CnPropertyValueCell.vue +247 -0
  16. package/src/components/CnAdvancedFormDialog/index.js +1 -0
  17. package/src/components/CnCardGrid/CnCardGrid.vue +152 -152
  18. package/src/components/CnCardGrid/index.js +1 -1
  19. package/src/components/CnCellRenderer/CnCellRenderer.vue +132 -132
  20. package/src/components/CnCellRenderer/index.js +1 -1
  21. package/src/components/CnChartWidget/CnChartWidget.vue +320 -0
  22. package/src/components/CnChartWidget/index.js +1 -0
  23. package/src/components/CnConfigurationCard/CnConfigurationCard.vue +77 -77
  24. package/src/components/CnConfigurationCard/index.js +1 -1
  25. package/src/components/CnDashboardGrid/CnDashboardGrid.vue +225 -0
  26. package/src/components/CnDashboardGrid/index.js +1 -0
  27. package/src/components/CnDashboardPage/CnDashboardPage.vue +390 -0
  28. package/src/components/CnDashboardPage/index.js +1 -0
  29. package/src/components/CnDataTable/CnDataTable.vue +349 -349
  30. package/src/components/CnDataTable/index.js +1 -1
  31. package/src/components/CnDetailCard/CnDetailCard.vue +214 -0
  32. package/src/components/CnDetailCard/index.js +1 -0
  33. package/src/components/CnDetailPage/CnDetailPage.vue +281 -0
  34. package/src/components/CnDetailPage/index.js +1 -0
  35. package/src/components/CnFacetSidebar/CnFacetSidebar.vue +231 -223
  36. package/src/components/CnFacetSidebar/index.js +1 -1
  37. package/src/components/CnFilterBar/CnFilterBar.vue +152 -152
  38. package/src/components/CnFilterBar/index.js +1 -1
  39. package/src/components/CnIcon/CnIcon.vue +89 -89
  40. package/src/components/CnIcon/index.js +1 -1
  41. package/src/components/CnIndexPage/CnIndexPage.vue +874 -816
  42. package/src/components/CnIndexPage/index.js +1 -1
  43. package/src/components/CnIndexSidebar/CnIndexSidebar.vue +503 -484
  44. package/src/components/CnIndexSidebar/index.js +1 -1
  45. package/src/components/CnItemCard/CnItemCard.vue +132 -0
  46. package/src/components/CnItemCard/index.js +1 -0
  47. package/src/components/CnKpiGrid/CnKpiGrid.vue +89 -89
  48. package/src/components/CnKpiGrid/index.js +1 -1
  49. package/src/components/CnMassActionBar/CnMassActionBar.vue +160 -160
  50. package/src/components/CnMassActionBar/index.js +1 -1
  51. package/src/components/CnMassCopyDialog/CnMassCopyDialog.vue +320 -320
  52. package/src/components/CnMassCopyDialog/index.js +1 -1
  53. package/src/components/CnMassDeleteDialog/CnMassDeleteDialog.vue +238 -238
  54. package/src/components/CnMassDeleteDialog/index.js +1 -1
  55. package/src/components/CnMassExportDialog/CnMassExportDialog.vue +190 -190
  56. package/src/components/CnMassExportDialog/index.js +1 -1
  57. package/src/components/CnMassImportDialog/CnMassImportDialog.vue +491 -491
  58. package/src/components/CnMassImportDialog/index.js +1 -1
  59. package/src/components/CnNoteCard/CnNoteCard.vue +149 -0
  60. package/src/components/CnNoteCard/index.js +1 -0
  61. package/src/components/CnNotesCard/CnNotesCard.vue +413 -0
  62. package/src/components/CnNotesCard/index.js +1 -0
  63. package/src/components/CnObjectCard/CnObjectCard.vue +292 -292
  64. package/src/components/CnObjectCard/index.js +1 -1
  65. package/src/components/CnObjectSidebar/CnObjectSidebar.vue +876 -0
  66. package/src/components/CnObjectSidebar/index.js +1 -0
  67. package/src/components/CnPageHeader/CnPageHeader.vue +57 -57
  68. package/src/components/CnPageHeader/index.js +1 -1
  69. package/src/components/CnPagination/CnPagination.vue +252 -252
  70. package/src/components/CnPagination/index.js +1 -1
  71. package/src/components/CnRowActions/CnRowActions.vue +73 -73
  72. package/src/components/CnRowActions/index.js +1 -1
  73. package/src/components/CnSchemaFormDialog/CnSchemaConfigurationTab.vue +226 -0
  74. package/src/components/CnSchemaFormDialog/CnSchemaFormDialog.vue +787 -0
  75. package/src/components/CnSchemaFormDialog/CnSchemaPropertiesTab.vue +305 -0
  76. package/src/components/CnSchemaFormDialog/CnSchemaPropertyActions.vue +1398 -0
  77. package/src/components/CnSchemaFormDialog/CnSchemaSecurityTab.vue +236 -0
  78. package/src/components/CnSchemaFormDialog/index.js +1 -0
  79. package/src/components/CnSettingsCard/CnSettingsCard.vue +92 -92
  80. package/src/components/CnSettingsCard/index.js +1 -1
  81. package/src/components/CnSettingsSection/CnSettingsSection.vue +266 -266
  82. package/src/components/CnSettingsSection/index.js +1 -1
  83. package/src/components/CnStatsBlock/CnStatsBlock.vue +420 -366
  84. package/src/components/CnStatsBlock/index.js +1 -1
  85. package/src/components/CnStatusBadge/CnStatusBadge.vue +77 -77
  86. package/src/components/CnStatusBadge/index.js +1 -1
  87. package/src/components/CnTabbedFormDialog/CnTabbedFormDialog.vue +540 -0
  88. package/src/components/CnTabbedFormDialog/index.js +1 -0
  89. package/src/components/CnTasksCard/CnTasksCard.vue +373 -0
  90. package/src/components/CnTasksCard/index.js +1 -0
  91. package/src/components/CnTileWidget/CnTileWidget.vue +159 -0
  92. package/src/components/CnTileWidget/index.js +1 -0
  93. package/src/components/CnTimelineStages/CnTimelineStages.vue +292 -0
  94. package/src/components/CnTimelineStages/index.js +1 -0
  95. package/src/components/CnUserActionMenu/CnUserActionMenu.vue +435 -0
  96. package/src/components/CnUserActionMenu/index.js +1 -0
  97. package/src/components/CnVersionInfoCard/CnVersionInfoCard.vue +312 -312
  98. package/src/components/CnVersionInfoCard/index.js +1 -1
  99. package/src/components/CnWidgetRenderer/CnWidgetRenderer.vue +180 -0
  100. package/src/components/CnWidgetRenderer/index.js +1 -0
  101. package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +211 -0
  102. package/src/components/CnWidgetWrapper/index.js +1 -0
  103. package/src/components/index.js +43 -29
  104. package/src/composables/index.js +4 -3
  105. package/src/composables/useDashboardView.js +240 -0
  106. package/src/composables/useDetailView.js +289 -132
  107. package/src/composables/useListView.js +363 -153
  108. package/src/composables/useSubResource.js +142 -142
  109. package/src/constants/metadata.js +30 -30
  110. package/src/css/CnSchemaFormDialog.css +546 -0
  111. package/src/css/__sample_nextcloud_tokens.css +110 -0
  112. package/src/css/actions-bar.css +48 -48
  113. package/src/css/badge.css +51 -51
  114. package/src/css/card.css +128 -128
  115. package/src/css/dashboard.css +70 -0
  116. package/src/css/detail-page.css +168 -0
  117. package/src/css/detail.css +68 -68
  118. package/src/css/index-page.css +44 -32
  119. package/src/css/index-sidebar.css +193 -187
  120. package/src/css/index.css +16 -12
  121. package/src/css/layout.css +90 -90
  122. package/src/css/page-header.css +33 -33
  123. package/src/css/pagination.css +72 -72
  124. package/src/css/table.css +142 -142
  125. package/src/css/timeline-stages.css +218 -0
  126. package/src/css/utilities.css +46 -46
  127. package/src/index.js +72 -53
  128. package/src/store/createSubResourcePlugin.js +135 -135
  129. package/src/store/index.js +3 -3
  130. package/src/store/plugins/auditTrails.js +17 -17
  131. package/src/store/plugins/files.js +250 -186
  132. package/src/store/plugins/index.js +7 -5
  133. package/src/store/plugins/lifecycle.js +180 -180
  134. package/src/store/plugins/relations.js +68 -68
  135. package/src/store/plugins/search.js +372 -0
  136. package/src/store/plugins/selection.js +104 -0
  137. package/src/store/useObjectStore.js +829 -686
  138. package/src/types/auditTrail.d.ts +32 -32
  139. package/src/types/file.d.ts +23 -23
  140. package/src/types/index.d.ts +35 -35
  141. package/src/types/notification.d.ts +36 -36
  142. package/src/types/object.d.ts +40 -40
  143. package/src/types/organisation.d.ts +41 -41
  144. package/src/types/register.d.ts +25 -25
  145. package/src/types/schema.d.ts +39 -39
  146. package/src/types/shared.d.ts +79 -79
  147. package/src/types/source.d.ts +14 -14
  148. package/src/types/task.d.ts +31 -31
  149. package/src/utils/errors.js +96 -96
  150. package/src/utils/headers.js +68 -50
  151. package/src/utils/id.js +13 -0
  152. package/src/utils/index.js +3 -3
  153. 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'