Skip to content

Commit f4b8d0f

Browse files
committed
refactor!: revamp CCard title section
This commit refactors the title section of the `CCard` component with the following changes: - Moves the close button into the title section, so that the title no longer lies behind it or is obscured by the button. - Also moves the `title-append` slot into the title section, where it now directly follows the title (`title`). - Changes the permissible values for the `titlePosition` property to `start` and `end` (based on Vuetify's `justify-...` logic, e.g., `justify-start` or `justify-end`). BREAKING CHANGE: The behavior of the `title-append` slot and the `titlePosition` property have been changed. - **`title-append` slot:** The `title-append` slot is now located immediately to the right of the title text. If the content of this slot should continue to be aligned to the right edge of the entire title area (as was previously potentially the case), this must now be done manually by using a `v-spacer`. - **`titlePosition`:** The `titlePosition` property now accepts the values `'start'` or `'end'` to fit with vuetify `justify-content-...`.
1 parent 9b07fdb commit f4b8d0f

File tree

2 files changed

+64
-35
lines changed

2 files changed

+64
-35
lines changed

src/components/CCard.vue

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,29 +21,44 @@
2121
></v-progress-linear>
2222
</template>
2323

24-
<div
25-
v-if="closable || slots['title-append']"
26-
class="position-absolute pa-4 pa-md-6 d-flex align-center"
27-
style="top: 0; right: 0"
28-
>
29-
<slot name="title-append"> </slot>
30-
31-
<!-- Close button -->
32-
<v-btn
33-
v-if="closable"
34-
:icon="mdiWindowClose"
35-
variant="text"
36-
color="on-surface"
37-
@click="emit('close')"
38-
></v-btn>
39-
</div>
40-
4124
<v-card-title
42-
v-if="title"
43-
class="pt-0 pb-0 px-6 px-md-8 text-h6"
44-
:class="titleClass"
25+
v-if="title || slots['title-append'] || closable"
26+
class="pt-0 pb-0 px-6 px-md-8 text-h6 d-flex align-center"
27+
:class="vTitleClass"
4528
>
46-
{{ title }}
29+
<!-- Placeholder to make sure the title is centered if the closable icon is visible -->
30+
<div
31+
v-if="closable && titlePosition === 'center'"
32+
class="mr-2"
33+
style="width: 48px"
34+
></div>
35+
36+
<div
37+
v-if="title || slots['title-append']"
38+
class="d-flex align-center w-100"
39+
:class="titleClass"
40+
>
41+
<div v-if="title" :class="wrapTitle ? '' : 'text-truncate'">
42+
{{ title }}
43+
</div>
44+
45+
<slot name="title-append"> </slot>
46+
</div>
47+
48+
<template v-if="closable">
49+
<!-- Placeholder -->
50+
<div style="width: 48px" class="ml-2"></div>
51+
52+
<!-- Close button -->
53+
<v-btn
54+
:icon="mdiWindowClose"
55+
variant="text"
56+
color="on-surface"
57+
class="position-absolute"
58+
style="right: 20px"
59+
@click="emit('close')"
60+
></v-btn>
61+
</template>
4762
</v-card-title>
4863

4964
<v-card-subtitle
@@ -130,7 +145,7 @@ const props = withDefaults(
130145
/**
131146
* The position of the title.
132147
*/
133-
titlePosition?: "center" | "left" | "right";
148+
titlePosition?: "center" | "start" | "end";
134149
135150
/**
136151
* The size of the title.
@@ -207,7 +222,7 @@ const props = withDefaults(
207222
}>(),
208223
{
209224
title: undefined,
210-
titlePosition: "left",
225+
titlePosition: "start",
211226
titleSize: "normal",
212227
wrapTitle: undefined,
213228
subtitle: undefined,
@@ -244,10 +259,10 @@ const cardClass = computed<string>(() => {
244259
});
245260
246261
/**
247-
* Computes the classes for the title component.
262+
* Computes the classes for the v-card-title component.
248263
*/
249-
const titleClass = computed<string>(() => {
250-
let classes = "text-" + props.titlePosition;
264+
const vTitleClass = computed<string>(() => {
265+
let classes = "";
251266
252267
if (props.titleSize && props.titleSize !== "normal")
253268
classes += " " + props.titleSize;
@@ -262,6 +277,17 @@ const titleClass = computed<string>(() => {
262277
return classes;
263278
});
264279
280+
/**
281+
* Computes the classes for the title component. (in which the title and title-append are)
282+
*/
283+
const titleClass = computed<string>(() => {
284+
let classes = "justify-" + props.titlePosition;
285+
286+
if (!props.wrapTitle) classes += " text-truncate";
287+
288+
return classes;
289+
});
290+
265291
/**
266292
* Whether scrolling of the content is currently enabled.
267293
*

stories/CCard.stories.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const meta: Meta<typeof CCard> = {
1515
},
1616
titlePosition: {
1717
control: "radio",
18-
options: ["center", "left", "right"],
18+
options: ["center", "start", "end"],
1919
},
2020
wrapTitle: {
2121
control: "boolean",
@@ -70,7 +70,7 @@ type Story = StoryObj<typeof meta>;
7070
export const Default: Story = {
7171
args: {
7272
title: "Card title",
73-
titlePosition: "left",
73+
titlePosition: "start",
7474
subtitle: "Card subtitle",
7575
loading: false,
7676
},
@@ -354,18 +354,20 @@ export const Disabled: Story = {
354354

355355
export const TitleAppendSlot: Story = {
356356
args: {
357-
title: "Card",
357+
title: "Card with a longer title",
358+
closable: true,
358359
},
359360
render: createStorybookRender({
360361
components: { CCard },
361362
template: `
362363
<c-card v-bind='args' class="ma-5">
363364
<template #title-append>
365+
<v-spacer></v-spacer>
364366
<v-btn
365-
variant="outlined"
366-
color="primary"
367+
variant="outlined"
368+
color="primary"
367369
>
368-
Close
370+
Action
369371
</v-btn>
370372
</template>
371373
@@ -378,11 +380,12 @@ export const TitleAppendSlot: Story = {
378380
parameters: createStorybookParameters({
379381
slotTemplate: `
380382
<template #title-append>
383+
<v-spacer></v-spacer>
381384
<v-btn
382-
variant="outlined"
383-
color="primary"
385+
variant="outlined"
386+
color="primary"
384387
>
385-
Close
388+
Action
386389
</v-btn>
387390
</template>
388391

0 commit comments

Comments
 (0)