Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/cms/src/ui.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export const {
AuthCard,
Avatar,
Badge,
Button,
ButtonGroup,
Expand Down
1 change: 1 addition & 0 deletions resources/js/bootstrap/cms/ui.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export {
AuthCard,
Avatar,
Badge,
Button,
ButtonGroup,
Expand Down
2 changes: 0 additions & 2 deletions resources/js/bootstrap/components.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import FileIcon from '../components/FileIcon.vue';

import Slugify from '../components/slugs/Slugify.vue';
import ElementContainer from '../components/ElementContainer.vue';
import Avatar from '../components/Avatar.vue';
import CreateEntryButton from '../components/entries/CreateEntryButton.vue';
import Portal from '../components/portals/Portal.vue';
import ConfirmationModal from '../components/modals/ConfirmationModal.vue';
Expand Down Expand Up @@ -62,7 +61,6 @@ export default function registerGlobalComponents(app) {

app.component('slugify', Slugify);
app.component('element-container', ElementContainer);
app.component('avatar', Avatar);
app.component('create-entry-button', CreateEntryButton);
app.component('portal', Portal);
app.component('date-time', DateTime);
Expand Down
46 changes: 0 additions & 46 deletions resources/js/components/Avatar.vue

This file was deleted.

73 changes: 73 additions & 0 deletions resources/js/components/ui/Avatar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<script setup lang="ts">
import { cva } from 'cva';
import { twMerge } from 'tailwind-merge';
import { computed, ref, useAttrs } from "vue";

interface Asset {
permalink: string;
}

interface User {
initials?: string;
avatar?: string | Asset;
name?: string;
}

interface Props {
user: User;
}

const props = withDefaults(defineProps<Props>(), {
user: () => ({})
})

const attrs = useAttrs();
const hasAvatarError = ref(false);
const hasAvatar = computed(() => !!props.user.avatar && !hasAvatarError.value);

const avatarSrc = computed(() => {
if (!hasAvatar.value) return null;

return typeof props.user.avatar === 'object' ? props.user.avatar.permalink : props.user.avatar;
})

const initials = computed(() => {
if (props.user.initials) return props.user.initials;

if (props.user.name) {
const names = props.user.name.split(' ');
return names.length === 1
? names[0].charAt(0).toUpperCase()
: (names[0].charAt(0) + names[names.length - 1].charAt(0)).toUpperCase();
}

return '?';
});

const avatarClasses = computed(() => {
const classes = cva({
base: 'size-7 rounded-xl [button:has(&)]:rounded-xl shape-squircle',
variants: {
type: {
avatar: '',
initials: 'antialiased text-white text-2xs font-medium flex flex-shrink-0 items-center justify-center bg-gradient-to-tr from-purple-500 to-red-600'
}
}
})({
type: hasAvatar.value ? 'avatar' : 'initials'
})

return twMerge(classes, attrs.class as string);
})
</script>

<template>
<template v-if="hasAvatar">
<img :src="avatarSrc" :class="avatarClasses" :alt="user.name" @error="hasAvatarError = true" />
</template>
<template v-else>
<div :aria-label="user.name" :class="avatarClasses">
{{ initials }}
</div>
</template>
</template>
1 change: 1 addition & 0 deletions resources/js/components/ui/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from '../../../../packages/ui/src/index.js';

export { default as Avatar } from "./Avatar.vue";
export { default as CreateForm } from "./CreateForm.vue";
export { default as LivePreview } from "./LivePreview/LivePreview.vue";
import { default as LivePreviewPopout } from "./LivePreview/Popout.vue";
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/users/Listing.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
>
<template #cell-email="{ row: user }">
<a class="title-index-field" :href="user.edit_url" @click.stop>
<avatar :user="user" class="h-8 w-8 rounded-full ltr:mr-2 rtl:ml-2" />
<avatar :user="user" class="size-8 text-xs ltr:mr-2 rtl:ml-2" />
<span v-text="user.email" />
</a>
</template>
Expand Down
1 change: 1 addition & 0 deletions resources/js/tests/Package.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ it('exports ui', async () => {

const expectedCmsPackageExports = [
...expectedUiPackageExports,
'Avatar',
'CommandPaletteItem',
'CreateForm',
'Listing',
Expand Down
7 changes: 0 additions & 7 deletions resources/views/components/avatar.blade.php

This file was deleted.

8 changes: 5 additions & 3 deletions resources/views/components/user-dropdown.blade.php
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
@php($userJson = json_encode($user))

<div v-if="false" class="inline-flex items-center justify-center h-10 w-10">
<x-statamic::avatar :user="$user" />
<ui-avatar :user='{{ $userJson }}' />
</div>

<ui-dropdown align="end" v-cloak>
<template #trigger>
<ui-button :icon-only="true" variant="ghost">
<x-statamic::avatar :user="$user" />
<ui-avatar :user='{{ $userJson }}' />
</ui-button>
</template>

<ui-dropdown-header>
<div class="flex items-center gap-2">
<x-statamic::avatar :user="$user" class="size-8!" />
<ui-avatar :user='{{ $userJson }}' class="size-8" />
<div>
<div class="text-sm" v-pre>{{ $user->email() }}</div>
@if ($user->isSuper())
Expand Down
Loading