Repository: App-Dev-3/Superwise
Pull request #47: Scrum 85 nuxt fe create action card builder component
Author: login: FelixTeutsch
Created: 2025-05-03T15:28:31Z | Merged: 2025-05-04T18:47:53Z

This pull request introduces a new `ActionCard` Vue component and its corresponding test suite. The changes include the implementation of the component's functionality, props, and event handling, as well as comprehensive unit tests to ensure proper behavior.

### New `ActionCard` Component Implementation:
* [`Frontend/components/ActionCard/ActionCard.vue`](diffhunk://#diff-ca2ef68aac61b76d8966be8f8adf079a5ffa365522367bf9e4b78cd34553d389R1-R63): Added the `ActionCard` component with props for `buttonText`, `cardType`, `action`, and `headerText`. The component includes a slot for custom content, a button with customizable text and style, and emits an `action` event when the button is clicked. Validation for `cardType` ensures only valid values (`"default"` or `"primary"`) are accepted.

### Unit Tests for `ActionCard` Component:
* [`Frontend/components/ActionCard/ActionCard.test.js`](diffhunk://#diff-bd77cb10628bc9dfa20d9f67b26bbdb4db1aa350d7ba2e2326d911ace61c6899R1-R58): Added a test suite for the `ActionCard` component. Tests cover rendering of the header, button behavior with default and custom text, event emission on button click, validation of `cardType` prop, and slot content rendering.


Diff:
diff --git a/Frontend/components/ActionCard/ActionCard.test.js b/Frontend/components/ActionCard/ActionCard.test.js
new file mode 100644
index 00000000..79f29be2
--- /dev/null
+++ b/Frontend/components/ActionCard/ActionCard.test.js
@@ -0,0 +1,46 @@
+import {mount} from '@vue/test-utils'
+import {describe, expect, it} from 'vitest'
+import ActionCard from './ActionCard.vue'
+
+describe('ActionCard.vue', () => {
+    it('renders header text when headerText prop is provided', () => {
+        const wrapper = mount(ActionCard, {
+            props: {headerText: 'Header'}
+        })
+        expect(wrapper.text()).toContain('Header')
+    })
+
+    it('does not render header text when headerText prop is empty', () => {
+        const wrapper = mount(ActionCard)
+        expect(wrapper.text()).not.toContain('Header')
+    })
+
+    it('renders button with default text when buttonText prop is not provided', () => {
+        const wrapper = mount(ActionCard)
+        expect(wrapper.findComponent({name: 'CustomButton'}).props('text')).toBe('Click Me')
+    })
+
+    it('renders button with custom text when buttonText prop is provided', () => {
+        const wrapper = mount(ActionCard, {
+            props: {buttonText: 'Submit'}
+        })
+        expect(wrapper.findComponent({name: 'CustomButton'}).props('text')).toBe('Submit')
+    })
+
+    it('accepts only valid cardType values', () => {
+        const validTypes = ['ghost', 'primary']
+        validTypes.forEach(type => {
+            const wrapper = mount(ActionCard, {
+                props: {cardType: type}
+            })
+            expect(wrapper.props('cardType')).toBe(type)
+        })
+    })
+
+    it('renders slot content', () => {
+        const wrapper = mount(ActionCard, {
+            slots: {default: '<div class="slot-content">Slot Content</div>'}
+        })
+        expect(wrapper.find('.slot-content').exists()).toBe(true)
+    })
+})
diff --git a/Frontend/components/ActionCard/ActionCard.vue b/Frontend/components/ActionCard/ActionCard.vue
new file mode 100644
index 00000000..7336d22a
--- /dev/null
+++ b/Frontend/components/ActionCard/ActionCard.vue
@@ -0,0 +1,53 @@
+<script setup>
+import CustomButton from "../CustomButton/CustomButton.vue";
+
+const props = defineProps({
+    buttonText: {
+        type: String,
+        default: "Click Me",
+    },
+    cardType: {
+        type: String,
+        default: 'ghost',
+        validator: (value) => !value || ["ghost", "primary"].includes(value),
+    },
+    headerText: {
+        type: String,
+        default: ''
+    },
+});
+
+const emit = defineEmits(['actionButtonClicked']);
+function emitActionEvent() {
+  emit('actionButtonClicked');
+}
+</script>
+
+<template>
+    <div>
+        <p v-if="props.headerText" class="px-1">
+          {{ props.headerText }}
+        </p>
+        <div class="card shadow-xl border border-base-300">
+            <slot/>
+            <!-- Action button at the bottom -->
+            <div class="px-16 py-4 border-t border-base-300">
+                <CustomButton
+                    v-if="props.cardType === 'ghost'"
+                    :text="props.buttonText"
+                    block
+                    color="default"
+                    variant="ghost"
+                    @click="emitActionEvent"
+                />
+                <CustomButton
+                    v-else
+                    :text="props.buttonText"
+                    block
+                    color="primary"
+                    @click="emitActionEvent"
+                />
+            </div>
+        </div>
+    </div>
+</template>
\ No newline at end of file


Reviews:
user: login: nb159
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-03T17:19:02Z
user: login: nb159
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-03T17:21:43Z
user: login: nb159
body: Good job for the work :D. Left some comments, good luck
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-03T17:27:15Z
user: login: jb-cc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-03T20:36:00Z
user: login: jb-cc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-03T20:36:53Z
user: login: FelixTeutsch
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-04T07:34:20Z
user: login: jb-cc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-04T18:22:04Z
user: login: jb-cc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-04T18:22:15Z
user: login: jb-cc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-04T18:23:04Z
user: login: jb-cc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-04T18:23:52Z
user: login: jb-cc
body: I left some comments :)
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-04T18:25:32Z
user: login: jb-cc
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-04T18:40:55Z

Review comments:
diff_hunk: @@ -0,0 +1,63 @@
+<script setup>
+import CustomButton from "../CustomButton/CustomButton.vue";
+
+const props = defineProps({
+  buttonText: {
+    type: String,
+    default: "Click Me",
+  },
+  cardType: {
+    type: String,
+    default: 'default',
+    validator: (value) => !value || ["default", "primary"].includes(value),
+  },
+  action: {
+    type: Function,
+    default: () => {
+    }
+  },
+  headerText: {
+    type: String,
+    default: ''
+  },
+});
+
+const emit = defineEmits(['action']);
+
+function handleAction() {
+  // Call the action prop if provided
+  props.action();
+  // Also emit the action event
+  emit('action');
+}
+
+</script>
+
+<template>
+  <div
+      class="">
+    <p
+        v-if="props.headerText"
+        class="px-1"
+    >
+      {{ props.headerText }}
+    </p>
+    <div class="card shadow-xl border border-base-300">
+      <slot/>
+
+      <!-- Action button at the bottom -->
+      <div class="px-16 py-4 border-t border-base-300">
+
+        <CustomButton
path: Frontend/components/ActionCard/ActionCard.vue
user: login: nb159
body: I would suggest making the button either be a named slot option or have a prop on the component that determines the type of button. 

Based on the figma designs there are two types of action btns, Ill link the image here

![image](https://github.com/user-attachments/assets/cdc19f04-0341-456b-bbaa-d174aa5ada44)

![image](https://github.com/user-attachments/assets/9cd4a89f-e3e9-4beb-80b7-36a8d1a7ea22)

created_at: 2025-05-03T17:19:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,63 @@
+<script setup>
+import CustomButton from "../CustomButton/CustomButton.vue";
+
+const props = defineProps({
+  buttonText: {
+    type: String,
+    default: "Click Me",
+  },
+  cardType: {
+    type: String,
+    default: 'default',
+    validator: (value) => !value || ["default", "primary"].includes(value),
+  },
+  action: {
+    type: Function,
+    default: () => {
+    }
+  },
+  headerText: {
+    type: String,
+    default: ''
+  },
+});
+
+const emit = defineEmits(['action']);
+
+function handleAction() {
+  // Call the action prop if provided
+  props.action();
+  // Also emit the action event
+  emit('action');
+}
+
+</script>
+
+<template>
+  <div
+      class="">
+    <p
+        v-if="props.headerText"
+        class="px-1"
+    >
+      {{ props.headerText }}
+    </p>
+    <div class="card shadow-xl border border-base-300">
+      <slot/>
path: Frontend/components/ActionCard/ActionCard.vue
user: login: nb159
body: With the current classes, the slot content is not centered nor is it 'encompassed' by the card. Ill link my index as well as an image, please let me know if I missed something :D. 

`<ActionCard
      buttonText="Click Me"
      cardType="default"
      headerText="Action Card Header"
      :action="handleAction"
      @action="handlEmitAction"
    >
    <CardStack
        :amount="3"
      >
        <SupervisorCard
          fName="John"
          lName="Doe"
          :tags="['Tag1', 'Tag2', 'Tag3']"
          :maxTagAmount=4
          description="This is a description of the supervisor."
          :similarityScore=0.85
          :maxCapacity=100
          :currentCapacity=50
          :pendingAmount=10
        />
      </CardStack>
    </ActionCard>`
    
![image](https://github.com/user-attachments/assets/5d552b94-7f52-42cb-a13d-006190b216e9)



created_at: 2025-05-03T17:21:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,63 @@
+<script setup>
+import CustomButton from "../CustomButton/CustomButton.vue";
+
+const props = defineProps({
+  buttonText: {
+    type: String,
+    default: "Click Me",
+  },
+  cardType: {
+    type: String,
+    default: 'default',
+    validator: (value) => !value || ["default", "primary"].includes(value),
+  },
+  action: {
+    type: Function,
+    default: () => {
+    }
+  },
+  headerText: {
+    type: String,
+    default: ''
+  },
+});
+
+const emit = defineEmits(['action']);
+
+function handleAction() {
+  // Call the action prop if provided
+  props.action();
+  // Also emit the action event
+  emit('action');
+}
+
+</script>
+
+<template>
+  <div
+      class="">
+    <p
+        v-if="props.headerText"
+        class="px-1"
+    >
+      {{ props.headerText }}
+    </p>
+    <div class="card shadow-xl border border-base-300">
+      <slot/>
path: Frontend/components/ActionCard/ActionCard.vue
user: login: jb-cc
body: This is an issue that is on me, the Card Stack was not working correctly. The working fix is on dev now.
created_at: 2025-05-03T20:36:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,63 @@
+<script setup>
+import CustomButton from "../CustomButton/CustomButton.vue";
+
+const props = defineProps({
+  buttonText: {
+    type: String,
+    default: "Click Me",
+  },
+  cardType: {
+    type: String,
+    default: 'default',
+    validator: (value) => !value || ["default", "primary"].includes(value),
+  },
+  action: {
+    type: Function,
+    default: () => {
+    }
+  },
+  headerText: {
+    type: String,
+    default: ''
+  },
+});
+
+const emit = defineEmits(['action']);
+
+function handleAction() {
+  // Call the action prop if provided
+  props.action();
+  // Also emit the action event
+  emit('action');
+}
+
+</script>
+
+<template>
+  <div
+      class="">
+    <p
+        v-if="props.headerText"
+        class="px-1"
+    >
+      {{ props.headerText }}
+    </p>
+    <div class="card shadow-xl border border-base-300">
+      <slot/>
path: Frontend/components/ActionCard/ActionCard.vue
user: login: jb-cc
body: See https://github.com/App-Dev-3/Superwise/pull/42 latest comment
created_at: 2025-05-03T20:36:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,63 @@
+<script setup>
+import CustomButton from "../CustomButton/CustomButton.vue";
+
+const props = defineProps({
+  buttonText: {
+    type: String,
+    default: "Click Me",
+  },
+  cardType: {
+    type: String,
+    default: 'default',
+    validator: (value) => !value || ["default", "primary"].includes(value),
+  },
+  action: {
+    type: Function,
+    default: () => {
+    }
+  },
+  headerText: {
+    type: String,
+    default: ''
+  },
+});
+
+const emit = defineEmits(['action']);
+
+function handleAction() {
+  // Call the action prop if provided
+  props.action();
+  // Also emit the action event
+  emit('action');
+}
+
+</script>
+
+<template>
+  <div
+      class="">
+    <p
+        v-if="props.headerText"
+        class="px-1"
+    >
+      {{ props.headerText }}
+    </p>
+    <div class="card shadow-xl border border-base-300">
+      <slot/>
+
+      <!-- Action button at the bottom -->
+      <div class="px-16 py-4 border-t border-base-300">
+
+        <CustomButton
path: Frontend/components/ActionCard/ActionCard.vue
user: login: FelixTeutsch
body: I have updated the code, to contain two different buttons, and depending on what card type is selected, one of the buttons is shown
<img width="334" alt="Screenshot 2025-05-04 at 09 33 13" src="https://github.com/user-attachments/assets/48397eb4-c97e-4432-9e8d-88cffe5ceb24" />
created_at: 2025-05-04T07:34:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,78 @@
+<script setup>
+import CustomButton from "../CustomButton/CustomButton.vue";
+import {computed} from "vue";
+
+const props = defineProps({
+  buttonText: {
+    type: String,
+    default: "Click Me",
+  },
+  cardType: {
+    type: String,
+    default: 'ghost',
+    validator: (value) => !value || ["ghost", "primary"].includes(value),
+  },
+  action: {
path: Frontend/components/ActionCard/ActionCard.vue
user: login: jb-cc
body: pls remove this, as we use the emit for that
created_at: 2025-05-04T18:22:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,78 @@
+<script setup>
+import CustomButton from "../CustomButton/CustomButton.vue";
+import {computed} from "vue";
+
+const props = defineProps({
+  buttonText: {
+    type: String,
+    default: "Click Me",
+  },
+  cardType: {
+    type: String,
+    default: 'ghost',
+    validator: (value) => !value || ["ghost", "primary"].includes(value),
+  },
+  action: {
+    type: Function,
+    default: () => {
+    }
+  },
+  headerText: {
+    type: String,
+    default: ''
+  },
+});
+
+const emit = defineEmits(['action']);
+
+function handleAction() {
+  // Call the action prop if provided
+  props.action();
path: Frontend/components/ActionCard/ActionCard.vue
user: login: jb-cc
body: remove this as well
created_at: 2025-05-04T18:22:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,78 @@
+<script setup>
+import CustomButton from "../CustomButton/CustomButton.vue";
+import {computed} from "vue";
+
+const props = defineProps({
+  buttonText: {
+    type: String,
+    default: "Click Me",
+  },
+  cardType: {
+    type: String,
+    default: 'ghost',
+    validator: (value) => !value || ["ghost", "primary"].includes(value),
+  },
+  action: {
+    type: Function,
+    default: () => {
+    }
+  },
+  headerText: {
+    type: String,
+    default: ''
+  },
+});
+
+const emit = defineEmits(['action']);
+
+function handleAction() {
+  // Call the action prop if provided
+  props.action();
+  // Also emit the action event
+  emit('action');
+}
+
+const ghostButton = computed(() => {
path: Frontend/components/ActionCard/ActionCard.vue
user: login: jb-cc
body: not needed, you can just check it like this in the button itself:

```vue
<CustomButton
                    v-if="props.cardType === 'ghost'"
                    :text="props.buttonText"
                    block
                    color="default"
                    variant="ghost"
                    @click="handleAction"
                />
                <CustomButton
                    v-else
                    :text="props.buttonText"
                    block
                    color="primary"
                    @click="handleAction"
                />
```
created_at: 2025-05-04T18:23:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,58 @@
+import {mount} from '@vue/test-utils'
+import {describe, expect, it, vi} from 'vitest'
+import ActionCard from './ActionCard.vue'
+
+describe('ActionCard.vue', () => {
+    it('renders header text when headerText prop is provided', () => {
+        const wrapper = mount(ActionCard, {
+            props: {headerText: 'Header'}
+        })
+        expect(wrapper.text()).toContain('Header')
+    })
+
+    it('does not render header text when headerText prop is empty', () => {
+        const wrapper = mount(ActionCard)
+        expect(wrapper.text()).not.toContain('Header')
+    })
+
+    it('renders button with default text when buttonText prop is not provided', () => {
+        const wrapper = mount(ActionCard)
+        expect(wrapper.findComponent({name: 'CustomButton'}).props('text')).toBe('Click Me')
+    })
+
+    it('renders button with custom text when buttonText prop is provided', () => {
+        const wrapper = mount(ActionCard, {
+            props: {buttonText: 'Submit'}
+        })
+        expect(wrapper.findComponent({name: 'CustomButton'}).props('text')).toBe('Submit')
+    })
+
+    it('emits action event and calls action prop when button is clicked', async () => {
path: Frontend/components/ActionCard/ActionCard.test.js
user: login: jb-cc
body: You can then remove this test as well :)
created_at: 2025-05-04T18:23:52Z
author_association: CONTRIBUTOR

PR comments:
user: login: jb-cc
created_at: 2025-05-04T13:20:49Z
body: @FelixTeutsch The tests fail because you didnt import the "computed" method, pls add it.
Usually we dont have to do that, but vitest needs to have everything imported to pass the tests.
author_association: CONTRIBUTOR
user: login: nb159
created_at: 2025-05-04T17:51:19Z
body: Please provide me with a testable index.vue. I saw the image you posted to display the ghost/primary card types and that looks good, but when I run the code I still have the alignment messed up. Example:
![image](https://github.com/user-attachments/assets/554dfd1c-95d8-4b56-a1da-8053cd750e40)


Also make sure to rebase dev into your current branch :D
author_association: CONTRIBUTOR
user: login: jb-cc
created_at: 2025-05-04T18:17:02Z
body: > Please provide me with a testable index.vue. I saw the image you posted to display the ghost/primary card types and that looks good, but when I run the code I still have the alignment messed up. Example: ![image](https://private-user-images.githubusercontent.com/46753692/440205172-554dfd1c-95d8-4b56-a1da-8053cd750e40.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NDYzODI0NzYsIm5iZiI6MTc0NjM4MjE3NiwicGF0aCI6Ii80Njc1MzY5Mi80NDAyMDUxNzItNTU0ZGZkMWMtOTVkOC00YjU2LWExZGEtODA1M2NkNzUwZTQwLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTA1MDQlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwNTA0VDE4MDkzNlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTZkNmE2MzY2ZTQwMjI3MDc4ZTQ4YzBkZWIyNDcyYTFmMDBhNmZjNGY0M2YwMzZiZDk3MzI2Yjg2MGY4NTU4MTcmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.ffLYHaf2U2Gekt0-IrWcOzziccE_zm-aNzaIVYzyHUk)
> 
> Also make sure to rebase dev into your current branch :D

This is because we leave the alignment of the cardstack to the parent element. I rebased and tested locally (with center styles) and it works

![image](https://github.com/user-attachments/assets/db84daa2-a6f0-4aff-ba7a-a909cf774616)

author_association: CONTRIBUTOR
user: login: jb-cc
created_at: 2025-05-04T18:31:09Z
body: This is the index.vue I tested it with @nb159 :

```vue
<template>
    <div>
        <div class="px-6 py-8 max-w-lg">
            <action-card
                :action="() => console.log('Action function called')"
                button-text="Start Matching"
                card-type="primary"
                @action-button-clicked="logEmit"
            >
                <div class="flex flex-col items-center my-4">
                    <h2 class="text-lg mb-8">Find your supervisor now!</h2>
                    <CardStack>
                        <SupervisorCard
                            :current-capacity=0
                            first-name="Fname"
                            :tags="['tag1', 'tag2', 'tag3']"
                            image=""
                            last-name="Lname"
                            :max-capacity=4
                            :similarity-score=69
                            size="xs"
                        />
                    </cardstack>
                </div>
            </action-card>
        </div>
        <div class="px-6 py-8 max-w-md">
            <action-card
                card-type="primary"
                button-text="Download Confirmation"
                @action-button-clicked="logEmit"
            >
                <div class="flex flex-col items-center mt-12">
                    <div class="avatar avatar-offline">
                        <div class="w-24 rounded-full">
                            <img src="https://img.daisyui.com/images/profile/demo/batperson@192.webp">
                        </div>
                    </div>
                    <h2 class="text-lg mb-8 text-base-content/60">Batman is your supervisor!</h2>
                </div>
            </action-card>
        </div>

        <div class="px-6 py-8 max-w-md">
            <action-card
                card-type="ghost"
                button-text="Open Chat..."
                @action-button-clicked="logEmit"
            >
                <div class="flex flex-col items-center my-12">
                    <div class="card-title">
                    <div class="avatar avatar-online">
                        <div class="w-12 rounded-full">
                            <img src="https://img.daisyui.com/images/profile/demo/batperson@192.webp">
                        </div>
                    </div>
                    <h2 class="text-lg font-bold">Batman</h2>
                    </div>
                </div>
            </action-card>
        </div>
        <div class="px-6 py-8 max-w-sm">
            <ActionCard
                card-type="ghost"
                button-text="Show all..."
                header-text="Latest Messages"
                @action-button-clicked="logEmit"
            >
                <div class="flex flex-col items-center p-4">
                    <ul class="list bg-base-100 rounded-box shadow-md">
                        <li class="list-row">
                            <div>
                                <img
                                    class="size-10 rounded-box"
                                    src="https://img.daisyui.com/images/profile/demo/1@94.webp">
                            </div>
                            <div>
                                <div>Dio Lupa</div>
                                <div class="text-xs uppercase font-semibold opacity-60">Remaining Reason</div>
                            </div>
                            <button class="btn btn-square btn-ghost">
                                <svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g stroke-linejoin="round" stroke-linecap="round" stroke-width="2" fill="none" stroke="currentColor"><path d="M6 3L20 12 6 21 6 3z"></path></g></svg>
                            </button>
                            <button class="btn btn-square btn-ghost">
                                <svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g stroke-linejoin="round" stroke-linecap="round" stroke-width="2" fill="none" stroke="currentColor"><path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z"></path></g></svg>
                            </button>
                        </li>

                        <li class="list-row">
                            <div><img class="size-10 rounded-box" src="https://img.daisyui.com/images/profile/demo/4@94.webp"/></div>
                            <div>
                                <div>Ellie Beilish</div>
                                <div class="text-xs uppercase font-semibold opacity-60">Bears of a fever</div>
                            </div>
                            <button class="btn btn-square btn-ghost">
                                <svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g stroke-linejoin="round" stroke-linecap="round" stroke-width="2" fill="none" stroke="currentColor"><path d="M6 3L20 12 6 21 6 3z"></path></g></svg>
                            </button>
                            <button class="btn btn-square btn-ghost">
                                <svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g stroke-linejoin="round" stroke-linecap="round" stroke-width="2" fill="none" stroke="currentColor"><path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z"></path></g></svg>
                            </button>
                        </li>

                        <li class="list-row">
                            <div><img class="size-10 rounded-box" src="https://img.daisyui.com/images/profile/demo/3@94.webp"/></div>
                            <div>
                                <div>Sabrino Gardener</div>
                                <div class="text-xs uppercase font-semibold opacity-60">Cappuccino</div>
                            </div>
                            <button class="btn btn-square btn-ghost">
                                <svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g stroke-linejoin="round" stroke-linecap="round" stroke-width="2" fill="none" stroke="currentColor"><path d="M6 3L20 12 6 21 6 3z"></path></g></svg>
                            </button>
                            <button class="btn btn-square btn-ghost">
                                <svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g stroke-linejoin="round" stroke-linecap="round" stroke-width="2" fill="none" stroke="currentColor"><path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z"></path></g></svg>
                            </button>
                        </li>
                    </ul>
                </div>
            </ActionCard>
        </div>
    </div>
</template>

<script setup>
import ActionCard from "../components/ActionCard/ActionCard.vue";
import CardStack from "../components/CardStack/CardStack.vue";
import SupervisorCard from "../components/SupervisorCard/SupervisorCard.vue";

function logEmit() {
    console.log("Action button clicked");
}
</script>
```
author_association: CONTRIBUTOR