Skip to content

Commit ca18556

Browse files
Merge pull request #7361 from getkirby/fix/items-sortable
fix!: Place sort handle inside `k-item` boundaries
2 parents 6062784 + 91f4830 commit ca18556

1 file changed

Lines changed: 97 additions & 79 deletions

File tree

panel/src/components/Collection/Item.vue

Lines changed: 97 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -11,67 +11,69 @@
1111
@click="onClick"
1212
@dragstart="$emit('drag', $event)"
1313
>
14-
<!-- Image -->
15-
<slot name="image">
16-
<k-item-image
17-
v-if="hasFigure"
18-
:image="image"
19-
:layout="layout"
20-
:width="width"
21-
/>
22-
</slot>
23-
2414
<!-- Sort handle -->
2515
<k-sort-handle v-if="sortable" class="k-item-sort-handle" tabindex="-1" />
2616

27-
<!-- Content -->
28-
<div class="k-item-content">
29-
<h3 class="k-item-title" :title="title(text)">
30-
<k-link
31-
v-if="link !== false && selecting !== true"
32-
:target="target"
33-
:to="link"
34-
>
17+
<div class="k-item-box">
18+
<!-- Image -->
19+
<slot name="image">
20+
<k-item-image
21+
v-if="hasFigure"
22+
:image="image"
23+
:layout="layout"
24+
:width="width"
25+
/>
26+
</slot>
27+
28+
<!-- Content -->
29+
<div class="k-item-content">
30+
<h3 class="k-item-title" :title="title(text)">
31+
<k-link
32+
v-if="link !== false && selecting !== true"
33+
:target="target"
34+
:to="link"
35+
>
36+
<!-- eslint-disable-next-line vue/no-v-html -->
37+
<span v-html="text ?? '&nbsp;'" />
38+
</k-link>
3539
<!-- eslint-disable-next-line vue/no-v-html -->
36-
<span v-html="text ?? '&nbsp;'" />
37-
</k-link>
40+
<span v-else v-html="text ?? '&nbsp;'" />
41+
</h3>
3842
<!-- eslint-disable-next-line vue/no-v-html -->
39-
<span v-else v-html="text ?? '&nbsp;'" />
40-
</h3>
41-
<!-- eslint-disable-next-line vue/no-v-html -->
42-
<p v-if="info" :title="title(info)" class="k-item-info" v-html="info" />
43-
</div>
44-
45-
<div
46-
v-if="buttons?.length || options || $slots.options || selecting"
47-
class="k-item-options"
48-
>
49-
<!-- Buttons -->
50-
<k-button
51-
v-for="button in buttons"
52-
:key="JSON.stringify(button)"
53-
v-bind="button"
54-
/>
43+
<p v-if="info" :title="title(info)" class="k-item-info" v-html="info" />
44+
</div>
5545

56-
<label v-if="selecting" class="k-item-options-checkbox" @click.stop>
57-
<input
58-
ref="selector"
59-
:checked="selected"
60-
:disabled="!selectable"
61-
:type="selectmode === 'single' ? 'radio' : 'checkbox'"
62-
@change="$emit('select', $event)"
46+
<div
47+
v-if="buttons?.length || options || $slots.options || selecting"
48+
class="k-item-options"
49+
>
50+
<!-- Buttons -->
51+
<k-button
52+
v-for="button in buttons"
53+
:key="JSON.stringify(button)"
54+
v-bind="button"
6355
/>
64-
</label>
6556

66-
<!-- Options -->
67-
<slot name="options">
68-
<k-options-dropdown
69-
v-if="options && !selecting"
70-
:options="options"
71-
class="k-item-options-dropdown"
72-
@option="onOption"
73-
/>
74-
</slot>
57+
<label v-if="selecting" class="k-item-options-checkbox" @click.stop>
58+
<input
59+
ref="selector"
60+
:checked="selected"
61+
:disabled="!selectable"
62+
:type="selectmode === 'single' ? 'radio' : 'checkbox'"
63+
@change="$emit('select', $event)"
64+
/>
65+
</label>
66+
67+
<!-- Options -->
68+
<slot name="options">
69+
<k-options-dropdown
70+
v-if="options && !selecting"
71+
:options="options"
72+
class="k-item-options-dropdown"
73+
@option="onOption"
74+
/>
75+
</slot>
76+
</div>
7577
</div>
7678
</div>
7779
</template>
@@ -199,15 +201,23 @@ export default {
199201
200202
.k-item {
201203
position: relative;
204+
min-height: var(--item-height);
205+
}
206+
.k-item-box:has(a:focus) {
207+
outline: 2px solid var(--color-focus);
208+
}
209+
.k-item:not(:hover):not(.k-sortable-fallback) .k-item-sort-handle {
210+
opacity: 0;
211+
}
212+
.k-item-box {
213+
position: relative;
214+
width: 100%;
215+
height: 100%;
202216
background: var(--item-color-back);
203217
box-shadow: var(--item-shadow);
204218
border-radius: var(--rounded);
205-
min-height: var(--item-height);
206219
container-type: inline-size;
207220
}
208-
.k-item:has(a:focus) {
209-
outline: 2px solid var(--color-focus);
210-
}
211221
212222
.k-item-content {
213223
line-height: 1.25;
@@ -240,16 +250,16 @@ export default {
240250
--button-width: var(--item-button-width);
241251
}
242252
243-
.k-item .k-sort-button {
244-
position: absolute;
245-
z-index: 2;
246-
}
247-
.k-item:not(:hover):not(.k-sortable-fallback) .k-sort-button {
248-
opacity: 0;
249-
}
250-
251253
/** List */
252254
.k-item[data-layout="list"] {
255+
--item-sort-button-width: calc(1.5rem + var(--spacing-1));
256+
display: flex;
257+
align-items: center;
258+
}
259+
.k-item[data-layout="list"]:has(.k-item-sort-handle) {
260+
margin-inline-start: calc(-1 * var(--item-sort-button-width));
261+
}
262+
.k-item[data-layout="list"] .k-item-box {
253263
--item-height: var(
254264
--field-input-height
255265
); /* TODO: change back to --height-md after input refactoring */
@@ -260,10 +270,14 @@ export default {
260270
align-items: center;
261271
grid-template-columns: 1fr auto;
262272
}
263-
.k-item[data-layout="list"][data-has-image="true"] {
273+
.k-item[data-layout="list"] .k-item-sort-handle {
274+
--button-width: var(--item-sort-button-width);
275+
--button-height: var(--item-height);
276+
}
277+
.k-item[data-layout="list"][data-has-image="true"] .k-item-box {
264278
grid-template-columns: var(--item-height) 1fr auto;
265279
}
266-
.k-item[data-layout="list"] .k-frame {
280+
.k-item[data-layout="list"] .k-item-image {
267281
--ratio: 1/1;
268282
border-start-start-radius: var(--rounded);
269283
border-end-start-radius: var(--rounded);
@@ -288,14 +302,10 @@ export default {
288302
flex-direction: column;
289303
}
290304
}
291-
.k-item[data-layout="list"] .k-sort-button {
292-
--button-width: calc(1.5rem + var(--spacing-1));
293-
--button-height: var(--item-height);
294-
left: calc(-1 * var(--button-width));
295-
}
296305
297306
/** Cardlet & cards */
298-
.k-item:is([data-layout="cardlets"], [data-layout="cards"]) .k-sort-button {
307+
.k-item:is([data-layout="cardlets"], [data-layout="cards"])
308+
.k-item-sort-handle {
299309
top: var(--spacing-2);
300310
inset-inline-start: var(--spacing-2);
301311
color: light-dark(var(--color-black), var(--color-white));
@@ -310,27 +320,34 @@ export default {
310320
}
311321
312322
.k-item:is([data-layout="cardlets"], [data-layout="cards"])
313-
.k-sort-button:hover {
323+
.k-item-sort-handle {
324+
position: absolute;
325+
z-index: 2;
326+
}
327+
.k-item:is([data-layout="cardlets"], [data-layout="cards"])
328+
.k-item-sort-handle:hover {
314329
background: hsla(0, 0%, light-dark(100%, 7%), 95%);
315330
}
316331
317332
/** Cardlet */
318333
.k-item[data-layout="cardlets"] {
319334
--item-height: var(--item-height-cardlet);
335+
}
336+
.k-item[data-layout="cardlets"] .k-item-box {
320337
display: grid;
321338
grid-template-areas:
322339
"content"
323340
"options";
324341
grid-template-columns: 1fr;
325342
grid-template-rows: 1fr var(--height-md);
326343
}
327-
.k-item[data-layout="cardlets"][data-has-image="true"] {
344+
.k-item[data-layout="cardlets"][data-has-image="true"] .k-item-box {
328345
grid-template-areas:
329346
"image content"
330347
"image options";
331348
grid-template-columns: minmax(0, var(--item-height)) 1fr;
332349
}
333-
.k-item[data-layout="cardlets"] .k-frame {
350+
.k-item[data-layout="cardlets"] .k-item-image {
334351
grid-area: image;
335352
border-start-start-radius: var(--rounded);
336353
border-end-start-radius: var(--rounded);
@@ -347,15 +364,16 @@ export default {
347364
}
348365
.k-item[data-layout="cardlets"] .k-item-options {
349366
grid-area: options;
367+
justify-content: flex-end;
350368
}
351369
352370
/** Card */
353-
.k-item[data-layout="cards"] {
371+
.k-item[data-layout="cards"] .k-item-box {
354372
display: flex;
355373
flex-direction: column;
356374
/* container-type: inline-size; */
357375
}
358-
.k-item[data-layout="cards"] .k-frame {
376+
.k-item[data-layout="cards"] .k-item-image {
359377
border-start-start-radius: var(--rounded);
360378
border-start-end-radius: var(--rounded);
361379
}
@@ -385,7 +403,7 @@ export default {
385403
}
386404
387405
/** Theme: disabled */
388-
.k-item[data-theme="disabled"] {
406+
.k-item[data-theme="disabled"] .k-item-box {
389407
background: transparent;
390408
box-shadow: none;
391409
outline: 1px solid var(--color-border);

0 commit comments

Comments
 (0)