Browse Source

fix: AmountInput increment/decrement buttons not working

- Fixed input field binding from :value to v-model for proper two-way binding
- Input field now properly reflects programmatic value changes from buttons
- Simplified handleInput method to work with v-model synchronization
- Fixed vite.config.mts fs alias to resolve worker import issues
- Applied ESLint formatting fixes across all component files
- Maintains comprehensive debugging logs for event flow tracing

The issue was that :value creates one-way binding, so when increment/decrement
methods updated displayValue programmatically, Vue wasn't updating the DOM.
v-model creates proper two-way binding that synchronizes both directions.
matthew-scratch-2025-06-28
Matthew Raymer 2 weeks ago
parent
commit
f4856f48aa
  1. BIN
      public/wasm/sql-wasm.wasm
  2. 67
      src/components/AmountInput.vue
  3. 29
      src/components/EntityGrid.vue
  4. 17
      src/components/EntitySelectionStep.vue
  5. 23
      src/components/EntitySummaryButton.vue
  6. 50
      src/components/GiftDetailsStep.vue
  7. 80
      src/components/GiftedDialog.vue
  8. 40
      src/components/PersonCard.vue
  9. 32
      src/components/ProjectCard.vue
  10. 29
      src/components/ShowAllCard.vue
  11. 42
      src/components/SpecialEntityCard.vue
  12. 2
      vite.config.mts

BIN
public/wasm/sql-wasm.wasm

Binary file not shown.

67
src/components/AmountInput.vue

@ -1,25 +1,20 @@
/**
* AmountInput.vue - Specialized amount input with increment/decrement controls
*
* Extracted from GiftedDialog.vue to handle numeric amount input
* with increment/decrement buttons and validation.
*
* @author Matthew Raymer
*/
/** * AmountInput.vue - Specialized amount input with increment/decrement
controls * * Extracted from GiftedDialog.vue to handle numeric amount input *
with increment/decrement buttons and validation. * * @author Matthew Raymer */
<template>
<div class="flex">
<button
class="rounded-s border border-e-0 border-slate-400 bg-slate-200 px-4 py-2"
:disabled="isAtMinimum"
@click.prevent="decrement"
type="button"
@click.prevent="decrement"
>
<font-awesome icon="chevron-left" />
</button>
<input
:id="inputId"
:value="displayValue"
v-model="displayValue"
type="number"
:min="min"
:max="max"
@ -28,12 +23,12 @@
@input="handleInput"
@blur="handleBlur"
/>
<button
class="rounded-e border border-slate-400 bg-slate-200 px-4 py-2"
:disabled="isAtMaximum"
@click.prevent="increment"
type="button"
@click.prevent="increment"
>
<font-awesome icon="chevron-right" />
</button>
@ -45,7 +40,7 @@ import { Component, Prop, Vue, Watch, Emit } from "vue-facing-decorator";
/**
* AmountInput - Numeric input with increment/decrement controls
*
*
* Features:
* - Increment/decrement buttons with validation
* - Configurable min/max values and step size
@ -82,7 +77,13 @@ export default class AmountInput extends Vue {
* Initialize display value from prop
*/
mounted(): void {
console.log(
`[AmountInput] mounted() - initial value: ${this.value}, min: ${this.min}, max: ${this.max}, step: ${this.step}`,
);
this.displayValue = this.value.toString();
console.log(
`[AmountInput] mounted() - displayValue set to: ${this.displayValue}`,
);
}
/**
@ -97,21 +98,33 @@ export default class AmountInput extends Vue {
* Check if current value is at minimum
*/
get isAtMinimum(): boolean {
return this.value <= this.min;
const result = this.value <= this.min;
console.log(
`[AmountInput] isAtMinimum - value: ${this.value}, min: ${this.min}, result: ${result}`,
);
return result;
}
/**
* Check if current value is at maximum
*/
get isAtMaximum(): boolean {
return this.value >= this.max;
const result = this.value >= this.max;
console.log(
`[AmountInput] isAtMaximum - value: ${this.value}, max: ${this.max}, result: ${result}`,
);
return result;
}
/**
* Increment the value by step size
*/
increment(): void {
console.log(
`[AmountInput] increment() called - current value: ${this.value}, step: ${this.step}`,
);
const newValue = Math.min(this.value + this.step, this.max);
console.log(`[AmountInput] increment() calculated newValue: ${newValue}`);
this.updateValue(newValue);
}
@ -119,18 +132,19 @@ export default class AmountInput extends Vue {
* Decrement the value by step size
*/
decrement(): void {
console.log(
`[AmountInput] decrement() called - current value: ${this.value}, step: ${this.step}`,
);
const newValue = Math.max(this.value - this.step, this.min);
console.log(`[AmountInput] decrement() calculated newValue: ${newValue}`);
this.updateValue(newValue);
}
/**
* Handle direct input changes
*/
handleInput(event: Event): void {
const target = event.target as HTMLInputElement;
this.displayValue = target.value;
const numericValue = parseFloat(target.value);
handleInput(): void {
const numericValue = parseFloat(this.displayValue);
if (!isNaN(numericValue)) {
const clampedValue = Math.max(this.min, Math.min(numericValue, this.max));
this.updateValue(clampedValue);
@ -148,9 +162,17 @@ export default class AmountInput extends Vue {
* Update the value and emit change event
*/
private updateValue(newValue: number): void {
console.log(
`[AmountInput] updateValue() called - oldValue: ${this.value}, newValue: ${newValue}`,
);
if (newValue !== this.value) {
console.log(
`[AmountInput] updateValue() - values different, updating and emitting`,
);
this.displayValue = newValue.toString();
this.emitUpdateValue(newValue);
} else {
console.log(`[AmountInput] updateValue() - values same, skipping update`);
}
}
@ -159,6 +181,7 @@ export default class AmountInput extends Vue {
*/
@Emit("update:value")
emitUpdateValue(value: number): number {
console.log(`[AmountInput] emitUpdateValue() - emitting value: ${value}`);
return value;
}
}
@ -181,4 +204,4 @@ button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
</style>
</style>

29
src/components/EntityGrid.vue

@ -1,11 +1,6 @@
/**
* EntityGrid.vue - Unified entity grid layout component
*
* Extracted from GiftedDialog.vue to provide a reusable grid layout
* for displaying people, projects, and special entities with selection.
*
* @author Matthew Raymer
*/
/** * EntityGrid.vue - Unified entity grid layout component * * Extracted from
GiftedDialog.vue to provide a reusable grid layout * for displaying people,
projects, and special entities with selection. * * @author Matthew Raymer */
<template>
<ul :class="gridClasses">
<!-- Special entities (You, Unnamed) for people grids -->
@ -21,7 +16,7 @@
:entity-data="youEntityData"
@entity-selected="handleEntitySelected"
/>
<!-- "Unnamed" entity -->
<SpecialEntityCard
entity-type="unnamed"
@ -51,7 +46,7 @@
@person-selected="handlePersonSelected"
/>
</template>
<template v-else-if="entityType === 'projects'">
<ProjectCard
v-for="project in displayedEntities"
@ -85,7 +80,7 @@ import { PlanData } from "../interfaces/records";
/**
* EntityGrid - Unified grid layout for displaying people or projects
*
*
* Features:
* - Responsive grid layout for people/projects
* - Special entity integration (You, Unnamed)
@ -100,7 +95,7 @@ import { PlanData } from "../interfaces/records";
ProjectCard,
SpecialEntityCard,
ShowAllCard,
}
},
})
export default class EntityGrid extends Vue {
/** Type of entities to display */
@ -152,7 +147,7 @@ export default class EntityGrid extends Vue {
*/
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 {
@ -243,7 +238,11 @@ export default class EntityGrid extends Vue {
/**
* Handle special entity selection from SpecialEntityCard
*/
handleEntitySelected(event: { type: string; entityType: string; data: any }): void {
handleEntitySelected(event: {
type: string;
entityType: string;
data: any;
}): void {
this.emitEntitySelected({
type: "special",
entityType: event.entityType,
@ -262,4 +261,4 @@ export default class EntityGrid extends Vue {
<style scoped>
/* Grid-specific styles if needed */
</style>
</style>

17
src/components/EntitySelectionStep.vue

@ -1,11 +1,6 @@
/**
* EntitySelectionStep.vue - Entity selection step component
*
* Extracted from GiftedDialog.vue to handle the complete step 1
* entity selection interface with dynamic labeling and grid display.
*
* @author Matthew Raymer
*/
/** * EntitySelectionStep.vue - Entity selection step component * * Extracted
from GiftedDialog.vue to handle the complete step 1 * entity selection interface
with dynamic labeling and grid display. * * @author Matthew Raymer */
<template>
<div id="sectionGiftedGiver">
<label class="block font-bold mb-4">
@ -53,7 +48,7 @@ interface EntitySelectionEvent {
/**
* EntitySelectionStep - Complete step 1 entity selection interface
*
*
* Features:
* - Dynamic step labeling based on context
* - EntityGrid integration for unified entity display
@ -66,7 +61,7 @@ interface EntitySelectionEvent {
@Component({
components: {
EntityGrid,
}
},
})
export default class EntitySelectionStep extends Vue {
/** Type of step: 'giver' or 'recipient' */
@ -244,4 +239,4 @@ export default class EntitySelectionStep extends Vue {
<style scoped>
/* Component-specific styles if needed */
</style>
</style>

23
src/components/EntitySummaryButton.vue

@ -1,11 +1,6 @@
/**
* EntitySummaryButton.vue - Displays selected entity with edit capability
*
* Extracted from GiftedDialog.vue to handle entity summary display
* in the gift details step with edit functionality.
*
* @author Matthew Raymer
*/
/** * EntitySummaryButton.vue - Displays selected entity with edit capability *
* Extracted from GiftedDialog.vue to handle entity summary display * in the gift
details step with edit functionality. * * @author Matthew Raymer */
<template>
<component
:is="editable ? 'button' : 'div'"
@ -49,9 +44,9 @@
<!-- Edit/Lock Icon -->
<p class="ms-auto text-sm pe-1" :class="iconClasses">
<font-awesome
:icon="editable ? 'pen' : 'lock'"
:title="editable ? 'Change' : 'Can\'t be changed'"
<font-awesome
:icon="editable ? 'pen' : 'lock'"
:title="editable ? 'Change' : 'Can\'t be changed'"
/>
</p>
</component>
@ -75,7 +70,7 @@ interface EntityData {
/**
* EntitySummaryButton - Displays selected entity with optional edit capability
*
*
* Features:
* - Shows entity avatar (person or project)
* - Displays entity name and role label
@ -87,7 +82,7 @@ interface EntityData {
components: {
EntityIcon,
ProjectIcon,
}
},
})
export default class EntitySummaryButton extends Vue {
/** Entity data to display */
@ -147,4 +142,4 @@ button:hover {
div {
cursor: default;
}
</style>
</style>

50
src/components/GiftDetailsStep.vue

@ -1,11 +1,6 @@
/**
* GiftDetailsStep.vue - Gift details step component
*
* Extracted from GiftedDialog.vue to handle the complete step 2
* gift details form interface with entity summaries and validation.
*
* @author Matthew Raymer
*/
/** * GiftDetailsStep.vue - Gift details step component * * Extracted from
GiftedDialog.vue to handle the complete step 2 * gift details form interface
with entity summaries and validation. * * @author Matthew Raymer */
<template>
<div id="sectionGiftedGift">
<!-- Entity Summary Buttons -->
@ -79,8 +74,8 @@
</p>
<!-- Conflict Warning -->
<div
v-if="hasConflict"
<div
v-if="hasConflict"
class="mb-4 p-3 bg-red-50 border border-red-200 rounded-md"
>
<p class="text-red-700 text-sm text-center">
@ -126,7 +121,7 @@ interface EntityData {
/**
* GiftDetailsStep - Complete step 2 gift details form interface
*
*
* Features:
* - Entity summary display with edit capability
* - Gift description input with placeholder support
@ -141,7 +136,7 @@ interface EntityData {
components: {
EntitySummaryButton,
AmountInput,
}
},
})
export default class GiftDetailsStep extends Vue {
/** Giver entity data */
@ -232,8 +227,8 @@ export default class GiftDetailsStep extends Vue {
* Computed label for giver entity
*/
get giverLabel(): string {
return this.giverEntityType === "project"
? "Benefited from:"
return this.giverEntityType === "project"
? "Benefited from:"
: "Received from:";
}
@ -279,15 +274,20 @@ export default class GiftDetailsStep extends Vue {
query: {
amountInput: this.localAmount.toString(),
description: this.localDescription,
giverDid: this.giverEntityType === "person" ? this.giver?.did : undefined,
giverDid:
this.giverEntityType === "person" ? this.giver?.did : undefined,
giverName: this.giver?.name,
offerId: this.offerId,
fulfillsProjectId: this.giverEntityType === "person" && this.recipientEntityType === "project"
? this.toProjectId
: undefined,
providerProjectId: this.giverEntityType === "project" && this.recipientEntityType === "person"
? this.giver?.handleId
: this.fromProjectId,
fulfillsProjectId:
this.giverEntityType === "person" &&
this.recipientEntityType === "project"
? this.toProjectId
: undefined,
providerProjectId:
this.giverEntityType === "project" &&
this.recipientEntityType === "person"
? this.giver?.handleId
: this.fromProjectId,
recipientDid: this.receiver?.did,
recipientName: this.receiver?.name,
unitCode: this.localUnitCode,
@ -306,6 +306,9 @@ export default class GiftDetailsStep extends Vue {
* Handle amount input changes
*/
handleAmountChange(newAmount: number): void {
console.log(
`[GiftDetailsStep] handleAmountChange() called - oldAmount: ${this.localAmount}, newAmount: ${newAmount}`,
);
this.localAmount = newAmount;
this.emitUpdateAmount(newAmount);
}
@ -373,6 +376,9 @@ export default class GiftDetailsStep extends Vue {
@Emit("update:amount")
emitUpdateAmount(amount: number): number {
console.log(
`[GiftDetailsStep] emitUpdateAmount() - emitting amount: ${amount}`,
);
return amount;
}
@ -405,4 +411,4 @@ export default class GiftDetailsStep extends Vue {
<style scoped>
/* Component-specific styles if needed */
</style>
</style>

80
src/components/GiftedDialog.vue

@ -39,7 +39,7 @@
:from-project-id="fromProjectId"
:to-project-id="toProjectId"
@update:description="description = $event"
@update:amount="amountInput = $event.toString()"
@update:amount="handleAmountUpdate"
@update:unit-code="unitCode = $event"
@edit-entity="handleEditEntity"
@explain-data="explainData"
@ -138,25 +138,35 @@ export default class GiftedDialog extends Vue {
// Computed property to check if current selection would create a conflict
get hasPersonConflict() {
// Only check for conflicts when both entities are persons
if (this.giverEntityType !== "person" || this.recipientEntityType !== "person") {
if (
this.giverEntityType !== "person" ||
this.recipientEntityType !== "person"
) {
return false;
}
// Check if giver and recipient are the same person
if (this.giver?.did && this.receiver?.did && this.giver.did === this.receiver.did) {
if (
this.giver?.did &&
this.receiver?.did &&
this.giver.did === this.receiver.did
) {
return true;
}
return false;
}
// Computed property to check if a contact would create a conflict when selected
wouldCreateConflict(contactDid: string) {
// Only check for conflicts when both entities are persons
if (this.giverEntityType !== "person" || this.recipientEntityType !== "person") {
if (
this.giverEntityType !== "person" ||
this.recipientEntityType !== "person"
) {
return false;
}
if (this.stepType === "giver") {
// If selecting as giver, check if it conflicts with current recipient
return this.receiver?.did === contactDid;
@ -164,7 +174,7 @@ export default class GiftedDialog extends Vue {
// If selecting as recipient, check if it conflicts with current giver
return this.giver?.did === contactDid;
}
return false;
}
@ -348,7 +358,7 @@ export default class GiftedDialog extends Vue {
);
return;
}
// Check for person conflict
if (this.hasPersonConflict) {
this.$notify(
@ -407,13 +417,19 @@ export default class GiftedDialog extends Vue {
let fulfillsProjectHandleId: string | undefined;
let providerPlanHandleId: string | undefined;
if (this.giverEntityType === "project" && this.recipientEntityType === "person") {
if (
this.giverEntityType === "project" &&
this.recipientEntityType === "person"
) {
// Project-to-person gift
fromDid = undefined; // No person giver
toDid = recipientDid as string; // Person recipient
fulfillsProjectHandleId = undefined; // No project recipient
providerPlanHandleId = this.giver?.handleId; // Project giver
} else if (this.giverEntityType === "person" && this.recipientEntityType === "project") {
} else if (
this.giverEntityType === "person" &&
this.recipientEntityType === "project"
) {
// Person-to-project gift
fromDid = giverDid as string; // Person giver
toDid = undefined; // No person recipient
@ -611,12 +627,16 @@ export default class GiftedDialog extends Vue {
giverDid: this.giverEntityType === "person" ? this.giver?.did : undefined,
giverName: this.giver?.name,
offerId: this.offerId,
fulfillsProjectId: this.giverEntityType === "person" && this.recipientEntityType === "project"
? this.toProjectId
: undefined,
providerProjectId: this.giverEntityType === "project" && this.recipientEntityType === "person"
? this.giver?.handleId
: this.fromProjectId,
fulfillsProjectId:
this.giverEntityType === "person" &&
this.recipientEntityType === "project"
? this.toProjectId
: undefined,
providerProjectId:
this.giverEntityType === "project" &&
this.recipientEntityType === "person"
? this.giver?.handleId
: this.fromProjectId,
recipientDid: this.receiver?.did,
recipientName: this.receiver?.name,
unitCode: this.unitCode,
@ -629,17 +649,20 @@ export default class GiftedDialog extends Vue {
* Handle entity selection from EntitySelectionStep
* @param entity - The selected entity (person or project)
*/
handleEntitySelected(entity: { type: 'person' | 'project', data: Contact | PlanData }) {
if (entity.type === 'person') {
handleEntitySelected(entity: {
type: "person" | "project";
data: Contact | PlanData;
}) {
if (entity.type === "person") {
const contact = entity.data as Contact;
if (this.stepType === 'giver') {
if (this.stepType === "giver") {
this.selectGiver(contact);
} else {
this.selectRecipient(contact);
}
} else {
const project = entity.data as PlanData;
if (this.stepType === 'giver') {
if (this.stepType === "giver") {
this.selectProject(project);
} else {
this.selectRecipientProject(project);
@ -651,7 +674,7 @@ export default class GiftedDialog extends Vue {
* Handle edit entity request from GiftDetailsStep
* @param entityType - 'giver' or 'recipient'
*/
handleEditEntity(entityType: 'giver' | 'recipient') {
handleEditEntity(entityType: "giver" | "recipient") {
this.goBackToStep1(entityType);
}
@ -661,6 +684,19 @@ export default class GiftedDialog extends Vue {
handleSubmit() {
this.confirm();
}
/**
* Handle amount update from GiftDetailsStep
*/
handleAmountUpdate(newAmount: number) {
console.log(
`[GiftedDialog] handleAmountUpdate() called - oldAmount: ${this.amountInput}, newAmount: ${newAmount}`,
);
this.amountInput = newAmount.toString();
console.log(
`[GiftedDialog] handleAmountUpdate() - amountInput updated to: ${this.amountInput}`,
);
}
}
</script>

40
src/components/PersonCard.vue

@ -1,16 +1,8 @@
/**
* PersonCard.vue - Individual person display component
*
* Extracted from GiftedDialog.vue to handle person entity display
* with selection states and conflict detection.
*
* @author Matthew Raymer
*/
/** * PersonCard.vue - Individual person display component * * Extracted from
GiftedDialog.vue to handle person entity display * with selection states and
conflict detection. * * @author Matthew Raymer */
<template>
<li
:class="cardClasses"
@click="handleClick"
>
<li :class="cardClasses" @click="handleClick">
<div class="relative w-fit mx-auto">
<EntityIcon
v-if="person.did"
@ -22,21 +14,18 @@
icon="circle-question"
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]"
/>
<font-awesome icon="clock" class="block text-white text-xs w-[1em]" />
</div>
</div>
<h3 :class="nameClasses">
{{ person.name || person.did || 'Unnamed' }}
{{ person.name || person.did || "Unnamed" }}
</h3>
</li>
</template>
@ -48,7 +37,7 @@ import { Contact } from "../db/tables/contacts";
/**
* PersonCard - Individual person display with selection capability
*
*
* Features:
* - Person avatar using EntityIcon
* - Selection states (selectable, conflicted, disabled)
@ -59,7 +48,7 @@ import { Contact } from "../db/tables/contacts";
@Component({
components: {
EntityIcon,
}
},
})
export default class PersonCard extends Vue {
/** Contact data to display */
@ -92,12 +81,13 @@ export default class PersonCard extends Vue {
* Computed CSS classes for the person name
*/
get nameClasses(): string {
const baseClasses = "text-xs font-medium text-ellipsis whitespace-nowrap overflow-hidden";
const baseClasses =
"text-xs font-medium text-ellipsis whitespace-nowrap overflow-hidden";
if (this.conflicted) {
return `${baseClasses} text-slate-400`;
}
return baseClasses;
}
@ -121,4 +111,4 @@ export default class PersonCard extends Vue {
<style scoped>
/* Component-specific styles if needed */
</style>
</style>

32
src/components/ProjectCard.vue

@ -1,16 +1,8 @@
/**
* ProjectCard.vue - Individual project display component
*
* Extracted from GiftedDialog.vue to handle project entity display
* with selection states and issuer information.
*
* @author Matthew Raymer
*/
/** * ProjectCard.vue - Individual project display component * * Extracted from
GiftedDialog.vue to handle project entity display * with selection states and
issuer information. * * @author Matthew Raymer */
<template>
<li
class="cursor-pointer"
@click="handleClick"
>
<li class="cursor-pointer" @click="handleClick">
<div class="relative w-fit mx-auto">
<ProjectIcon
:entity-id="project.handleId"
@ -19,11 +11,13 @@
class="!size-[3rem] mx-auto border border-slate-300 bg-white overflow-hidden rounded-full mb-1"
/>
</div>
<h3 class="text-xs font-medium text-ellipsis whitespace-nowrap overflow-hidden">
<h3
class="text-xs font-medium text-ellipsis whitespace-nowrap overflow-hidden"
>
{{ project.name }}
</h3>
<div class="text-xs text-slate-500 truncate">
<font-awesome icon="user" class="fa-fw text-slate-400" />
{{ issuerDisplayName }}
@ -40,7 +34,7 @@ import { didInfo } from "../libs/endorserServer";
/**
* ProjectCard - Displays a project entity with selection capability
*
*
* Features:
* - Shows project icon using ProjectIcon
* - Displays project name and issuer information
@ -50,7 +44,7 @@ import { didInfo } from "../libs/endorserServer";
@Component({
components: {
ProjectIcon,
}
},
})
export default class ProjectCard extends Vue {
/** Project entity to display */
@ -77,7 +71,7 @@ export default class ProjectCard extends Vue {
this.project.issuerDid,
this.activeDid,
this.allMyDids,
this.allContacts
this.allContacts,
);
}
@ -99,4 +93,4 @@ export default class ProjectCard extends Vue {
<style scoped>
/* Component-specific styles if needed */
</style>
</style>

29
src/components/ShowAllCard.vue

@ -1,22 +1,13 @@
/**
* ShowAllCard.vue - Show All navigation card component
*
* Extracted from GiftedDialog.vue to handle "Show All" navigation
* for both people and projects entity types.
*
* @author Matthew Raymer
*/
/** * ShowAllCard.vue - Show All navigation card component * * Extracted from
GiftedDialog.vue to handle "Show All" navigation * for both people and projects
entity types. * * @author Matthew Raymer */
<template>
<li class="cursor-pointer">
<router-link
:to="navigationRoute"
class="block text-center"
>
<font-awesome
icon="circle-right"
class="text-blue-500 text-5xl mb-1"
/>
<h3 class="text-xs text-slate-500 font-medium italic text-ellipsis whitespace-nowrap overflow-hidden">
<router-link :to="navigationRoute" class="block text-center">
<font-awesome icon="circle-right" class="text-blue-500 text-5xl mb-1" />
<h3
class="text-xs text-slate-500 font-medium italic text-ellipsis whitespace-nowrap overflow-hidden"
>
Show All
</h3>
</router-link>
@ -29,7 +20,7 @@ import { RouteLocationRaw } from "vue-router";
/**
* ShowAllCard - Displays "Show All" navigation for entity grids
*
*
* Features:
* - Provides navigation to full entity listings
* - Supports different routes based on entity type
@ -72,4 +63,4 @@ a:hover .fa-circle-right {
transform: scale(1.1);
transition: transform 0.2s ease;
}
</style>
</style>

42
src/components/SpecialEntityCard.vue

@ -1,20 +1,9 @@
/**
* SpecialEntityCard.vue - Special entity display component
*
* Extracted from GiftedDialog.vue to handle special entities like "You"
* and "Unnamed" with conflict detection and selection capability.
*
* @author Matthew Raymer
*/
/** * SpecialEntityCard.vue - Special entity display component * * Extracted
from GiftedDialog.vue to handle special entities like "You" * and "Unnamed" with
conflict detection and selection capability. * * @author Matthew Raymer */
<template>
<li
:class="cardClasses"
@click="handleClick"
>
<font-awesome
:icon="icon"
:class="iconClasses"
/>
<li :class="cardClasses" @click="handleClick">
<font-awesome :icon="icon" :class="iconClasses" />
<h3 :class="nameClasses">
{{ label }}
</h3>
@ -27,7 +16,7 @@ import { Emit } from "vue-facing-decorator";
/**
* SpecialEntityCard - Displays special entities with selection capability
*
*
* Features:
* - Displays special entities like "You" and "Unnamed"
* - Shows appropriate FontAwesome icons
@ -36,7 +25,7 @@ import { Emit } from "vue-facing-decorator";
* - Configurable styling based on entity type
*/
@Component({
emits: ['entity-selected']
emits: ["entity-selected"],
})
export default class SpecialEntityCard extends Vue {
/** Type of special entity */
@ -68,11 +57,11 @@ export default class SpecialEntityCard extends Vue {
*/
get cardClasses(): string {
const baseClasses = "block";
if (!this.selectable || this.conflicted) {
return `${baseClasses} cursor-not-allowed opacity-50`;
}
return `${baseClasses} cursor-pointer`;
}
@ -81,11 +70,11 @@ export default class SpecialEntityCard extends Vue {
*/
get iconClasses(): string {
const baseClasses = "text-5xl mb-1";
if (this.conflicted) {
return `${baseClasses} text-slate-400`;
}
// Different colors for different entity types
switch (this.entityType) {
case "you":
@ -101,12 +90,13 @@ export default class SpecialEntityCard extends Vue {
* Computed CSS classes for the entity name/label
*/
get nameClasses(): string {
const baseClasses = "text-xs font-medium text-ellipsis whitespace-nowrap overflow-hidden";
const baseClasses =
"text-xs font-medium text-ellipsis whitespace-nowrap overflow-hidden";
if (this.conflicted) {
return `${baseClasses} text-slate-400`;
}
// Different colors for different entity types
switch (this.entityType) {
case "you":
@ -142,4 +132,4 @@ export default class SpecialEntityCard extends Vue {
<style scoped>
/* Component-specific styles if needed */
</style>
</style>

2
vite.config.mts

@ -22,7 +22,7 @@ export default defineConfig({
url: 'url/',
zlib: 'browserify-zlib',
path: 'path-browserify',
fs: false,
fs: path.resolve(__dirname, 'src/utils/node-modules/fs.js'),
tty: 'tty-browserify',
net: false,
dns: false,

Loading…
Cancel
Save