Browse Source

refactor: convert entity display to list style

- Switch from grid display to list layout for persons and projects
- Re-styled special entities (unnamed, You) to match
- Added max-height limit to list in preparation for scrolling and displaying more items
pull/216/head
Jose Olarte III 2 weeks ago
parent
commit
e647af0777
  1. 2
      src/assets/styles/tailwind.css
  2. 17
      src/components/EntityGrid.vue
  3. 32
      src/components/PersonCard.vue
  4. 17
      src/components/ProjectCard.vue
  5. 20
      src/components/ShowAllCard.vue
  6. 13
      src/components/SpecialEntityCard.vue

2
src/assets/styles/tailwind.css

@ -38,7 +38,7 @@
} }
.dialog { .dialog {
@apply bg-white p-4 rounded-lg w-full max-w-lg; @apply bg-white p-4 rounded-lg w-full max-w-lg max-h-[calc(100vh-3rem)] overflow-y-auto;
} }
/* Markdown content styling to restore list elements */ /* Markdown content styling to restore list elements */

17
src/components/EntityGrid.vue

@ -2,7 +2,7 @@
GiftedDialog.vue to provide a reusable grid layout * for displaying people, GiftedDialog.vue to provide a reusable grid layout * for displaying people,
projects, and special entities with selection. * * @author Matthew Raymer */ projects, and special entities with selection. * * @author Matthew Raymer */
<template> <template>
<ul :class="gridClasses"> <ul class="border-t border-slate-300 mb-4 max-h-[60vh] overflow-y-auto">
<!-- Special entities (You, Unnamed) for people grids --> <!-- Special entities (You, Unnamed) for people grids -->
<template v-if="entityType === 'people'"> <template v-if="entityType === 'people'">
<!-- "You" entity --> <!-- "You" entity -->
@ -205,19 +205,6 @@ export default class EntityGrid extends Vue {
return "text-xs text-slate-500 italic col-span-full"; return "text-xs text-slate-500 italic col-span-full";
} }
/**
* Computed CSS classes for the grid layout
*/
get gridClasses(): string {
const baseClasses = "grid gap-x-2 gap-y-4 text-center mb-4";
if (this.entityType === "projects") {
return `${baseClasses} grid-cols-3 md:grid-cols-4`;
} else {
return `${baseClasses} grid-cols-4 sm:grid-cols-5 md:grid-cols-6`;
}
}
/** /**
* Computed entities to display - uses function prop if provided, otherwise defaults * Computed entities to display - uses function prop if provided, otherwise defaults
*/ */
@ -231,7 +218,7 @@ export default class EntityGrid extends Vue {
} }
// Default implementation for backward compatibility // Default implementation for backward compatibility
const maxDisplay = this.entityType === "projects" ? 7 : this.maxItems; const maxDisplay = this.entityType === "projects" ? 10 : this.maxItems;
return this.entities.slice(0, maxDisplay); return this.entities.slice(0, maxDisplay);
} }

32
src/components/PersonCard.vue

@ -3,30 +3,25 @@ GiftedDialog.vue to handle person entity display * with selection states and
conflict detection. * * @author Matthew Raymer */ conflict detection. * * @author Matthew Raymer */
<template> <template>
<li :class="cardClasses" @click="handleClick"> <li :class="cardClasses" @click="handleClick">
<div class="relative w-fit mx-auto"> <div>
<EntityIcon <EntityIcon
v-if="person.did" v-if="person.did"
:contact="person" :contact="person"
class="!size-[3rem] mx-auto border border-slate-300 bg-white overflow-hidden rounded-full mb-1" class="!size-[2rem] border border-slate-300 bg-white overflow-hidden rounded-full"
/> />
<font-awesome <font-awesome
v-else v-else
icon="circle-question" icon="circle-question"
class="text-slate-400 text-5xl mb-1" class="text-slate-400 text-5xl mb-1"
/> />
<!-- Time icon overlay for contacts -->
<div
v-if="person.did && showTimeIcon"
class="rounded-full bg-slate-400 absolute bottom-0 right-0 p-1 translate-x-1/3"
>
<font-awesome icon="clock" class="block text-white text-xs w-[1em]" />
</div>
</div> </div>
<div class="overflow-hidden">
<h3 :class="nameClasses"> <h3 :class="nameClasses">
{{ displayName }} {{ displayName }}
</h3> </h3>
<p class="text-xs text-slate-500 truncate">{{ person.did }}</p>
</div>
</li> </li>
</template> </template>
@ -81,29 +76,32 @@ export default class PersonCard extends Vue {
* Computed CSS classes for the card * Computed CSS classes for the card
*/ */
get cardClasses(): string { get cardClasses(): string {
const baseCardClasses =
"flex items-center gap-2 px-2 py-1.5 border-b border-slate-300";
if (!this.selectable || this.conflicted) { if (!this.selectable || this.conflicted) {
return "opacity-50 cursor-not-allowed"; return `${baseCardClasses} *:opacity-50 cursor-not-allowed`;
} }
return "cursor-pointer hover:bg-slate-50";
return `${baseCardClasses} cursor-pointer hover:bg-slate-50`;
} }
/** /**
* Computed CSS classes for the person name * Computed CSS classes for the person name
*/ */
get nameClasses(): string { get nameClasses(): string {
const baseClasses = const baseNameClasses = "text-sm font-semibold truncate";
"text-xs font-medium text-ellipsis whitespace-nowrap overflow-hidden";
if (this.conflicted) { if (this.conflicted) {
return `${baseClasses} text-slate-400`; return `${baseNameClasses} text-slate-500`;
} }
// Add italic styling for entities without set names // Add italic styling for entities without set names
if (!this.person.name) { if (!this.person.name) {
return `${baseClasses} italic text-slate-500`; return `${baseNameClasses} italic text-slate-500`;
} }
return baseClasses; return baseNameClasses;
} }
/** /**

17
src/components/ProjectCard.vue

@ -2,26 +2,27 @@
GiftedDialog.vue to handle project entity display * with selection states and GiftedDialog.vue to handle project entity display * with selection states and
issuer information. * * @author Matthew Raymer */ issuer information. * * @author Matthew Raymer */
<template> <template>
<li class="cursor-pointer" @click="handleClick"> <li
<div class="relative w-fit mx-auto"> class="flex items-center gap-2 px-2 py-1.5 border-b border-slate-300 hover:bg-slate-50 cursor-pointer"
@click="handleClick"
>
<ProjectIcon <ProjectIcon
:entity-id="project.handleId" :entity-id="project.handleId"
:icon-size="48" :icon-size="48"
:image-url="project.image" :image-url="project.image"
class="!size-[3rem] mx-auto border border-slate-300 bg-white overflow-hidden rounded-full mb-1" class="!size-[2rem] border border-slate-300 bg-white overflow-hidden rounded-full"
/> />
</div>
<h3 <div class="overflow-hidden">
class="text-xs font-medium text-ellipsis whitespace-nowrap overflow-hidden" <h3 class="text-sm font-semibold truncate">
>
{{ project.name || unnamedProject }} {{ project.name || unnamedProject }}
</h3> </h3>
<div class="text-xs text-slate-500 truncate"> <div class="text-xs text-slate-500 truncate">
<font-awesome icon="user" class="fa-fw text-slate-400" /> <font-awesome icon="user" class="text-slate-400" />
{{ issuerDisplayName }} {{ issuerDisplayName }}
</div> </div>
</div>
</li> </li>
</template> </template>

20
src/components/ShowAllCard.vue

@ -2,14 +2,17 @@
GiftedDialog.vue to handle "Show All" navigation * for both people and projects GiftedDialog.vue to handle "Show All" navigation * for both people and projects
entity types. * * @author Matthew Raymer */ entity types. * * @author Matthew Raymer */
<template> <template>
<li class="cursor-pointer"> <li class="border-b border-slate-300 hover:bg-slate-50">
<router-link :to="navigationRoute" class="block text-center"> <router-link
<font-awesome icon="circle-right" class="text-blue-500 text-5xl mb-1" /> :to="navigationRoute"
<h3 class="flex items-center gap-2 px-2 py-1.5 w-full cursor-pointer"
class="text-xs text-slate-500 font-medium italic text-ellipsis whitespace-nowrap overflow-hidden" >
<font-awesome icon="circle-right" class="text-blue-500 text-[2rem]" />
<p
class="text-sm font-semibold text-ellipsis whitespace-nowrap overflow-hidden"
> >
Show All Show All
</h3> </p>
</router-link> </router-link>
</li> </li>
</template> </template>
@ -58,9 +61,4 @@ export default class ShowAllCard extends Vue {
a { a {
text-decoration: none; text-decoration: none;
} }
a:hover .fa-circle-right {
transform: scale(1.1);
transition: transform 0.2s ease;
}
</style> </style>

13
src/components/SpecialEntityCard.vue

@ -63,23 +63,24 @@ export default class SpecialEntityCard extends Vue {
conflictContext!: string; conflictContext!: string;
/** /**
* Computed CSS classes for the card container * Computed CSS classes for the card
*/ */
get cardClasses(): string { get cardClasses(): string {
const baseClasses = "block"; const baseCardClasses =
"flex items-center gap-2 px-2 py-1.5 border-b border-slate-300";
if (!this.selectable || this.conflicted) { if (!this.selectable || this.conflicted) {
return `${baseClasses} cursor-not-allowed opacity-50`; return `${baseCardClasses} *:opacity-50 cursor-not-allowed`;
} }
return `${baseClasses} cursor-pointer`; return `${baseCardClasses} cursor-pointer hover:bg-slate-50`;
} }
/** /**
* Computed CSS classes for the icon * Computed CSS classes for the icon
*/ */
get iconClasses(): string { get iconClasses(): string {
const baseClasses = "text-5xl mb-1"; const baseClasses = "text-[2rem]";
if (this.conflicted) { if (this.conflicted) {
return `${baseClasses} text-slate-400`; return `${baseClasses} text-slate-400`;
@ -101,7 +102,7 @@ export default class SpecialEntityCard extends Vue {
*/ */
get nameClasses(): string { get nameClasses(): string {
const baseClasses = const baseClasses =
"text-xs font-medium text-ellipsis whitespace-nowrap overflow-hidden"; "text-sm font-semibold text-ellipsis whitespace-nowrap overflow-hidden";
if (this.conflicted) { if (this.conflicted) {
return `${baseClasses} text-slate-400`; return `${baseClasses} text-slate-400`;

Loading…
Cancel
Save